[SwiftUI] Transitions

Junyoung Park·2022년 8월 20일
0

SwiftUI

목록 보기
31/136
post-thumbnail
post-custom-banner

How to create custom Transitions in SwiftUI | Advanced Learning #3

Transitions

구현 목표

  • Transition 커스텀
  • 애니메이션의 이동 방향을 커스텀할 수 있다.

구현 태스크

  1. 뷰 모디파이어를 커스텀, AnyTransition 익스텐션에 추가
  2. 값이 고정되었다면 static 변수로, 파라미터가 필요하다면 함수 선언 가능

핵심 코드

struct RotateViewModifier: ViewModifier {
    let angleDegree: Double
    
    init(angleDegree: Double = 40.0) {
        self.angleDegree = angleDegree
    }
    
    func body(content: Content) -> some View {
        content
            .rotationEffect(Angle(degrees: angleDegree))
            .offset(x: angleDegree != 0 ? UIScreen.main.bounds.width : 0,
                    y: angleDegree != 0 ? UIScreen.main.bounds.height : 0)
    }
}

extension AnyTransition {
    static var rotating: AnyTransition {
        modifier(
            active: RotateViewModifier(angleDegree: 180),
            identity: RotateViewModifier(angleDegree: 0))
    }
    
    static func rotating(angleDegree: Double) -> AnyTransition {
        modifier(
            active: RotateViewModifier(angleDegree: angleDegree),
            identity: RotateViewModifier(angleDegree: 0))
    }
    
    static var rotationOn: AnyTransition {
        asymmetric(
            insertion: .rotating,
            removal: .move(edge: .leading))
    }
}
  • AnyTransition은 활성화 상태와 그렇지 않은 상태를 구별하기 위해 뷰 모디파이어를 두 개 받는다. → 회전 상태를 보여주기 위한 RotationModifier의 경우 서로 다른 각도를 줌으로써 '회전하는 것처럼' 보이게 만들 수 있다.

소스 코드

import SwiftUI

struct RotateViewModifier: ViewModifier {
    let angleDegree: Double
    
    init(angleDegree: Double = 40.0) {
        self.angleDegree = angleDegree
    }
    
    func body(content: Content) -> some View {
        content
            .rotationEffect(Angle(degrees: angleDegree))
            .offset(x: angleDegree != 0 ? UIScreen.main.bounds.width : 0,
                    y: angleDegree != 0 ? UIScreen.main.bounds.height : 0)
    }
}

extension AnyTransition {
    static var rotating: AnyTransition {
        modifier(
            active: RotateViewModifier(angleDegree: 180),
            identity: RotateViewModifier(angleDegree: 0))
    }
    
    static func rotating(angleDegree: Double) -> AnyTransition {
        modifier(
            active: RotateViewModifier(angleDegree: angleDegree),
            identity: RotateViewModifier(angleDegree: 0))
    }
    
    static var rotationOn: AnyTransition {
        asymmetric(
            insertion: .rotating,
            removal: .move(edge: .leading))
    }
}

struct TransitionsBootCamp: View {
    @State private var transitionType: Int = 0
    @State private var showRectangle: Bool = false
    var body: some View {
        VStack {
            HStack(spacing: 20) {
                Button {
                    transitionType = 0
                } label: {
                    Text("First Transition")
                        .font(.headline)
                        .withDefaultButtonFormmating(.pink)
                }
                .withPressableStyle(0.8)
                Button {
                    transitionType = 1
                } label: {
                    Text("Second Transition")
                        .font(.headline)
                        .withDefaultButtonFormmating(.indigo)
                }
                .withPressableStyle(0.8)
            }
            .padding(.horizontal, 30)
            Spacer()
            if showRectangle {
                RoundedRectangle(cornerRadius: 25)
                    .frame(width: 250, height: 350)
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                    .transition(transitionType == 0 ? .rotating(angleDegree: 1080) : .rotationOn)
            }
            Spacer()
            
            Text("Click Me")
                .withDefaultButtonFormmating()
                .padding(.horizontal, 40)
                .onTapGesture {
                    withAnimation(.easeInOut) {
                        showRectangle.toggle()
                    }
                }
        }
    }
}
  • asymmetric를 통해 들어오는 방향과 나가는 방향이 일치하지 않을 수 있도록 구현 가능

구현 화면

profile
JUST DO IT
post-custom-banner

0개의 댓글