UIViewをアニメーションで回転させて、角度を取得する方法

##やりたいこと
1. 下記で描いた円弧（UIView）をアニメーションで回転させたい。
[［Swift］円弧の描き方](https://qiita.com/tamagalago/items/7f02077a7853caf24a67)
2. 停止時に、円弧の角度を取得したい。


##イメージ

![animation.gif](https://qiita-image-store.s3.amazonaws.com/0/118372/adf0d654-cdf1-4c0e-e6f8-67cfc59141ef.gif)





###1. UIViewをアニメーションで回転させる

```swift: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?](http://blog.ericd.net/2017/03/15/getting-the-rotation-angle-after-cabasicanimation/)

```swift

// 一時停止
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)
}
    
```

###コード全体
```swift: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?](http://blog.ericd.net/2017/03/15/getting-the-rotation-angle-after-cabasicanimation/)
[Apple 公式リファレンス CABasicAnimation](https://developer.apple.com/documentation/quartzcore/cabasicanimation)