← 아카이브로 돌아가기

Development · SwiftUI

SwiftUI transition으로 뷰의 등장과 퇴장 표현하기

뷰가 계층에 삽입되거나 제거될 때 transition과 animation으로 전환 효과를 적용하는 방법을 정리합니다.

Velog 원문 보기 ↗

Development 아카이브 표지

뷰의 위치나 색이 바뀌는 애니메이션과 뷰 자체가 계층에 들어오고 나가는 전환은 다르게 동작한다. transition을 적용했는데 움직이지 않았던 경우까지 함께 살펴봤다.

Animation Transition 효과

먼저 뷰에 애니메이션을 적용시킨 후, 조건문을 활용하여 뷰에 전환 효과를 적용시킬 수 있다.

struct TransitionStudy: View {
    
    @State var isAnimation: Bool = false
    
    var body: some View {
        VStack {
            Button("Button") {
            	// animation 효과 적용
                withAnimation {
                    isAnimation.toggle()
                }
            }
            Spacer()
            if isAnimation {
                RoundedRectangle(cornerRadius: 24)
                    .frame(height: UIScreen.main.bounds.height / 2)
                    // transition 효과 적용
                    .transition(.slide)
            }
        }
        .edgesIgnoringSafeArea(.bottom)
    }
}

Transition 종류

AnyTransition의 다양한 전환 효과를 적용시킬 수 있다.

.transition(.opacity)
.transition(.scale)
.transition(.slide)
.transition(.move(edge: .leading))
.transition(.push(from: .leading))
.transition(.offset(y: 100))

asymmetric을 활용하여 등장과 퇴장할 때의 전환 효과를 다르게 적용시킬 수 있다.

.transition(.asymmetric(
	insertion: .move(edge: .leading), // 등장 효과
	removal: .opacity // 퇴장 효과
))

combined을 활용하여 서로 다른 전환 효과를 동시에 적용시킬 수 있다.

.transition(.opacity.combined(with: .scale))

Removal Transition 오류

Removal Transition 시 zIndex가 0으로 변경되어, 애니메이션 적용이 안되는 것 처럼 보이는 경우가 있다. 이 때, zIndex를 명시적으로 설정하여 해결할 수 있다.

struct TransitionStudy: View {
    
    @State var isAnimating = false
    
    var body: some View {
        ZStack {
            Color.green
            	.zIndex(-1) // 배경의 zIndex를 설정할 경우
                .ignoresSafeArea()
                .onTapGesture {
                    withAnimation(.easeInOut) {
                        isAnimating.toggle()
                    }
                }
            if isAnimating {
                RoundedRectangle(cornerRadius: 24)
                    .zIndex(1) // 전경의 zIndex를 설정할 경우
                    .transition(.move(edge: .bottom))
                    .onTapGesture {
                        withAnimation(.easeInOut) {
                            isAnimating.toggle()
                        }
                    }
            }
        }
    }
}
← 아카이브로 돌아가기