SwiftUI에서 하나의 뷰 내부에서 값의 변동을 공유하기 위해 @State 프로퍼티 래퍼를 사용한다. 하지만 뷰 사이에 같은 값을 사용하는 @State를 사용하고 그 변수의 값이 변경되는 경우 하나의 뷰에서는 값이 변경되지 않는다. 말이 요상한데 아래와 같은 예시를 살펴보면 이해가 더 빠르다.
아래 코드는 두가지 뷰로 이루어져있고, 하나는 메인뷰, 하나는 커스텀 버튼 뷰이다. 원하는 기능은 버튼을 클릭했을 때 버튼 내부의 텍스트가 Dribbling에서 Shooting으로 바뀌고, 버튼의 배경색에 blue에서 orange로 바뀌는 것이고, 메인뷰의 텍스트 메시지가 shooting에서 sonny is on fire 로 바뀌는 것이다. 뷰 내부의 값들의 변경을 캐치하기 위해 두 가지 부울 변수를 @State 프로퍼티 래퍼로 선언했다.
import SwiftUI
// 커스텀 버튼 뷰
struct ShootingButtonView: View {
@State var isShoot: Bool
@State var isGoal: Bool
var body: some View {
Button {
// 버튼 클릭하면 isShoot 토글
isShooting.toggle()
// 버튼 클릭하면 isGoal 토글
isGoal.toggle()
} label: {
// 버튼 클릭하면 isShooting 의 결과에 따라 버튼의 텍스트 변경
Text(isShoot ? "Shooting" : "Dribbling")
.padding(.vertical, 20)
.padding(.horizontal, 40)
.background(isGoal ? Color.orange : Color.blue)
.foregroundColor(.white)
.cornerRadius(30)
}
}
}
// 메인 뷰
struct ContentView: View {
@State private var isShoot = false
@State private var isGoal = false
var body: some View {
VStack {
ShootingButtonView(isShoot: isShoot, isGoal: isGoal)
// isGoal의 값에 따라 버튼 아래의 텍스트 메시지 변경
Text(isGoal ? "sonny is on FIRE!!🔥" : "shooting")
.padding(.top, 40)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
하지만 이렇게 하면 버튼의 배경색상과 버튼의 텍스트는 바뀌지만 메인뷰의 텍스트는 변경되지 않는다. 또 다른 문제는 버튼을 한 번 눌렀을 때 버튼 뷰의 isGoal 의 변수에는 toggle로 인해 isGoal의 값이 true로 변경되지만 메인뷰의 isGoal 변수는 그대로 false를 유지하게 되는 한 뷰에 두 가지의 값이 공존하는 이상한 형태가 된다.
이를 해결하기 위해 @Binding 프로퍼티 래퍼를 사용한다. 커스텀 버튼 뷰의 isGoal 변수를 @Binding으로 선언하고 값 변경을 변수에 다시 반영하기 위해 메인뷰에서 isGoal을 $isGoal로 바꿔준다 바뀐 코드는 아래와 같다.
import SwiftUI
struct PushButton: View {
@State var isShoot: Bool
@Binding var isGoal: Bool // @State를 @Binding으로
var body: some View {
Button {
isShoot.toggle()
isGoal.toggle()
} label: {
Text(isShoot ? "Shooting" : "Dribbling")
.padding(.vertical, 20)
.padding(.horizontal, 40)
.background(isGoal ? Color.orange : Color.blue)
.foregroundColor(.white)
.cornerRadius(30)
}
}
}
struct ContentView: View {
@State private var isShoot = false
@State private var isGoal = false
var body: some View {
VStack {
PushButton(isShoot: isShoot, isGoal: $isGoal) // isGoal을 $isGoal로
Text(isGoal ? "sonny is on FIRE!!🔥" : "shooting")
.padding(.top, 40)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
이렇게 되면 커스텀버튼뷰에서 바뀐 isGoal의 값이 메인뷰의 isGoal 변수에 반영되고 그 결과 메인뷰의 텍스트 메시지가 변경된다.
'Apple > SwiftUI' 카테고리의 다른 글
SwiftUI 04 - @State, @StateObject (0) | 2022.03.15 |
---|---|
SwiftUI03 - Stepper (0) | 2022.03.14 |
SwiftUI02 - Button (0) | 2022.03.14 |
SwiftUI01 - Stack(HStack, VStack, ZStack) (0) | 2022.03.14 |