0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SwiftUIのAnimationについてふわっと学ぶ(animatableData編)

Last updated at Posted at 2024-09-27

はじめに

SwiftUIのアニメーションを実装するときに時々見かけるanimatableData
何のことかさっぱりだったので、キャッチアップしてみました。

animatableDataとは

早速animatableDataとはなんなのか、animatableDataでググって一番最初に出てきた下記の記事を見てみました。

animatableDataAnimatableプロトコルが持つプロパティのようで、animatableDataに設定した値が変わることでその値に紐づくコンポーネントがアニメーションできるようになるみたいです。

とは言っても文面だけでみても理解しきれなかったので、サンプルコードを書いてみます。

やってみる

まずはanimatableDataを定義せずにアニメーションするのかを確認しました。
四角形のカスタムShapeをタップすると横幅と縦幅を変えるようにしました。
animatableDatawidthheightを設定していないので、おそらくこれらの値を更新してもアニメーションしないはず!

struct CustomRectangleView: View {
    
    @State private var width: CGFloat = 100
    @State private var height: CGFloat = 100
    
    var body: some View {
        ZStack {
            CustomShape(width: width, height: height)
        }
        .frame(maxWidth: width, maxHeight: height)
        .onTapGesture {
            withAnimation(.linear(duration: 0.5)) {
                width = CGFloat.random(in: 10...200)
                height = CGFloat.random(in: 10...200)
            }
        }
    }
    
    struct CustomShape: Shape {
        
        var width: CGFloat
        var height: CGFloat
        
        nonisolated func path(in rect: CGRect) -> Path {
            var path = Path()
            path.addRect(.init(x: (rect.width - width) / 2, y: (rect.height - height) / 2, width: width, height: height))
            return path
        }
    }
}

NoAnimatableData.gif

こちらは想定通りアニメーションせずでした。

続いて、animatableDataにwidthを設定してみます。

struct CustomRectangleView: View {
    
    @State private var width: CGFloat = 100
    @State private var height: CGFloat = 100
    
    var body: some View {
        ZStack {
            CustomShape(width: width, height: height)
        }
        .frame(maxWidth: width, maxHeight: height)
        .onTapGesture {
            withAnimation(.linear(duration: 0.5)) {
                width = CGFloat.random(in: 10...200)
                height = CGFloat.random(in: 10...200)
            }
        }
    }
    
    struct CustomShape: Shape {
        
        var width: CGFloat
        var height: CGFloat

        var animatableData: CGFloat { // 追加行
                            // 追加行
            get { return width }    // 追加行
            set { width = newValue } // 追加行
        }                            // 追加行
        
        nonisolated func path(in rect: CGRect) -> Path {
            var path = Path()
            path.addRect(.init(x: (rect.width - width) / 2, y: (rect.height - height) / 2, width: width, height: height))
            return path
        }
    }
}

WidthAnimatable.gif

上記例では、横幅の変更だけアニメーションし、縦幅はアニメーションしないようになっています。
ここまでの例でanimatableDataに設定したデータの変更がアニメーションするようになることがわかりました。

ただ調べてみるとそれだけではなさそうです。
animatableDataの設定の仕方によってはアニメーションの仕方も変えられるみたいです。

struct CountUpAnimationTextView: View {
    
    @State private var text: String = "0"
    
    var body: some View {
        CountUpAnimationText(text: text)
            .onAppear {
                withAnimation(.linear(duration: 5)) {
                    text = "100"
                }
            }
    }
}

struct CountUpAnimationText: View, Animatable {
    
    private var text = "0"
    
    init(text: String = "0") {
        
        self.text = text
    }

    // 設定されたテキストをDouble型として参照する
    var animatableData: Double {
        
        get { Double(text) ?? 0 }
        set { text = String(format: "%.0f", newValue) }
    }
    
    var body: some View {
        Text(text)
            .font(.system(size: 30, weight: .bold))
    }
}

TextAnimatable.gif

animatableDataにtextの値をDouble型で設定することで、
アニメーションするときには数字としてアニメーションしてくれるのでgifのようにカウントアップするアニメーションになります。
上記のようなanimatableDataを設定しなければ、アニメーションは以下のようになります。

TextAnimatableNormal.gif

終わり

animatableDataのさわりの部分しかキャッチアップできていないのですが、どういったものなのかふわっとわかった気になりました。
アニメーションしない場合はanimatableDataが設定できてないのではとか考えられそうです。
アニメーションの方法についても、animatableDataで制御できるところがあるのでアニメーションの実装の幅が増えました。

参考

https://qiita.com/takehito-koshimizu/items/786dac0741e19552907b
https://medium.com/@bancarel.paul/swiftui-animatable-api-620311791f8a
https://digitalbunker.dev/mastering-animatable-and-animatablepair-swiftui/

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?