CAKeyframeAnimationを使ってUIBezierPathをアニメーションさせる

![bezierPath1.gif](https://qiita-image-store.s3.amazonaws.com/0/26043/f3cdaf3a-d3bc-d719-4314-4f2df8cba4ea.gif)
ベジェ曲線を引っ張って動かしてみました。

こちらを参考にしました。
https://www.youtube.com/watch?v=pTrW3cZg1YU
[Desarrollo iOS 7: Core Animation: CAKeyFrameAnimation y mucho más](http://www.migueldiazrubio.com/2013/10/28/desarrollo-ios-7-profundizando-en-core-animation-cakeyframeanimation-y-uibezierpathanimation/)

# viewを追加
```swift
class sampleView: UIView,UIGestureRecognizerDelegate {
    var verticalLine:CAShapeLayer?
}
```

# addGestureRecognizerを追加
```swift
func addPanGesture() {
    var sgr = UIPanGestureRecognizer(target: self, action: "handleSlide:")
    sgr.delegate = self
    self.addGestureRecognizer(sgr)
}
```

# タッチ位置の変化量を取得
```swift
func handleSlide(gr:UIPanGestureRecognizer) {
    var amountX = gr.translationInView(self).x
    var amountY = gr.translationInView(self).y
    self.verticalLine?.path = self.getLinePathWithAmount(amountX: amountX, amountY: amountY)
    
    if gr.state == UIGestureRecognizerState.Ended {
        self.removeGestureRecognizer(gr)
        self.animateLineReturnFrom(positionX: amountX, positionY: amountY)
    }
}
```
今回はY方向の移動量しか使用していませんが、X方向の移動量も計算しています。

# アニメーション定義
```swift
func animateLineReturnFrom(#positionX: CGFloat,positionY: CGFloat) {
    var bounce = CAKeyframeAnimation(keyPath: "path")
    bounce.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)
    
    var values = [
        self.getLinePathWithAmount(amountX: positionX, amountY: positionY),
        self.getLinePathWithAmount(amountX: -(positionX * 0.7), amountY: -(positionY * 0.7)),
        self.getLinePathWithAmount(amountX: positionX * 0.4, amountY: positionY * 0.4),
        self.getLinePathWithAmount(amountX: -(positionX * 0.3), amountY: -(positionY * 0.3)),
        self.getLinePathWithAmount(amountX: positionX * 0.15, amountY: positionY * 0.15),
        self.getLinePathWithAmount(amountX: 0.0, amountY: 0.0)
    ]
    
    bounce.values = values
    bounce.duration = 0.9
    bounce.removedOnCompletion = false
    bounce.fillMode = kCAFillModeForwards
    bounce.delegate = self
    self.verticalLine?.addAnimation(bounce, forKey: "return")
}
```
配列valuesにベジェ曲線を追加します。すべての位置を追加するのはとても大変なのですが、CAKeyframeAnimationを使えばkeyframe間を補完してアニメーションしてくれます。

CAKeyframeAnimationとCABasicAnimationとの違いは以下の通り。

**CAKeyframeAnimation**
* 3つ以上の値を補完するアニメーション

**CABasicAnimation**
* 2つの値を補完するアニメーション

・参考
http://www.slideshare.net/nakiwo/cakeyframeanimation-25415214

# ベジェ曲線を定義
```swift
func getLinePathWithAmount(#amountX:CGFloat,amountY:CGFloat) -> CGPathRef {
    let w = UIScreen.mainScreen().bounds.width
    let h = UIScreen.mainScreen().bounds.height
    let centerY = h / 2
    
    var bezierPath = UIBezierPath()
    
    var topLeftPoint = CGPointMake(0, centerY)
    var topMidPoint = CGPointMake(w / 2, centerY + amountY)
    var topRightPoint = CGPointMake(w, centerY)
    
    bezierPath.moveToPoint(topLeftPoint)
    bezierPath.addQuadCurveToPoint(topRightPoint, controlPoint: topMidPoint)
    
    return bezierPath.CGPath
}
```

![](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIBezierPath_class/Art/quadratic_bezier_curve.jpg)
CurrentPoint、Control Point,Endpointの関係はAppleのリファレンスを参考にしました。
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIBezierPath_class/#//apple_ref/occ/instm/UIBezierPath/addQuadCurveToPoint:controlPoint:

# ベジェ曲線を描画する
```swift
func createLine() {
    verticalLine = CAShapeLayer(layer: self.layer)
    verticalLine?.lineWidth = 3.0
    verticalLine?.path = getLinePathWithAmount(amountX: 0.0, amountY: 0.0)
    verticalLine?.strokeColor = UIColor.whiteColor().CGColor
    verticalLine?.fillColor = UIColor.clearColor().CGColor
    
    self.layer.addSublayer(verticalLine)
}
```
CAShapeLayerに描画します。

以上。