Notice
Recent Posts
Recent Comments
Link
관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - SwiftUI] 애니메이션 적용 주의사항 (animation, transition, withAnimation) 본문

iOS 응용 (SwiftUI)

[iOS - SwiftUI] 애니메이션 적용 주의사항 (animation, transition, withAnimation)

jake-kim 2024. 10. 11. 01:16

SwiftUI에서 애니메이션 적용 시 겪는 것

  • 뷰에다가 transition을 적용하려고해도 애니메이션이 걸리지 않음
  • transition을 매번 적용하고 싶은데 매번 동작하지 않음

(위와 관련된 개념들을 아래에서 알아볼 예정)

샘플 코드 준비) 버튼을 누르면 카운트가 올라가는 뷰

  • 아직 애니메이션 적용 x
import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            Text("count: \(cnt)")
            
            Button("refresh") {
               cnt += 1
            }
        }
        .padding()
    }
}

#Preview {
    ContentView()
}

  • 애니메이션을 주는 방법은 3가지가 존재
    • .animation()
    • withAnimation {}
    • .transition()

1. animation으로 애니메이션 주기

  • 단순히 .animation(.easeInOut)만 뷰에 붙이면 애니메이션 적용 완료
import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            Text("count: \(cnt)")  
                .animation(.easeInOut) // <- 추가
            
            Button("refresh") {
               cnt += 1
            }
        }
        .padding()
    }
}

결과)

2. withAnimation 으로 애니메이션 주기

  • withAnimation은 뷰에다가 적용하는게 아닌, 데이터를 변경시켜주는 쪽에서 사용
import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            Text("count: \(cnt)")  
            
            Button("refresh") {
                withAnimation {  // <- 추가
                    cnt += 1
                }
            }
        }
        .padding()
    }
}

결과)

  • withAnimation은 구체적인 애니메이션 타입을 정할 수 있고, 이 값은 첫 번째 방법 .animation과 동일한 옵션을 줄 수 있음
    • 둘 다 기능은 같지만, .animation은 뷰에다 직접 적용하는 방법이고, withAnimation은 데이터를 변경시켜 주는 쪽에서 적용해주는 방법
Button("refresh") {
    withAnimation(.easeInOut) {
        cnt += 1
    }
}

3. .transition()으로 애니메이션 주기

  • transition()은 뷰가 삭제될때나 생성될때만 적용됨 (같은 뷰가 다시 그려질 때는 적용안됨)
  • 첫번째 방법 .animation과 같이 뷰에다 직접 적용
struct ContentView: View {
    @State var cnt = 0
    
    var body: some View {
        VStack {
            Text("count: \(cnt)")
                .transition(.scale) // <-
            
            Button("refresh") {
                  cnt += 1
            }
        }
        .padding()
    }
}
  • 하지만 이렇게하면 애니메이션이 아무것도 걸리지 않음

  • transition은 데이터를 변경해주는 쪽에 withAnimation이 같이 수행되어야 동작
struct ContentView: View {
    @State var cnt = 0
    
    var body: some View {
        VStack {
            Text("count: \(cnt)")
                .transition(.scale) // <-
            
            Button("refresh") {
                withAnimation { // <-
                    cnt += 1
                }
            }
        }
        .padding()
    }
}
  • 이래도 애니메이션이 먹지 않음
    • -> transition은 뷰가 생성될때와 삭제될때만 동작하는데, 생성될때 이미 애니메이션이 동작했기 때문에 다시 동작안함
    • 애니메이션이 매번 걸리도록하는 방법은?
    • 뷰에다가 id를 부여하면 id가 바뀔때마다 뷰가 새로 만들어지는데 이 테크닉을 사용
struct ContentView: View {
    @State var cnt = 0
    
    var body: some View {
        VStack {
            Text("count: \(cnt)")
                .transition(.scale)
                .id("id_\(cnt)") // <-
            
            Button("refresh") {
                withAnimation {
                    cnt += 1
                }
            }
        }
        .padding()
    }
}

결과) transtion으로 애니메이션 적용 성공

애니메이션 적용 정리

  • 1. animation: 뷰에다 직접 적용하고 매번 애니메이션이 먹음
  • 2. withAnimation: 데이터를 변경시켜주는 쪽에서 적용
  • 3. transition: 생성되거나 사라질때만 애니메이션이 동작하며, withAnimation과 id를 부여하여 매번 애니메이션이 동작되게끔 처리가 가능
Comments