Sponsor Link
環境&対象
- macOS Big Sur 11.2
- Xcode 12.4
- iOS 14.4
概要
乱数で、サイコロを目を表示するだけは普通なので、しばらく回転してから 目が表示されるようなビューを作ってみます。
SwiftUI のアニメーションを使って、実装してみます。
サイコロの目を表示
サイコロの目のイメージ画像を6枚 “1”, “2”, …, “6” という名前でリソース内に用意しました。
//
// ContentView.swift
//
// Created by : Tomoaki Yagishita on 2021/02/03
// © 2021 SmallDeskSoftware
//
//
import SwiftUI
struct ContentView: View {
// (1)
@State private var dice:Int = Int.random(in: 1...6)
var body: some View {
VStack {
// (2)
Image("\(dice)")
.resizable()
.scaledToFit()
Button(action: {
// (3)
self.dice = Int.random(in: 1...6)
}, label: {
Text("Roll")
})
}
.padding()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
- サイコロの値を保持する変数です。初期値を乱数を使って設定しています。
- 数字を名前に持つイメージを用意したので、そのまま使っています。
- Roll ボタンを押されたときに、サイコロの値を乱数で再設定しています。
パッと表示されてしまうと、すこしシンプルすぎる感じを受けます。
アニメーションを追加
複雑なアニメーションを作ると大変なので、SwiftUI で用意されている rotation3DEffect を使った アニメーションにします。
Rotation3DEffect を使うと表示要素を3次元的に回転させることができます。
rotation3DEffect アニメーション
func rotation3DEffect(_ angle: Angle, axis: (x: CGFloat, y: CGFloat, z: CGFloat), anchor: UnitPoint = .center, anchorZ: CGFloat = 0, perspective: CGFloat = 1) -> some View
Axis を回転軸として、anchor を中心に、angle 分回転するアニメーションとなります。
今回はイメージを使用しています。SwiftUI 視点では、イメージは、その名称でしかないので、デフォルトでアニメーションをつけることはできません。
ですので、明示的に、アニメーションを指定する必要があります。
アニメーションを動作させる起点が必要ですので、@State 変数を1つ追加します。
ボタンが押されたときにその変数を操作することで、再描画のきっかけとします。
再描画される側は、回転角度を変更することでアニメーションさせます。
以下のような動作になります。
使ったコードはこちら。
//
// ContentView.swift
//
// Created by : Tomoaki Yagishita on 2021/02/03
// © 2021 SmallDeskSoftware
//
// assset from https://chicodeza.com/freeitems/saikoro-illust.html
import SwiftUI
struct ContentView: View {
@State private var dice:Int = Int.random(in: 1...6)
// (1)
@State private var animate = false
var body: some View {
VStack {
Image("\(dice)")
.resizable()
.scaledToFit()
// (2)
.rotation3DEffect(
// (3)
Angle.degrees(animate ? 360 * 20 : 0),
axis: (x:1, y:1, z:1))
Button(action: {
self.dice = Int.random(in: 1...6)
// (4)
withAnimation {
animate.toggle()
}
}, label: {
Text("Roll")
})
}
.padding()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
- アニメーションの起点となる変数
- Image に対して rotation3DEffect を設定します。
- animate 変数を使用して回転角を指定することでアニメーションします(角度や軸そのものは、適当な値です)
- animate 変数を withAnimation 内で操作することで、アニメーションが行われるようになります。
アニメーションを改良
このままでも良いのですが、もう少し改良します。
アニメーションをよくみると、アニメーション開始時には、新しい数値になっています。
これをアニメーション途中で数字を切り替えるようにしてみます。(機能的には意味はないです・・・)
以下のようにアニメーションのコードを変更しました。
Button(action: {
// (1)
withAnimation(Animation.default.repeatForever()) {
animate.toggle()
}
// (2)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
withAnimation {
self.dice = Int.random(in: 1...6)
animate.toggle()
}
}
}, label: {
- 最初の数字でアニメーションを実行します
- 0.5秒後に、新しい数字を設定してアニメーションを実行します
こうすることで、途中までは最初の数字、後半から別の数字でアニメーションするようになります。
少しのコードを追加するだけで、動きが加わるのでアニメーションは作っていて楽しいです。
説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。
今回のコードをベースに、外部からサイコロを振れるように改良しています。
[SwiftUI] Combine をつかって サイコロを振ってみる
最後に、Swift Package 化しました。
[SwiftUI] 作ったビューを SwiftPackage にしてみる
Sponsor Link