트랜지션은..
뷰 계층 구조에 새로운 뷰가 추가되거나 기존에 있던 것이 제거될 때 적용되는 애니메이션의 한 종류
따라서 transition Modifier 단독으로는 동작하지 않고 animation Modifier나 withAnimation 함수와 함께 사용해야 한다.
- 뷰 계층 구조에 새로운 뷰가 삽입되는 과정
- 뷰 계층 구조에 이미 추가된 뷰가 제거되는 과정
- 삽입과 제거가 동시에 일어나는 과정
중요한 것은 <뷰 계층 구조>에 변화가 생겨야 하고,
만약 뷰는 동일하고 그 안의 내용만 바뀌는 경우는 트랜지션이 적용되지 않는다.
struct TransitionExampleView: View {
@State private var showText = false
var body: some View {
VStack {
if showText {
Text("Transition")
}
Button {
withAnimation {
self.showText.toggle()
}
} label: {
Text("버튼 보이기")
}
}
}
}
Text라는 View가 VStack에 삽입/제거될 때 아무런 transition도 지정해주지 않으면 어떻게 될까?
기본으로 뭔가 적용된 것을 알 수 있음.
그래도 Text가 뽝! 하고 나오는것 같은 모습..
slide로 바꿔보았는데
struct TransitionExampleView: View {
@State private var showText = false
var body: some View {
VStack {
// Text가 추가/제거될 때 transition 효과 적용
if showText {
Text("Transition")
.transition(.slide) // .slide transition 설정
.animation(.easeInOut, value: showText)
}
Button {
withAnimation {
self.showText.toggle() // 애니메이션과 함께 상태 토글
}
} label: {
Text("버튼 보이기")
}
}
}
}
왜 사라질 때만 적용되고 나타날 땐 적용이 안되는건지 모르겠네
AnyTransition
트랜지션을 다룰 때는 타입 소거된 형태의 AnyTranstion 타입을 이용해야 한다.
트랜지션 합성
combine
- 2개 이상의 AnyTransition을 합성할 수 있다!
Text("Transition")
.transition(AnyTransition.slide.combined(with: .opacity))
asymmetric
- 기본 전환 효과들은 뷰가 삽입되고 제거될 때 동일한 형태로 적용되지만, 이걸 사용하면 두 시점에 서로 다르게 효과를 줄 수 있다.
var myTransition: AnyTransition {
let insertion = AnyTransition.opacity
.combined(with: .scale)
let removal = AnyTransition.move(edge: .leading)
return .asymmetric(insertion: insertion, removal: removal)
}
이런식으로 custom한 AnyTransition을 만들어서 넣어줄 수 있다.
Text("안녕하세요")
.transition(myTransition)
놀라운것은...
struct TransitionExampleView: View {
var myTransition: AnyTransition {
let insertion = AnyTransition.opacity
.combined(with: .scale)
let removal = AnyTransition.move(edge: .leading)
return .asymmetric(insertion: insertion, removal: removal)
}
@State private var showText = false
var body: some View {
VStack {
if showText {
Text("안녕하세요")
.transition(myTransition)
}
Button {
withAnimation {
self.showText.toggle() // 애니메이션과 함께 상태 토글
}
} label: {
Text("버튼 보이기")
}
}
}
}
프리뷰에 이 뷰 하나만 넣고 하면 나타날 때 transtion이 적용되지 않는데,
struct MyView: View {
var body: some View {
HStack {
TransitionExampleView()
TransitionExampleView()
}
}
}
이런식으로 여러개가 있으면 나온다.. 왜지?
뭘까..
아마 SwiftUI 버그겠지
modifier
- active와 identity 매개 변수에 ViewModifier 프로토콜을 채택하는 타입을 제공
- active: 뷰가 제거되기 직전의 상태
- identity: 뷰가 삽입되어 보이게 될 상태
애니메이션의 시작과 끝에서 이 두 매개 변수 값의 차이만큼 전환 효과가 발생하게 되며, 이것을 이용해 트렌지션을 만들 수 있다.
struct CustomScaleModifier: ViewModifier {
let scale: CGFloat
func body(content: Content) -> some View {
content
.scaleEffect(scale)
}
}
이런식으로 Modifer를 하나만들고,
Text("안녕하세요")
.transition(.modifier(active: CustomScaleModifier(scale: 0),
identity: CustomScaleModifier(scale: 1)))
이런식으로 사용한다.
View가 사라지기 직전에는 scale이 0이고,
View가 삽입되었을 때는 scale이 1이다.