XLOG

[SwiftUI] Animation 적용 기본 이론편 본문

Swift/SwiftUI

[SwiftUI] Animation 적용 기본 이론편

X_PROFIT 2023. 8. 7. 21:58

기본적으로 SwiftUI 에 애니메이션을 적용하기 위해 .animation(_:value:) 를 사용하거나 withAnimation() 을 사용했다.

1. 둘의 차이

우선 이 둘의 차이에 대해 먼저 확인을 해보자. animation(_:value:) 는?

먼저 .animation() 이다. 인스턴스 메소드로 some View 를 리턴한다. view를 리턴한다는 것은 viewModifier 로 생각하면 되는 것 같다. 변화를 추적할 값 V 의 변화를 감지, 그로 인해 영향을 받는 변수들을 animation 옵션에 따라 state 의 변화를 주어 해당 View에 애니메이션을 적용한다.

그렇다면 withAnimation은 ?

withAnimation은 함수이다. 결과값을 Return 한다. 즉 결과값을 리턴을 하게 되면 withAnimation은 메모리에서 해제가 될 수 있다고 생각된다. withAnimation 의 경우 클로져 내부에 변화를 주는 변수와 관련이 있는 모드 State의 변화를 준다. 즉 modifier처럼 하나의 view에 적용하는 것이 아닌 그 변수를 포함하고 있는 모든 View에 변화를 주게 된다.

일단 이렇게 말로만 하면 이해가 어려우니, 예시코드와 실제 동작에 대해 살펴보자.

 

2. 예시 코드 및 동작 예시

 

먼저 animation() 을 살펴보자.

struct AnimationView: View {
    
    @State var animationToggle: Bool = true
    
    var body: some View {
        VStack {
            HStack {
                VStack {
                    Text("\(animationToggle ? "Red" : "Blue")")
                        .animation(.easeInOut(duration: 2), value: animationToggle)
                    Rectangle()
                        .frame(width: 100, height: 100)
                        .cornerRadius(animationToggle ? 0 : 10)
                        .foregroundColor(animationToggle ? .red : .blue)
                        .animation(.easeInOut(duration: 2), value: animationToggle)
                        .onTapGesture {
                            animationToggle.toggle()
                        }
                        
                }
                
                VStack {
                    Text("\(animationToggle ? "Red" : "Blue")")
                    Rectangle()
                        .frame(width: 100, height: 100)
                        .cornerRadius(animationToggle ? 0 : 10)
                        .foregroundColor(animationToggle ? .red : .blue)
                        .onTapGesture {
                            animationToggle.toggle()
                        }
                }
            }
        }
    }
}

HStack 으로 왼쪽과 오른쪽 animationToggle 값에 의해 상태값의 변화를 주도록 했고, 왼쪽만 animation ViewModifier를 적용했다. 이 경우 왼쪽, 오른쪽 어느쪽을 탭을 하든지 왼쪽만 animation viewModifier를 거쳐서 View에 애니메이션이 적용된다.

 

그렇다면 withAnimation 은 어떨까?

VStack {
            HStack {
                VStack {
                    Text("\(animationToggle ? "Red" : "Blue")")
                        .animation(.easeInOut(duration: 2), value: animationToggle)
                    Rectangle()
                        .frame(width: 100, height: 100)
                        .cornerRadius(animationToggle ? 0 : 10)
                        .foregroundColor(animationToggle ? .red : .blue)
                        .animation(.easeInOut(duration: 2), value: animationToggle)
                        .onTapGesture {
                            withAnimation(.easeInOut(duration: 2)) {
                                animationToggle.toggle()
                            }
                            
                        }
                        
                }
                
                VStack {
                    Text("\(animationToggle ? "Red" : "Blue")")
                    Rectangle()
                        .frame(width: 100, height: 100)
                        .cornerRadius(animationToggle ? 0 : 10)
                        .foregroundColor(animationToggle ? .red : .blue)
                        .onTapGesture {
                            withAnimation(.easeInOut(duration: 2)) {
                                animationToggle.toggle()
                            }
                        }
                        
                }
                
            }
        }

위의 코드에서 onTapGesture 클로져 내부에 withAnimation만 적용시켰다. 이 경우 animation modifier가 있든 없든 view의 state 값들을 일정한 애니메이션을 적용하여 값을 변화시킨다. 즉 좌우 어느곳을 탭하더라도 동일한 애니메이션 효과를 얻을 수 있다.

 

3. 동작원리

두 개의 동작원리는 똑같다고 볼 수 있다. 우리는 SwiftUI 가 State 값에 의해 View 를 re rendering 한다는 것을 알고 있다. 여기에서 buttonToggle 값으 animation의 Trigger 라고 생각해도 된다. buttonToggle의 값의 변화로 view 에서는 animation을 생성한다. 여기서 animation 은 state 값의 변화다. 그 변화를 주는 방법은 다양한다. linear, eassIn, easeOut, easeInOut, smooth, snappy, bouncy.... 

간단하게 linear 는 일정한 가속도로 state값의 변화를 주게 된다. animation은 frame 단위로 state 값의 변화를 주고 view를 re Rendering 하는 것이다.

즉 위에 easeInOut 이 아니라 linear 로 duration을 2초로 설정했다면, button이 토글되는동안 60hz 의 아이폰은 한 프레임다 cornerRadius 값을 10 / 120 씩 증가시키는 것이다. 

wwdc23 Explore SwiftUI Animation 속 scaleEffect 의 state value 를 1.0 > 1.5로 변화시키는 과정

 

4. animation VS withAnimation 어떤것을 사용해야 하는가?

사실 여기에 정답은 없어보인다. 개인적으로는 withAnimation 이 메모리 관리 측면에서, 사용후 메모리가 해제되는 modifier 형태의 animation 보다 효율이 좋지 않을까 생각된다. 하지만 그 비중이 크지 않을 것 같다. 

그럼에도 withAnimation이 더 좋게 느껴지는 것은 swiftUI 의 경우 변수를 쉽게 binding 할 수 있다. 즉 여러 구조체에 변수를 binding 을 한다면 서로 다른 View 구조체에 일정한 Trigger로 애니메이션 효과를 줄 수 있으며 .animation modifier를 사용하지 않아도 되기 때문에 중복 코드를 줄일 수 있지 않을까 싶다.