안녕하세요.
이번에는 SwiftUI의 PreferenceKey에 대해 알아볼게요.
## PreferenceKey
A view with multiple children automatically combines its values for a given preference into a single value visible to its ancestors.
PreferenceKey는 자식 뷰에서 상위 뷰 계층으로 데이터를 전달하고 싶을 때 사용합니다.
즉, 하위에서 값을 수정하고 이를 상위 계층에 알려줘야 할 때 사용되는 게 PreferenceKey입니다.
하위 -> 상위 계층으로 데이터를 전달하는 개념도 생각보다 간단해요.
1. PreferenceKey 프로토콜을 준수한 Key를 하나 만들고,
2. 상위 뷰에서는 값이 변할 때 동작하는 action을 등록해주고,
3. 하위 뷰에서 해당 key에 대한 값을 설정 또는 변경
직접 해볼까요?
뷰는 아래처럼 구현해줄게요.
ChildView가 출력되고 2초 뒤에 상위 뷰(ContentView)의 text를 바꾸도록 구현해볼게요.
우선 PreferenceKey를 상속받은 커스텀 key를 하나 만들어줍니다.
그다음에는 PreferenceKey에 값을 저장해볼게요.
ChildView 출력하고 2초 뒤에 newValue라는 @State 프로퍼티에 text를 저장하고, 이 값을 CustomTitlePreferenceKey에 저장해줍니다.
값이 변경되었다는 걸 상위 계층에서 알아야겠죠?
ContentView에서 CustomTitlePreferenceKey 값이 변경되었을 때 이벤트를 받아서 text 값을 수정해줍니다.
전체 코드를 한번 볼게요.
ChildView에서 값을 변경했을 때 ContentView에서 이벤트를 받아서 처리를 했죠?
이렇게 하위 뷰에서 값을 변경하고 상위 계층에서 이벤트를 받아서 처리할 때 PreferenceKey를 사용합니다.
추가로, 상위 계층에서 하위 뷰의 크기를 알고 싶을 때 GeometryReader와 PreferenceKey를 활용해서 많이들 사용합니다.
요것도 한번 예시로 알아볼게요.
아래 같은 뷰가 있다고 해볼게요.
그런데 만약 위에 있는 Text 뷰의 width와 HStack 안에 있는 Rectangle 뷰의 width를 같게 설정하고 싶다면 어떻게 해야 할까요?
우선 GeometryReader로 Rectangle의 width를 알 수 있겠죠?
132.6666 이란 값을 상위 계층에 전달하기 위해서 PreferenceKey를 사용해야 합니다.
PreferenceKey를 준수하는 GeometryPreferenceKey를 추가해줄게요.
그다음 GeometryPreferenceKey에 값을 변경해줄게요.
GeometryPreferenceKey에 값을 설정했으니, 이 값을 가지고 Text 뷰의 width를 변경해주면 되겠죠?
@State 프로퍼티를 하나 추가하고, onPreferenceChange method를 통해 GeometryPreferenceKey 값이 변경되었을 때의 action을 넣어줍시다.
👍 👍 👍
## 참고
- https://developer.apple.com/documentation/swiftui/state-and-data-flow
- https://developer.apple.com/documentation/swiftui/preferencekey
- https://developer.apple.com/documentation/swiftui/form/preference(key:value:)
- https://developer.apple.com/documentation/swiftui/link/onpreferencechange(_:perform:)
- https://www.youtube.com/watch?v=OnbBc00lqWU&ab_channel=SwiftfulThinking
- https://swiftwithmajid.com/2020/01/15/the-magic-of-view-preferences-in-swiftui/
이번 글은 여기서 마무리.
'SwiftUI' 카테고리의 다른 글
TimelineView (0) | 2022.06.17 |
---|---|
trim (0) | 2022.06.06 |
Environment (0) | 2022.05.29 |
SwiftUI에서 ViewController를? (0) | 2022.05.11 |
복잡한 Navigation Flow 처리 (feat. Combine) (0) | 2022.05.10 |