안녕하세요.
이번에는 SwiftUI에서 View의 identity와 transition이 어떤 관계에 있으며 어떻게 화면이 렌더링 되는지에 대해 알아볼게요.
SwiftUI View의 identity는 2가지가 있어요.
- structual identity: View 계층에서 type과 위치에 따라 구분되는 암시적인 identity
- explicit identity: id 수식어를 사용해서 명시적으로 identity 선언
이런 Identity는 transition과 밀접한 관계를 가지고 있습니다.
(View의 identity가 바뀔 때, transition이 동작하게 됩니다.)
structual identity와 explicit idenity 별로 transition이 어떻게 동작하는지 알아볼게요.
## Structual identity
View 내부의 값이 바뀌더라도 View 자체의 structual identity는 변하지 않습니다.
아래의 예시를 볼까요?
struct ContentView: View {
@State private var count: Int = 0
var body: some View {
VStack {
SubView(count: count)
.transition(.move(edge: .leading)) 🤔
Button {
withAnimation {
count += 1
}
} label: {
Text("Increment")
}
}
}
}
struct SubView: View {
let count: Int
var body: some View {
RoundedRectangle(cornerRadius: 6)
.foregroundColor(.yellow)
.frame(width: 100, height: 100)
.overlay(
Text("\(count)")
.monospacedDigit()
.padding()
)
}
}
버튼을 누를 때마다 count 값이 바뀌게 되고, 그때마다 SubView가 다시 그려질 것이라고 예상해서 기존 SubView가 옆으로 사라지도록 transition을 넣어줬어요.
기대한 것처럼 잘 나오는지 한번 볼까요?
버튼이 누를 때마다 값이 바뀌긴 하지만, transition이 적용되지 않았습니다..
이 말은 'SubView의 Structual Identity가 동일하게 유지가 된다!' 라고 볼 수 있어요.
만약 지금 상태에서 transition이 적용되도록 하고 싶으면 어떻게 해야 할까요?
많은 방법들이 있지만.. 분기문을 통해서 View의 identity를 나눠주는 것도 좋은 방법이 될 것입니다ㅎㅎ
struct ContentView: View {
@State private var count: Int = 0
var body: some View {
VStack {
Group { ✅
if count % 2 == 0 {
SubView(count: count)
.transition(.move(edge: .leading))
} else {
SubView(count: count)
.transition(.move(edge: .leading))
}
}
Button {
withAnimation {
count += 1
}
} label: {
Text("Increment")
}
}
}
}
struct SubView: View {
let count: Int
var body: some View {
RoundedRectangle(cornerRadius: 6)
.foregroundColor(.yellow)
.frame(width: 100, height: 100)
.overlay(
Text("\(count)")
.monospacedDigit()
.padding()
)
}
}
structual identity는 'identity가 동일한지? 그래서 transition이 적용되는지?' 가 한눈에 안 보이는 단점이 있어요.
## Explicit identity
이번에는 명시적으로 identity를 설정해줄게요.
id 수식어를 사용해서 identity를 직접 설정해줄 수 있어요.
Hashable 한 값들만 identity로 설정할 수 있습니다!!
func id<ID>(_ id: ID) -> some View where ID : Hashable
이번에는 SubView에 id를 직접 선언해줘 볼게요.
struct ContentView: View {
@State private var count: Int = 0
var body: some View {
VStack {
SubView(count: count)
.id(count) ✅
.transition(.move(edge: .leading))
Button {
withAnimation {
count += 1
}
} label: {
Text("Increment")
}
}
}
}
struct SubView: View {
let count: Int
var body: some View {
RoundedRectangle(cornerRadius: 6)
.foregroundColor(.yellow)
.frame(width: 100, height: 100)
.overlay(
Text("\(count)")
.monospacedDigit()
.padding()
)
}
}
count가 변경됨에 따라 SubView의 identity도 변경되니 transition이 잘 적용되는 것을 볼 수 있습니다.ㅎㅎ
이렇게 명시적으로 identity를 설정하는 경우, identity가 잘못된 경우에는 transition이 이상하게 동작할 수 있으니 유의해줘야 합니다.
## 참고
- https://sakunlabs.com/blog/swiftui-identity-transitions/
이번 글은 여기서 마무리.
'SwiftUI' 카테고리의 다른 글
@FocusState (0) | 2022.12.11 |
---|---|
텍스트 길이에 맞춰서 자식뷰의 width를 통일시키는 방법 (0) | 2022.06.18 |
TimelineView (0) | 2022.06.17 |
trim (0) | 2022.06.06 |
PreferenceKey (0) | 2022.05.30 |