環境: Xcode8.2.1, Swift3
CGPath の変化をアニメーションさせる方法を試した。
気をつける点としては変更前と変更後のパスの数を同じにしておくこと。
import UIKit import PlaygroundSupport class SquareButton: UIControl { let pathLayer = CAShapeLayer() var squarePath: UIBezierPath! var halfMoonPath: UIBezierPath! required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } override init(frame: CGRect) { super.init(frame: frame) self.squarePath = self.squarePath(rect: frame) self.halfMoonPath = self.halfMoonPath(rect: frame) self.pathLayer.fillColor = UIColor.orange.cgColor self.pathLayer.strokeColor = UIColor.white.cgColor self.pathLayer.lineWidth = 4 self.pathLayer.path = self.squarePath.cgPath self.layer.addSublayer(self.pathLayer) } override func endTracking(_ touch: UITouch?, with event: UIEvent?) { super.endTracking(touch, with: event) self.toggle() } func toggle() { let anim = CABasicAnimation(keyPath: "path") if self.isSelected { anim.fromValue = self.halfMoonPath.cgPath anim.toValue = self.squarePath.cgPath } else { anim.fromValue = self.squarePath.cgPath anim.toValue = self.halfMoonPath.cgPath } anim.duration = 0.4 anim.fillMode = kCAFillModeForwards anim.isRemovedOnCompletion = false self.pathLayer.add(anim, forKey: "animatePath") self.isSelected = !self.isSelected } func squarePath(rect: CGRect) -> UIBezierPath { let initialPoint = CGPoint(x: 0, y: 0) let curveStart = CGPoint(x: rect.maxX * 0.05, y: 0) let curveControl = CGPoint(x: rect.maxX * 0.5, y: 0) let curveEnd = CGPoint(x: rect.maxX * 0.95, y: 0) let firstCorner = CGPoint(x: rect.maxX, y: 0) let secondCorner = CGPoint(x: rect.maxX, y: rect.maxY) let thirdCorner = CGPoint(x: 0, y: rect.maxY) let myBezier = UIBezierPath() myBezier.move(to: initialPoint) myBezier.addLine(to: curveStart) myBezier.addQuadCurve(to: curveEnd, controlPoint: curveControl) myBezier.addLine(to: firstCorner) myBezier.addLine(to: secondCorner) myBezier.addLine(to: thirdCorner) myBezier.close() return myBezier } func halfMoonPath(rect: CGRect) -> UIBezierPath { let initialPoint = CGPoint(x: 0, y: 0) let curveStart = CGPoint(x: rect.maxX * 0.05, y: 0) let curveControl = CGPoint(x: rect.maxX * 0.5, y: rect.maxY * 0.6) let curveEnd = CGPoint(x: rect.maxX * 0.95, y: 0) let firstCorner = CGPoint(x: rect.maxX, y: 0) let secondCorner = CGPoint(x: rect.maxX, y: rect.maxY) let thirdCorner = CGPoint(x: 0, y: rect.maxY) let myBezier = UIBezierPath() myBezier.move(to: initialPoint) myBezier.addLine(to: curveStart) myBezier.addQuadCurve(to: curveEnd, controlPoint: curveControl) myBezier.addLine(to: firstCorner) myBezier.addLine(to: secondCorner) myBezier.addLine(to: thirdCorner) myBezier.close() return myBezier } } let baseView = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 200)) baseView.backgroundColor = UIColor(red: 38.0/255, green: 151.0/255, blue: 68.0/255, alpha: 1) let button = SquareButton(frame: CGRect(x: 0, y: 0, width: 50, height: 50)) baseView.addSubview(button) button.center = baseView.center PlaygroundPage.current.liveView = baseView