CABasicAnimation を使ってゆっくり止めるという処理を考えてみたのですが、かなり実装がややこしくなりそうなので(そのままではUIView.animate
が適用できない上、layer.speed
は CABasicAnimation のkeyPath
として使えない)、代わりにCGAffineTransform
を使って回転させた方が最終的にはやりやすそうに思えます。
回転処理、停止処理を一つのメソッドにまとめることも可能ですが、ここではわかりやすさ優先であえて冗長的な記述をしています。
基本的な考え方は
-- 一定時間ごとに指定角度(ここでは10度)回転させるために、rotateImage(_:)
を呼び出す
-- タイマ割り込みは自動的に繰り返す
-- 連続して行われていたタイマ割り込みは止める
-- 止めるためのメソッド stopImage(_:)
を呼び出す
-- 回転角を減らす(ここでは 0.05 減らす)
-- 減らした回転角がゼロより大きければ、あらためてstopImage(_:)
を呼び出す
という流れです。
下記の動画は Animation Gif なので減速度合いがわかりにくいですが、それなりに減速しています。
あとは各種パラメータをお好きな具合に調整していただければと思います。
Swift
1import UIKit
2
3class ViewController: UIViewController {
4 // ボタンフラグ
5 var buttonStartFlg = true
6
7 // 現時点での回転角
8 var currentDegree: CGFloat = 0
9
10 // 定期割り込みのための Timer のインスタンス
11 var timer = Timer()
12
13 var interval: TimeInterval = 0.01
14
15 // ボタン
16 @IBOutlet weak var startButton: UIButton!
17 // ルーレット画像
18 @IBOutlet weak var rouletteImage: UIImageView!
19
20 // スタートボタンを押した際のIBAction
21 @IBAction func tapStartButton(_ sender: UIButton) {
22 // 初期スピード
23 let degree: CGFloat = 10.0
24
25 if buttonStartFlg {
26 // ストップボタンを押すまでは、定期的に(repeats: true)呼び出される
27 // 回転処理に使われるメソッドは rotateImage)
28 timer = Timer.scheduledTimer(timeInterval: interval, target: self, selector: #selector(rotateImage), userInfo: degree, repeats: true)
29 buttonStartFlg = false
30
31 // ボタンのタイトルを変更
32 startButton.setTitle("Stop", for: .normal)
33 } else {
34 // 定期的な呼び出しを中止する
35 timer.invalidate()
36
37 // 回転を徐々に止めるためのメソッドを1回だけ(repeats: false)呼び出し
38 // 止めるために使われるメソッドは stopImage
39 timer = Timer.scheduledTimer(timeInterval: interval, target: self, selector: #selector(stopImage), userInfo: degree, repeats: false)
40 }
41 }
42
43 // ストップボタンを押されるまで呼びだされる回転処理
44 @objc func rotateImage(_ sender: Timer) {
45 let degree = sender.userInfo as! CGFloat
46 let angle = currentDegree * CGFloat.pi / 180 // Radian
47 let affine = CGAffineTransform(rotationAngle: angle)
48 rouletteImage.transform = affine
49 currentDegree += degree
50 currentDegree.formRemainder(dividingBy: 360.0)
51 }
52
53 // ストップボタンを押した後、止まるまで呼び出される回転処理
54 @objc func stopImage(_ sender: Timer) {
55 // 呼び出し時に送られれてきた値を CGFloat に変換
56 var degree = sender.userInfo as! CGFloat
57
58 let angle = currentDegree * CGFloat.pi / 180 // Radian
59 let affine = CGAffineTransform(rotationAngle: angle)
60 rouletteImage.transform = affine
61 currentDegree += degree
62 currentDegree.formRemainder(dividingBy: 360.0)
63
64 // 回転角を減らす
65 degree -= 0.05
66
67 if degree > 0 {
68 // 回転角が正の間は、減らした回転角を使って再度タイマ割り込みを使う
69 timer = Timer.scheduledTimer(timeInterval: interval, target: self, selector: #selector(stopImage), userInfo: degree, repeats: false)
70 } else {
71 // 状態を元に戻し、ボタンのタイトルを変更する
72 buttonStartFlg = true
73 startButton.setTitle("Start", for: .normal)
74 }
75 }
76}
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/02/16 04:28
2021/02/16 08:51