##やりたいこと
- 下記で描いた円弧(UIView)をアニメーションで回転させたい。
[Swift]円弧の描き方 - 停止時に、円弧の角度を取得したい。
##イメージ
###1. UIViewをアニメーションで回転させる
ViewController.swift
var animation: CABasicAnimation = CABasicAnimation()
// animation の設定
animation = CABasicAnimation(keyPath: "transform.rotation")
animation.isRemovedOnCompletion = true
animation.fillMode = CAMediaTimingFillMode.forwards
animation.fromValue = 0
// 1回のアニメーションで、360度まで回転する。
animation.toValue = CGFloat(Double.pi / 180) * 360
// 回転速度
animation.duration = 2.0
// リピート回数
animation.repeatCount = .infinity
pathDrawView.layer.add(animation, forKey: "animation")
###2. アニメーションを停止させて、角度を取得する
こちらの記事を参考にさせてもらいました。
Getting the rotation angle after CABasicAnimation?
// 一時停止
func stopRotate() {
let layer = pathDrawView.layer
// 角度を取得する
let transform: CATransform3D = layer.presentation()!.transform
let angle: CGFloat = atan2(transform.m12, transform.m11)
var testAngle = radiansToDegress(radians: angle) + 90
if testAngle < 0 {
testAngle = 360 + testAngle
}
print("角度", testAngle)
angleLabel.text = String("\(Int(testAngle))°")
// アニメーションを停止する
layer.speed = 0.0
}
func radiansToDegress(radians: CGFloat) -> CGFloat {
return radians * 180 / CGFloat(Double.pi)
}
###コード全体
ViewController.swift
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var arkBackgroundView: UIView!
@IBOutlet weak var switchButton: UIButton!
@IBOutlet weak var angleLabel: UILabel!
var pathDrawView = PathDraw()
var isRotate = true
var animation: CABasicAnimation = CABasicAnimation()
override func viewDidLoad() {
super.viewDidLoad()
switchButton.setTitle("STOP", for: .normal)
pathDrawView = PathDraw(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
// isOpaque 背景を透明にする。デフォルトは黒色。
pathDrawView.isOpaque = false
arkBackgroundView.addSubview(pathDrawView)
// animation の設定
animation = CABasicAnimation(keyPath: "transform.rotation")
animation.isRemovedOnCompletion = true
animation.fillMode = CAMediaTimingFillMode.forwards
// 0度から回転を開始する。
animation.fromValue = 0
// 1回のアニメーションで、360度まで回転する。
animation.toValue = CGFloat(Double.pi / 180) * 360
// 回転速度
animation.duration = 2.0
// リピート回数
animation.repeatCount = .infinity
pathDrawView.layer.add(animation, forKey: "animation")
}
// 一時停止
func stopRotate() {
let layer = pathDrawView.layer
// 角度を取得する
let transform: CATransform3D = layer.presentation()!.transform
let angle: CGFloat = atan2(transform.m12, transform.m11)
var testAngle = radiansToDegress(radians: angle) + 90
if testAngle < 0 {
testAngle = 360 + testAngle
}
print("角度", testAngle)
angleLabel.text = String("\(Int(testAngle))°")
// 現在時刻を layer の timeOffset プロパティに設定
let pausedTime = layer.convertTime(CACurrentMediaTime(), from: nil)
layer.timeOffset = pausedTime
// アニメーションを停止する
layer.speed = 0.0
}
func radiansToDegress(radians: CGFloat) -> CGFloat {
return radians * 180 / CGFloat(Double.pi)
}
// 再開
func restartRotate() {
let layer = pathDrawView.layer
// 一時停止した時の時刻
let pausedTime = layer.timeOffset
// アニメーションを再開する
layer.speed = 1.0
// layer の timeOffset プロパティに 0 を設定
layer.timeOffset = 0.0
// beginTimeプロパティはアニメーションの開始時刻を表します。
layer.beginTime = 0.0
// 現在時刻 - 一時停止した時の時刻
let timeSincePause = layer.convertTime(CACurrentMediaTime(), from: nil) - pausedTime
layer.beginTime = timeSincePause
}
@IBAction func SpinButtonTapped(_ sender: Any) {
if isRotate {
switchButton.setTitle("START", for: .normal)
stopRotate()
print("stop!!")
isRotate = false
} else {
switchButton.setTitle("STOP", for: .normal)
restartRotate()
print("restart!")
isRotate = true
}
}
}
###参考
Getting the rotation angle after CABasicAnimation?
Apple 公式リファレンス CABasicAnimation