SwiftUI

animatableData

Phililip
728x90

안녕하세요.

 

SwiftUI에서 Shape에 애니메이션이 적용 안 되는 경우가 있더라구요.

 

그래서 이번 글에서는 animatableData를 사용해서 Shape에 애니메이션을 적용하는 방법에 대해 알아볼게요.

 

 


 

우선 팔각형 형태의 Octagon이라는 Shape를 만들게요.

 

struct Octagon: Shape {
    var inset: CGFloat
    
    func path(in rect: CGRect) -> Path {
        return Path { path in
            path.move(to: CGPoint(x: inset, y: 0))
            path.addLines([
                CGPoint(x: 0, y: inset),
                CGPoint(x: 0, y: rect.height - inset),
                CGPoint(x: inset, y: rect.height),
                CGPoint(x: rect.width - inset, y: rect.height),
                CGPoint(x: rect.width, y: rect.height - inset),
                CGPoint(x: rect.width, y: inset),
                CGPoint(x: rect.width - inset, y: 0),
                CGPoint(x: inset, y: 0),
            ])
        }
    }
}

 

 

그 다음에 Octagon을 터치하면 inset에 랜덤한 값을 주도록 해볼게요.

 

struct ContentView: View {
    @State var inset: CGFloat = 50

    var body: some View {
        Octagon(inset: inset)
            .frame(width: 200, height: 200)
            .foregroundColor(.blue)
            .onTapGesture {
                inset = CGFloat.random(in: 10...90)
            }
    }
}

 

 

 

모양이 변하긴 하지만, 애니메이션이 적용 안되었네요.

 

 

 

withAnimation 함수를 사용해볼게요.

 

struct ContentView: View {
    @State var inset: CGFloat = 50

    var body: some View {
        Octagon(inset: inset)
            .frame(width: 200, height: 200)
            .foregroundColor(.blue)
            .onTapGesture {
                withAnimation {		✅
                    inset = CGFloat.random(in: 10...90)
                }
            }
    }
}

 

 

 

엥...?? 그래도 애니메이션이 적용 안되었습니다...

 

 

 

Shape는 애니메이션이 적용 안되나?? 하는 생각에 터치할 때마다 랜덤하게 scale 되는 코드를 추가해봤어요.

 

struct ContentView: View {
    @State var inset: CGFloat = 50
    @State var scale: CGFloat = 1	✅
    
    var body: some View {
        Octagon(inset: inset)
            .frame(width: 200, height: 200)
            .foregroundColor(.blue)
            .scaleEffect(scale)		✅
            .onTapGesture {
                withAnimation {
                    inset = CGFloat.random(in: 10...90)
                    scale = CGFloat.random(in: 0.5...1.5)	✅
                }
            }
    }
}

 

 

 

 

scale 효과는 애니메이션이 적용되었는데, inset 변경은 애니메이션이 적용되지 않는 것을 볼 수 있습니다.

 

 

 

왜 scale이 바뀔 때는 애니메이션이 적용되고, inset이 변경될 때는 애니메이션이 적용 안될까요??

 

그 이유는 SwiftUI 애니메이션 효과가 적용되는 조건을 봐야 해요.

 

SwiftUI의 애니메이션 효과는 뷰의 상태가 변경되었을 때, 상태 A -> 상태 B로 점차 바뀌면서 애니메이션 효과를 주게 됩니다.

 

만약 뷰의 scale이 1.0 -> 2.0으로 변경되었다면, 1.0에서 2.0으로 바로 바뀌는 것이 아니라, scale = 1.0, 1.1, 1.2, ..., 2.0이 적용되면서 애니메이션 효과를 주는 것이죠.

 

그런데 위의 inset은 뷰의 상태는 아니기 때문에 애니메이션 효과가 적용되지 않는 것이죠..ㅠㅠ

 

 

 

그럼 뷰의 상태가 아닌 특정 값이 변경되었을 때 애니메이션 효과를 주려면???

 

이때 animatableData가 사용됩니다.

 

애니메이션 효과를 주고 싶은 뷰 안에 animatableData 프로퍼티와 getter, setter를 구현해주면 됩니다ㅎㅎ

 

 

 

 

위에서 구현한 Octagon 뷰에 animatableData를 구현해볼게요.

 

struct Octagon: Shape {
    var inset: CGFloat
    var animatableData: CGFloat {	✅
        get { inset }
        set { inset = newValue }
    }
    func path(in rect: CGRect) -> Path {
        return Path { path in
            path.move(to: CGPoint(x: inset, y: 0))
            path.addLines([
                CGPoint(x: 0, y: inset),
                CGPoint(x: 0, y: rect.height - inset),
                CGPoint(x: inset, y: rect.height),
                CGPoint(x: rect.width - inset, y: rect.height),
                CGPoint(x: rect.width, y: rect.height - inset),
                CGPoint(x: rect.width, y: inset),
                CGPoint(x: rect.width - inset, y: 0),
                CGPoint(x: inset, y: 0),
            ])
        }
    }
}

 

 

Octagon에 애니메이션 적용할 거임?? 어떤 데이터가 변경되었을 때 애니메이션을 적용해줄까?? 의 의미라고 보시면 됩니다.

 

 

애니메이션이 진짜 잘 적용되는지 확인해볼까요??

 

 

 

 

👍 👍 👍

 

 

 

## 참고

- https://www.hackingwithswift.com/books/ios-swiftui/animating-simple-shapes-with-animatabledata

 

Animating simple shapes with animatableData - a free Hacking with iOS: SwiftUI Edition tutorial

Was this page useful? Let us know! 1 2 3 4 5

www.hackingwithswift.com

 

 


 

 

이번 글은 여기서 마무리.

 

 

 

 

 

반응형

'SwiftUI' 카테고리의 다른 글

cornerRadius  (0) 2022.03.13
SwiftUI에서 testable 한 코드 만들기  (0) 2022.03.05
renderingMode(_:)  (0) 2022.03.01
AlignmentGuide  (0) 2022.02.27
스크린샷 주의 팝업, 화면 녹화 방지  (3) 2022.02.25