SwiftUI tutorials: How to troubleshoot a complex UI with layout and animation problems
import SwiftUI
struct ContentView: View {
@State private var isClicked: Bool = false
var body: some View {
GeometryReader { geometry in
ZStack(alignment: .top) {
Button {
isClicked.toggle()
} label: {
Image(systemName: isClicked ? "gobackward" : "plus.circle.fill")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: geometry.size.width / 5, height: geometry.size.width / 5, alignment: .center)
}
.rotationEffect(.degrees(isClicked ? 90 : 0))
.animation(.spring(), value: isClicked)
.offset(x: 0, y: isClicked ? geometry.size.height - 400 : geometry.size.height - 200)
.border(.blue)
Color.black
.frame(width: 100, height: 100)
.rotation3DEffect(.degrees(isClicked ? 180 : 0), axis: (x: 1, y: 1, z: 0))
.offset(x: 0, y: isClicked ? geometry.size.height - 300 : geometry.size.height - 100)
.animation(.spring(), value: isClicked)
.border(.black)
}
.background(Color.red)
.frame(width: geometry.size.width, height: geometry.size.height, alignment: .top)
.border(Color.yellow)
}
}
}
ZStack
안에 컴포넌트를 모두 선언, GeometryReader
로 읽어들인 현 시점의 전체 뷰(즉 컴포넌트를 모두 가지고 있는 부모 뷰)의 프레임을 통해 컴포너트가 위치할 offset
값 조정@State
프로퍼티를 통해 핸들링 → 각 컴포넌트 별로 애니메이션이 달려 있음import SwiftUI
struct ComplexView: View {
@State private var isClicked: Bool = false
var body: some View {
VStack(spacing: 40) {
if isClicked {
Spacer()
.frame(height: 60)
}
Button {
withAnimation(.easeIn(duration: 1)) {
isClicked.toggle()
}
} label: {
Image(systemName: isClicked ? "gobackward" : "plus.circle.fill")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 60, height: 60, alignment: .center)
}
.rotationEffect(.degrees(isClicked ? 90 : 0))
Color.black
.frame(width: 100, height: 100)
.rotation3DEffect(.degrees(isClicked ? 180 : 0), axis: (x: 1, y: 1, z: 0))
.animation(.easeIn(duration: 1), value: isClicked)
}
.zIndex(10)
}
}
ZStack
이 아니라 VStack
을 통해 쌓이는 컴포넌트 구조Spacer
를 통해 오프셋을 관리할 필요 없이 각 컴포넌트의 프레임, 패딩 값을 통해 조정 가능withAnimation
을 통해 implict animation
효과 적용 가능if isClicked {
Spacer()
.frame(height: 60)
}
@State
프로퍼티로 선언된 값에 따라 스페이서를 넣을 지 여부를 결정 가능VStack
으로 감싸고 있는 구조이기 때문에 스페이서를 통해 패딩 조정 가능withAnimation(.easeIn(duration: 1)) {
isClicked.toggle()
}
isClicked.toggle()
파트가 애니메이션 단 안에서 실행.zIndex(10)