3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-10-29

##やりたいこと

  1. 下記で描いた円弧(UIView)をアニメーションで回転させたい。
    [Swift]円弧の描き方
  2. 停止時に、円弧の角度を取得したい。

##イメージ

animation.gif

###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

3
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?