【Swift】CoreAnimationで遊ぶ

#はじめに
今回は、CoreAnimationを使ってアニメーションで遊んでみます。

#GitHub

https://github.com/0429oonishi/Animation-Sample

#CoreAnimation
[CoreAnimation](https://developer.apple.com/documentation/quartzcore)はドキュメントでは以下のように書かれています。
>Core Animation provides high frame rates and smooth animations without burdening the CPU and slowing down your app. Most of the work required to draw each frame of an animation is done for you. You configure animation parameters such as the start and end points, and Core Animation does the rest, handing off most of the work to dedicated graphics hardware, to accelerate rendering. 

>Core Animationは、CPUに負担をかけたり、アプリの速度を低下させたりすることなく、高いフレームレートとスムーズなアニメーションを提供します。 アニメーションの各フレームを描画するために必要な作業のほとんどは、あなたのために行われます。 開始点や終了点などのアニメーションパラメータを設定すると、Core Animationが残りの作業を行い、ほとんどの作業を専用のグラフィックハードウェアに渡して、レンダリングを高速化します。

つまり、軽くて高速に動く便利なフレームワークということですね！

#実装(CABasicAnimation)
CABasicAnimationの完成品は以下です。
![ezgif.com-gif-maker.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/086a4f65-ae6b-9698-3d72-0b55ad7b8027.gif)

ストリーボードでUIButtonと正方形のUIViewを配置します。

![ScreenShot 2021-07-05 12.10.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/8119bc85-8df2-a971-3a79-d60d99c39619.png)


```swift 
final class ViewController: UIViewController {
    
    @IBOutlet private weak var myView: UIView!
    
    private var shapeLayer: CAShapeLayer!
    private var path: UIBezierPath!
    private var height: CGFloat { myView.frame.size.height }
    private var width: CGFloat { myView.frame.size.width }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        setupMyView()
        
    }
    
    private func setupMyView() {
        path = UIBezierPath()
        path.move(to: CGPoint(x: width / 2, y: 0.0))
        path.addLine(to: CGPoint(x: 0.0, y: height / 2))
        path.addLine(to: CGPoint(x: width / 2, y: height))
        path.addLine(to: CGPoint(x: width, y: height / 2))
        path.close()
        
        shapeLayer = CAShapeLayer()
        shapeLayer.path = path.cgPath
        shapeLayer.lineWidth = 3
        myView.layer.mask = shapeLayer
    }
    
    // MARK: - CABasicAnimation
    @IBAction private func CABasicButtonDidTapped(_ sender: Any) {
        let animation = CABasicAnimation(keyPath: #keyPath(CALayer.opacity))
        animation.fromValue = 1
        animation.toValue = 0
        animation.duration = 3
        animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
        shapeLayer.add(animation, forKey: nil)
    }
    
}
```

#解説(CABasicAnimation)
[CABasicAnimation](https://developer.apple.com/documentation/quartzcore/cabasicanimation)を使うことで、簡単なアニメーションを実現することができます。

keyPathを指定することで、どのようなアニメーションにするのかを指定します。今回は、opacityを変更しています。

```swift
let animation = CABasicAnimation(keyPath: #keyPath(CALayer.opacity))
```

fromValueとtoValueで初めと終わりの値を指定できます。

```swift
animation.fromValue = 1
animation.toValue = 0
```

durationでアニメーション時間を指定できます。

```swift
animation.duration = 3
```

[timingFunction](https://developer.apple.com/documentation/quartzcore/caanimation/1412456-timingfunction)を使うことで、自然なアニメーションを実現できます。
以下の5つが用意されています。
・Linear
・EaseIn
・EaseOut
・EaseInEaseOut
・Default

#実装(CAKeyframeAnimation)
CABasicAnimationよりもより細かいアニメーションができます。
![ezgif.com-gif-maker (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/10ed3131-8f21-65a6-04d8-48e56f301bf6.gif)

```swift
// MARK: - CAKeyframeAnimation
@IBAction private func CAKeyframeButtonDidTapped(_ sender: Any) {
    let animation = CAKeyframeAnimation(keyPath: #keyPath(CALayer.position))
    let path = CGMutablePath()
    path.move(to: CGPoint(x: 0, y: 0))
    path.addCurve(to: CGPoint(x: 100, y: 100),
                  control1: CGPoint(x: 0, y: 100),
                  control2: CGPoint(x: 100, y: 100))
    path.addCurve(to: CGPoint(x: -100, y: 100),
                  control1: CGPoint(x: -50, y: 50),
                  control2: CGPoint(x: 100, y: -100))
    animation.path = path
    animation.duration = 3
    shapeLayer.add(animation, forKey: nil)
}
```


#解説(CAKeyframeAnimation)
[CAKeyframeAnimation](https://developer.apple.com/documentation/quartzcore/cakeyframeanimation)

CAKeyframeAnimationのkeyPathを指定して、今回はpositionを変更してみます。

```swift
let animation = CAKeyframeAnimation(keyPath: #keyPath(CALayer.position))
```

[CGMutablePath](https://developer.apple.com/documentation/coregraphics/cgmutablepath)を使います。

```swift
let path = CGMutablePath()
```

CGMutablePathの[addCurve](https://developer.apple.com/documentation/coregraphics/cgmutablepath/2427158-addcurve)メソッドを使って曲線を描くようなアニメーションを実現させます。

```swift
path.addCurve(to: CGPoint(x: 100, y: 100),
              control1: CGPoint(x: 0, y: 100),
              control2: CGPoint(x: 100, y: 100))
path.addCurve(to: CGPoint(x: -100, y: 100),
              control1: CGPoint(x: -50, y: 50),
              control2: CGPoint(x: 100, y: -100))
```

#おわりに
[参考にさせていただいた記事](https://qiita.com/shiz/items/10cb712a26620f2e3bdc#cakeyframeanimation)