swiftUI入門

「カウンターアプリ」アニメーション追加

リセットボタンを押したときに カウントの数字がフェード&拡大するアニメーション を追加したコードを紹介します!


アニメーション付きカウンターアプリ

import SwiftUI

struct ContentView: View {
    @State private var count = 0  // カウント変数
    @State private var animate = false  // アニメーション用の変数

    var body: some View {
        VStack(spacing: 20) {
            Text("カウンター: \(count)")
                .font(.largeTitle)
                .scaleEffect(animate ? 1.2 : 1.0) // 拡大アニメーション
                .opacity(animate ? 0.5 : 1.0) // 透明度アニメーション
                .animation(.easeInOut(duration: 0.3), value: animate) // アニメーション適用
                .padding()

            HStack {
                Button(action: { count -= 1 }) {
                    Text("−")
                        .font(.largeTitle)
                        .frame(width: 80, height: 80)
                        .background(Color.red.opacity(0.7))
                        .foregroundColor(.white)
                        .clipShape(Circle())
                }

                Button(action: { count += 1 }) {
                    Text("+")
                        .font(.largeTitle)
                        .frame(width: 80, height: 80)
                        .background(Color.blue.opacity(0.7))
                        .foregroundColor(.white)
                        .clipShape(Circle())
                }
            }

            // リセットボタン
            Button(action: {
                animate = true  // アニメーション開始
                count = 0
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
                    animate = false // アニメーションを元に戻す
                }
            }) {
                Text("リセット")
                    .font(.title)
                    .padding()
                    .frame(width: 150)
                    .background(Color.gray.opacity(0.7))
                    .foregroundColor(.white)
                    .cornerRadius(10)
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

ポイント

@State private var animate = false を追加
scaleEffect(animate ? 1.2 : 1.0) → 数字を拡大
opacity(animate ? 0.5 : 1.0) → 数字を少し薄く
.animation(.easeInOut(duration: 0.3), value: animate) でアニメーションを適用
DispatchQueue.main.asyncAfter を使い、0.3秒後に animate = false で元の状態に戻す


📌 こんな風に改造するともっと楽しくなる!

アニメーションを追加すると、アプリの体験がグッと良くなります!
リセットボタンを押したときやカウントが増減したときの動きを、いろいろ工夫できますよ✨


1️⃣ バウンドするアニメーション

数字がポヨンと跳ねるような動きを追加!

Text("カウンター: \(count)")
    .font(.largeTitle)
    .scaleEffect(animate ? 1.2 : 1.0) // 大きくなる
    .offset(y: animate ? -10 : 0) // 上に少し動く
    .animation(.interpolatingSpring(stiffness: 100, damping: 5), value: animate)

🔹 ポイント

  • offset(y: animate ? -10 : 0)カウントがポヨンと跳ねる
  • .interpolatingSpring(stiffness: 100, damping: 5)バネっぽい動き にする

2️⃣ フェード&スライドアニメーション

リセット時に 数字が下からスッと現れる

Text("カウンター: \(count)")
    .font(.largeTitle)
    .opacity(animate ? 0 : 1) // 透明度を変える
    .offset(y: animate ? 50 : 0) // 下から出てくる
    .animation(.easeOut(duration: 0.4), value: animate)

🔹 ポイント

  • .opacity(animate ? 0 : 1)一度透明にしてからフェードイン
  • .offset(y: animate ? 50 : 0)数字が下からスライドして出てくる

3️⃣ 背景色が変わるアニメーション

カウントが増えると 背景色が変化

Color(count >= 10 ? .yellow : .white)
    .edgesIgnoringSafeArea(.all)
    .animation(.easeInOut(duration: 0.5), value: count)

🔹 ポイント

  • count >= 10背景色を黄色に変える
  • .animation(.easeInOut(duration: 0.5), value: count)スムーズに色が変化

4️⃣ ボタンが押されたときに一瞬小さくなる

押したボタンが ギュッと縮んで戻る

Button(action: {
    animate = true
    count += 1
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
        animate = false
    }
}) {
    Text("+")
        .font(.largeTitle)
        .frame(width: 80, height: 80)
        .background(Color.blue.opacity(0.7))
        .foregroundColor(.white)
        .clipShape(Circle())
        .scaleEffect(animate ? 0.8 : 1.0) // 縮むアニメーション
        .animation(.spring(), value: animate)
}

🔹 ポイント

  • .scaleEffect(animate ? 0.8 : 1.0)ボタンが一瞬小さくなる
  • .spring()柔らかい動き にする

5️⃣ 数字が回転しながらリセット

リセット時に 数字がクルッと回る

Text("カウンター: \(count)")
    .font(.largeTitle)
    .rotationEffect(animate ? .degrees(360) : .degrees(0)) // 回転
    .animation(.easeInOut(duration: 0.5), value: animate)

🔹 ポイント

  • .rotationEffect(animate ? .degrees(360) : .degrees(0))1回転する
  • .easeInOut(duration: 0.5)なめらかに動く

実際に上記のアニメーションをコーディング

import SwiftUI

struct ContentView: View {
@State private var count = 0 // カウント変数
@State private var animateNumber = false // 数字のアニメーション用
@State private var animateReset = false // リセット時のアニメーション用
@State private var animateButton = false // ボタンを押したときのアニメーション

var body: some View {
    ZStack {
        // 背景色が変わるアニメーション
        Color(count >= 10 ? .yellow : .white)
            .edgesIgnoringSafeArea(.all)
            .animation(.easeInOut(duration: 0.5), value: count)

        VStack(spacing: 20) {
            // 数字の表示(バウンド & 回転 & フェード)
            Text("カウンター: \(count)")
                .font(.largeTitle)
                .scaleEffect(animateNumber ? 1.2 : 1.0) // ポヨンと跳ねる
                .opacity(animateReset ? 0 : 1) // フェードアウト
                .offset(y: animateReset ? 50 : 0) // 下からスライド
                .rotationEffect(animateReset ? .degrees(360) : .degrees(0)) // 回転
                .animation(.interpolatingSpring(stiffness: 100, damping: 5), value: animateNumber)
                .animation(.easeInOut(duration: 0.5), value: animateReset)

            HStack {
                // マイナスボタン
                Button(action: {
                    animateButton = true
                    count -= 1
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                        animateButton = false
                    }
                    animateNumber.toggle() // 数字のバウンド
                }) {
                    Text("−")
                        .font(.largeTitle)
                        .frame(width: 80, height: 80)
                        .background(Color.red.opacity(0.7))
                        .foregroundColor(.white)
                        .clipShape(Circle())
                        .scaleEffect(animateButton ? 0.8 : 1.0) // ギュッと縮む
                        .animation(.spring(), value: animateButton)
                }

                // プラスボタン
                Button(action: {
                    animateButton = true
                    count += 1
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                        animateButton = false
                    }
                    animateNumber.toggle() // 数字のバウンド
                }) {
                    Text("+")
                        .font(.largeTitle)
                        .frame(width: 80, height: 80)
                        .background(Color.blue.opacity(0.7))
                        .foregroundColor(.white)
                        .clipShape(Circle())
                        .scaleEffect(animateButton ? 0.8 : 1.0) // ギュッと縮む
                        .animation(.spring(), value: animateButton)
                }
            }

            // リセットボタン
            Button(action: {
                animateReset = true  // 数字をフェードアウト&回転
                count = 0
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
                    animateReset = false // 元に戻す
                }
            }) {
                Text("リセット")
                    .font(.title)
                    .padding()
                    .frame(width: 150)
                    .background(Color.gray.opacity(0.7))
                    .foregroundColor(.white)
                    .cornerRadius(10)
            }
        }
    }
}

}

struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

まとめ

アニメーション効果キーポイント
バウンド数字がポヨンと跳ねるoffset + interpolatingSpring
フェード&スライド下からスッと現れるopacity + offset
背景色変化カウントが増えると色が変わるColor + animation
ボタン縮小押した瞬間にギュッと縮むscaleEffect
回転リセットリセット時にクルッと回るrotationEffect

📌 さらに発展!

複数のアニメーションを組み合わせる
タップ時のフィードバック(振動)を加える (UIImpactFeedbackGenerator)
カウントが偶数のときだけ別のアニメーションをする

アニメーションを追加すると、アプリの 遊び心 が増して、より楽しいUIになります!
どれか試してみて、気に入った動きを追加してみてください😊🚀