Hacking with Swift 사이트의 강좌 번역본입니다.
[원문 : https://www.hackingwithswift.com/quick-start/swiftui/two-way-bindings-in-swiftui]
Two-way bindings in SwiftUI
[동영상 강좌 : https://youtu.be/U1s4bDmpanc]
SwiftUI 미리보기 윈도우를 보는 경우에 표준 iOS picker 인터페이스를 보게 될 것입니다 - 회전하는 휠(wheel)로 되어 있습니다. paymentType의 값을 읽기 때문에, 기본적으로 0으로 설정한 첫번째 옵션이 보여질 것입니다. 하지만 사용자가 휠(wheel)을 움직일때 선택이 변경합니다 - 결제 타입을 0 대신에 1이나 2 선택할지도 모릅니다.
해당 picker는 paymentType의 값을 읽기만 하는 게 아니며, 값을 쓰기도 합니다. paymentType의 값을 변경하면 picker를 업데이트하고, picker를 변경하면 paymentType이 업데이트 할 것이기 때문에, 이를 양방향(two-way) 바인딩이라고 합니다.
달러($) 표시가 있는 것입니다: Swift 프로퍼티 래퍼(propery wrapper)는 해당 데이터에 양방향(two-way) 바인딩을 사용하며, $paymentType를 사용할때 SwiftUI는 해당 프로퍼티 래퍼를 사용해서 값을 쓸(write) 것이며, UI가 자동으로 갱신될 것입니다.
언듯보기에 @과 $ 모두 약간 Swifty 같지 않아 보이고, 이런 방법 사용해보지 않은 것도 사실입니다. 하지만, 번거로운 많은 다른 기능들을 사용할 수 있습니다.
- 구조체는 고정된 값이기 때문에, @State이 없이는 구조체 안의 프로퍼티들을 변경할 수 없을 것입니다.
- @EnvironmentObject 없이는 앱내의 다른 곳에서 공유된 데이터를 수신할 수 없을 것입니다.
- ObjservableObject 없이는 외부 값이 변경 될때 알림받지 못할 것입니다.
- $property 양방향(two-way) 바인딩이 없으면 직접 값을 업데이트 해야 합니다.
어쨌든, 그것은 기본 picker이며, OrderView.swift로 돌아가서 텍스 Checkout 보다 새로운 CheckoutView 구조체를 보여주도록 코드를 업데이트 할 수 있습니다.
다음 코드를 찾으세요:
NavigationLink(destination: Text("Check out")) {
그리고 다음으로 교체하세요.
NavigationLink(destination: CheckoutView()) {
지금 앱을 실행하고나서, Order 탭으로 이동하고 Place Order를 누르세요. 결과는… 음, 완벽하지 않지만, 그렇게 둡시다. 지금까지 많은 노력을 기울였음에도 불구하고 말입니다.
글쎄요, CheckoutView.swift에서 딱 한 단어만 바꿀것이고, 모든 것이 옳다고 느껴지도록 해야 합니다.
CheckoutView 안쪽에서, VStack을 Form으로 변경하고나서, 앱을 다시 실행하기 위해서 Cmd+R을 누르세요. 차이점을 알수 있나요?
이전에는 회전하는 wheel picker가 있었지만, 지금은 form이 있으므로, picker의 제목과 현재 선택된 값을 보여주는 단일 테이블을 사용합니다. 더 좋은 방법은, 해당 행을 탭할때, 다른 옵션을 보여주는 새 화면이 표시되고, 하나를 선택하고 선택한 것이 원래 화면에 다시 반영된 것을 볼 수 있을 것입니다.
이것이 사용자 인터페이스에 대한 SwiftUI의 선언적인 접근법의 힘입니다: 정확한 스타일링보다 원하는 동작을 얘기하며, SwiftUI는 사용되는 상황에 따라 자동적으로 적용합니다.
2가지 구성요소를 추가해서 form을 계속 사용해 봅시다: 하나는 사용자가 iDine 로열터 카드가 있는지를 선택할 수 있는지이고, 또 다른 하나는 카드 번호를 입력할 수 있는것입니다. 2가지 모두 picker와 마찬가지로 양방향 바인딩이 필요하기에, 2개의 새로운 @State 프로퍼티로 시작하겠습니다.
@State private var addLoyaltyDetails = false
@State private var loyaltyNumber = ""
이제 이를 표현하기 위해서 form에 컨트롤을 추가 할 수 있습니다 - Toggle는 UISwitche와 같고, TextField는 UITextField와 같습니다. 기존 form 섹션 안쪽에 이러한 2가지를 추가하세요.
Toggle(isOn: $addLoyaltyDetails) {
Text("Add iDine loyalty card")
}
TextField("Enter your iDine ID", text: $loyaltyNumber)
코드는 많지 않지만, 몇가지 세부내용을 언급할 가치가 있습니다.
- 2개의 컨트롤 모두 방금 만든 @State 프로퍼티에 바인딩했습니다.
- Toggle은 설명으로 자동으로 왼쪽에 나타나는 텍스트가 있습니다.
- TextField는 무엇을 입력해야 하는지 알수 있는 자리표시자(placeholder) 텍스트를 가집니다.
앱을 실행하기 전에, 먼저 이야기하고자 하는 또 다른 변경사항이 있습니다. 방금 추가한 텍스트 필드입니다 - 항상 거기에 있어야 하거나, 토글 스위치가 활성화 된 경우에만 있어야 하나요?
Toggle을 addLoyaltyDetails의 값과 바인딩했으며, 사용자가 이를 켜거나 끌때 Boolean이 true 또는 false로 설정되는 것을 의미합니다. 토글이 켜져 있을때만 텍스트 필드를 볼 수 있는게 좋지 않을까요?
흠, 이는 아주 쉬운 일입니다. 조건문 안으로 텍스트 필드를 감싸주세요.
Toggle(isOn: $addLoyaltyDetails) {
Text("Add iDine loyalty card")
}
if addLoyaltyDetails {
TextField("Enter your iDine ID", text: $loyaltyNumber)
}
프로그램을 실행할때 토글의 상태를 변경하면 텍스트 필드가 보여지거나 숨겨지는 것을 보게 될 것입니다. 곰곰히 생각해보면 모두 일리가 있습니다.
- 토글은 addLoyaltyDetails 프로퍼티에 양방향 바인딩을 합니다.
- 토글이 변경될때, 프로퍼티가 업데이트하는 것을 의미합니다.
- 프로퍼티는 @State로 표시됩니다.
- @State 또는 @EnvironmentObject 값이 변경될때, SwiftUI는 body 프로퍼티를 다시 호출할 것입니다.
- body 프로퍼티는 텍스트 필드의 생성여부를 결정하기 위해 addLoyaltyDetails의 값을 직접 읽습니다.
효과를 향상시키기 위해, Toggle의 바인딩을 수정해서 바뀌는 것을 애니메이션합니다.
Toggle(isOn: $addLoyaltyDetails.animation()) {
Text("Add iDine loyalty card")
}
로열티 카드 행이 부드럽게 밀려나올 것입니다.
다른 표준 컨트롤도 사용해봅시다: 세그먼트 컨트롤. SwiftUI는 실제로 modifier를 사용하는 Picker일 뿐므로, 정확히 같은 방법으로 동작합니다 - 선택 인덱스를 저장하는 양방향 바인딩을 제공하고나서, 선택할수 있는 몇가지 옵션을 만들기위해 배열을 반복하는 ForEach를 사용합니다.
이 화면에서는, 사용자가 선택할 수 있는 다양한 팁 비율을 나타내기 위해서 세그먼트 컨트롤을 사용할 수 있습니다. 먼저 보여주려는 옵션을 저장하기 위한 프로퍼티를 추가하세요.
static let tipAmounts = [10, 15, 20, 25, 0]
이제 선택된 세그먼트에 저장하도록 해당 프로퍼티를 추가하세요.
@State private var tipAmount = 1
form에 실제 주문을 확인하기 위한 버튼인, 컴포넌트 1개를 추가할 것입니다. 먼저 봐야할 것이 있기때문에, 잠시 후에 다시 정확하게 볼 것입니다.
다음은 테이블의 마지막 섹션입니다.
Section(header:
Text("TOTAL: $100")
) {
Button("Confirm order") {
// place the order
}
}
전체 주문 값이 잘못된것을 알고 있지만, 지금은 앱을 실행하세요.
ItemDetail 안에 버튼을 추가했고 투명한(clear) 배경에 파란색 텍스트로, 화면의 중앙에 배치했습니다. 이제 form에 버튼이 하나 있고, 그것은 다릅니다: 파란색 텍스트, 왼쪽 정렬, 탭하는 경우에 행(row)이 회색으로 깜빡입니다. 이는 SwiftUI의 form 시스템 내부에 있는 컴포넌트의 디자인과 동작을 변경하는 또 다른 방식의 예제입니다.
'SwiftUI > Building a complete project' 카테고리의 다른 글
Adding swipe to delete and EditButton (0) | 2019.11.13 |
---|---|
Presenting an alert (0) | 2019.11.13 |
Formatting interpolated strings in SwiftUI (0) | 2019.11.13 |
Bindings and forms (0) | 2019.11.08 |
Adding TabView and tabItem() (0) | 2019.11.08 |
Adding items to an order with @EnvironmentObject (0) | 2019.11.08 |
Observable objects, environment objects, and @Published (0) | 2019.11.07 |
Displaying a detail screen with NavigationLink (0) | 2019.11.07 |