본문 바로가기

iOS 프로그래밍/swiftUI

SwiftUI ( Animation )

이번에는 SwiftUI의 Animation에 대해서 공부해 보도록 하겠습니다.

애니메이션은 점점 변해갈 수 있는 값을 사용하는 것이 중점인데요
그래서 기본 UIkit에서도 isHidden으로 true / false를 사용하기 보다는 alpha값을 1 / 0 이렇게 사용하여 1 ... 0.8 ... 0.6 점차 내려갈 수 있는 값을 사용하였죠

SwiftUI는 쉽고 깔끔하면서도 강력한 애니메이션 기능을 제공합니다.

개별적인 효과들을 각각 적용하는 것은 물론이고 그것들을 조합하거나 덮어쓰고, 중단하는 등 애니메이션에 필요한 작업들을 직관적인 API를 통해 쉽게 조절할 수 있다고 합니다.


커스텀 뷰 애니메이션

애니메이션화 할 수 있는 것으로는
- 이미 화면에 준비되어 있는 컨테이너뷰 안에 있는 뷰
- ViewModifier 속성
- Shape
등등이 있습니다. 

Animatable 프로토콜

ViewModifier은 그 자체로는 애니메이션을 진행할 수 없고
AnimationModifier 프로토콜을 채택하여 animatableData에 animation될 값을 알려주는 방식으로 애니메이션이 실행됩니다.

여기서 포인트는 Animatable입니다.
아래와 같이 Shape도 기본적으로 Animatable을 가지기 때문에 animatableData 값을 설정할 수 있게 됩니다.
따라서 모든 shape는 애니메이션을 할 수 있다는 것을 알 수 있겠네요

그럼 Animatable은 무엇일까요?
아래처럼 Animatable을 보면 AnimatableData를 조작하여 사용 하는 것 같은데
아직은 어떻게 하는건지는 알 수 없네요

그렇다면 Angle을 살펴 보도록 하겠습니다.
여기서 AnimatableData는 각도(Double)를 사용하는 것을 예상할 수 있을것 같아요

AnimatablePair

CGPoint 같은 x와 y 두개의 값을 사용해야할 때는 어떻게 해야 할까요?
AnimatableData 타입으로 사용할 수 있게 하나의 타입으로 묶어 줄것이 필요할 때는 AnimatablePair를 사용 할 수 있다고 합니다.

 

위에서 애니메이션화 할 수 있는 것을 알아보았습니다.

이제 실질적으로 애니메이션 할 수 있는 방법에 대해서 알아볼까요?

애니메이션 방법에는 두가지가 있습니다.

- 암시적 애니메이션 <.animation(Animation)>
: 뷰의 수정자중 하나가 변경되면 자동으로 뷰의 수정자가 변경될때마다 애니메이션적용

- 명시적 애니메이션 < withAnimation(Animation) {} >
: 결과가 될 코드호출, ViewModifer나 Shape에서 변경하고 또는 뷰가오고갈때 동시에 모든 변화를 일으킬수 있습니다

암시적 애니메이션에서 컨테이너뷰에 애니메이션을 넣지 않고 font처럼 전체가 적용되는 현상이 있기 때문에 최소한의 단위로 애니메이션을 실행할 것을 권장하며
명시적 애니메이션에서 암시적 애니메이션을 재정의하지 않아야 합니다.

애니메이션 제어

지속시간, 딜레이, 반복유무, 곡선
linear - 일정한 속도
easeInOut - 천천히시작 > 빨라짐 > 끝에 다시느려짐
spring - 바운스 효과

전환 효과

.transition()사용
.scale, .identity, .opacity

여기까지 SwiftUI의 Animation을 공부한 것을 정리해보았는데요
실제로 적용하는 법을 알기 위하여 Demo파일을 만들어 보고 싶으시다면 아래 링크를 확인해보시면 좋을것 같네요
https://developer.apple.com/tutorials/swiftui/animating-views-and-transitions

추가로 transition에서 VStack vs ForEach, Group의 차이점을 주의해야합니다.

struct ContentView: View {
    @State private var isNum: Bool = true
    var body: some View {
        Group {
            VStack {
                Button(action: {
//                    withAnimation(.linear) {
                        isNum = !isNum
//                    }
                }, label: {
                    Text(isNum ? "들어가 네모네모" : "나와라 네모네모")
                })
            }
            Group {
                if isNum {
                    Text("ForEach")
                    ForEach(0..<3) { _ in
                        Rectangle().foregroundColor(.blue)
                        
                    }
                    Text("VStack")
                    VStack {
                        Rectangle().foregroundColor(.red)
                        Rectangle().foregroundColor(.red)
                        Rectangle().foregroundColor(.red)
                    }
                    Text("Group")
                    Group {
                        Rectangle().foregroundColor(.green)
                        Rectangle().foregroundColor(.green)
                        Rectangle().foregroundColor(.green)
                    }
                }
                Spacer()
            }
            .transition(.scale)
        }
        .animation(.linear(duration: 1))
    }
}

이와 같은 코드를 실행시켜 보면 ForEach, Group는 각 셀의 크기가 줄어들고 VStack은 전체 크기가 줄어드는것 처럼 보이더라구요

Group, ForEach와 같은 식별가능한 컨테이너뷰는 각각의 뷰들에대해서 일어나지만
ZStack은 전체에서 일어난다고 합니다.

Group {
                if isNum {

에서 Group -> VStack으로 바꾸면 
.transition(.scale)이 작동하지 않고 Fade out, Fade in으로 동작하더라구요
이 부분은 이유를 알아내지 못하였습니다.
알게 된다면 댓글 달아주세요🥲

 

'iOS 프로그래밍 > swiftUI' 카테고리의 다른 글

swiftUI 기본 요약  (0) 2020.12.17