圆到矩形变换动画

rol*_*JKS 1 core-animation cabasicanimation cashapelayer ios swift

我是iOS新手,我需要做以下动画:

在此输入图像描述

将圆转换为矩形应该是平滑的,但在上面的动画中它不是很平滑.

我所做的是使用本教程中的以下代码创建一个圆和一个矩形:

  Circle : 
        class OvalLayer: CAShapeLayer {

        let animationDuration: CFTimeInterval = 0.3

        override init() {
            super.init()
            fillColor = Colors.red.CGColor
            path = ovalPathSmall.CGPath
        }

        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }

        var ovalPathSmall: UIBezierPath {
            return UIBezierPath(ovalInRect: CGRect(x: 50.0, y: 50.0, width: 0.0, height: 0.0))
        }

        var ovalPathLarge: UIBezierPath {
            return UIBezierPath(ovalInRect: CGRect(x: 2.5, y: 17.5, width: 95.0, height: 95.0))
        }

        var ovalPathSquishVertical: UIBezierPath {
            return UIBezierPath(ovalInRect: CGRect(x: 2.5, y: 20.0, width: 95.0, height: 90.0))
        }

        var ovalPathSquishHorizontal: UIBezierPath {
            return UIBezierPath(ovalInRect: CGRect(x: 5.0, y: 20.0, width: 90.0, height: 90.0))
        }

        func expand() {
            let expandAnimation: CABasicAnimation = CABasicAnimation(keyPath: "path")
            expandAnimation.fromValue = ovalPathLarge.CGPath// change ovalPathLarge to ovalPathSmail for animation
            expandAnimation.toValue = ovalPathLarge.CGPath
            expandAnimation.duration = animationDuration
            expandAnimation.fillMode = kCAFillModeForwards
            expandAnimation.removedOnCompletion = false
            addAnimation(expandAnimation, forKey: nil)
        }

    }

Rectangle : 

    class RectangleLayer: CAShapeLayer {


    override init() {
        super.init()
        fillColor = Colors.clear.CGColor
        lineWidth = 5.0
        path = rectanglePathFull.CGPath
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    var rectanglePathFull: UIBezierPath {
        let rectanglePath = UIBezierPath()
        rectanglePath.moveToPoint(CGPoint(x: 0.0, y: 100.0))
        rectanglePath.addLineToPoint(CGPoint(x: 0.0, y: -lineWidth))
        rectanglePath.addLineToPoint(CGPoint(x: 100.0, y: -lineWidth))
        rectanglePath.addLineToPoint(CGPoint(x: 100.0, y: 100.0))
        rectanglePath.addLineToPoint(CGPoint(x: -lineWidth / 2, y: 100.0))
        rectanglePath.closePath()

//        fillColor = Colors.red.CGColor
        return rectanglePath
    }

//    var topLeft: UIBezierPath {}

    func animateStrokeWithColor(color: UIColor, view : UIView) {
        strokeColor = color.CGColor

//        CATransaction.setDisableActions(true)
//        view.layer.bounds.size.height = view.layer.bounds.width + 50

        let strokeAnimation: CABasicAnimation = CABasicAnimation(keyPath: "bounds.size.width") //bounds.size.width
        strokeAnimation.fromValue = view.layer.bounds.width
        strokeAnimation.toValue = view.layer.bounds.size.width - 50
        strokeAnimation.duration = 0.4
        addAnimation(strokeAnimation, forKey: nil)
    }
}

my view : 

    protocol HolderViewDelegate:class {
    func animateLabel()
}

class HolderView: UIView {

    let ovalLayer = OvalLayer()
    let redRectangleLayer = RectangleLayer()

    var parentFrame :CGRect = CGRectZero
    weak var delegate:HolderViewDelegate?

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = Colors.clear
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }

    func addOval() {
        layer.addSublayer(ovalLayer)
        ovalLayer.expand()
//        NSTimer.scheduledTimerWithTimeInterval(0.3, target: self, selector: "wobbleOval",
//            userInfo: nil, repeats: false)
    }

    func expandRectangle(){
        NSTimer.scheduledTimerWithTimeInterval(0.45, target: self,
            selector: "drawRedAnimatedRectangle",
            userInfo: nil, repeats: false)
    }

    func drawRedAnimatedRectangle() {
        layer.addSublayer(redRectangleLayer)
        redRectangleLayer.animateStrokeWithColor(Colors.red,view: self)
    }
Run Code Online (Sandbox Code Playgroud)

但我不知道怎么做动画,请有人帮帮我吗?

Ham*_*ish 9

如果要同时按比例增加和圆角半径减小到在发生同样的时间,您可以简化从我的其他答案代码显著.

您现在不再需要将动画"链接"在一起,因此您可以将它们都添加到单个动画中并同时CAAnimationGroup运行它们.

我们使用的属性将保持几乎相同,除了添加groupAnim属性和删除cornerRadiusUndoAnim.

class ViewController2: UIViewController {

    let animLayer = CALayer() // the layer that is going to be animated
    let cornerRadiusAnim = CABasicAnimation(keyPath: "cornerRadius") // the corner radius reducing animation
    let widthAnim = CABasicAnimation(keyPath: "bounds.size.width") // the width animation
    let groupAnim = CAAnimationGroup() // the combination of the corner and width animation
    let animDuration = NSTimeInterval(1.0) // the duration of one 'segment' of the animation
    let layerSize = CGFloat(100) // the width & height of the layer (when it's a square)

    ...        
Run Code Online (Sandbox Code Playgroud)

我们现在可以添加设置CAAnimationGroup,添加我们的角半径动画和缩放动画

override func viewDidLoad() {
    super.viewDidLoad()

    let rect = view.frame

    animLayer.backgroundColor = UIColor.blueColor().CGColor // color of the layer, feel free to change
    animLayer.frame = CGRect(x: rect.width-layerSize*0.5, y: rect.height-layerSize*0.5, width: layerSize, height: layerSize)
    animLayer.cornerRadius = layerSize*0.5;
    animLayer.anchorPoint = CGPoint(x: 1, y: 1) // sets so that when the width is changed, it goes to the left
    view.layer.addSublayer(animLayer)

    // decreases the corner radius
    cornerRadiusAnim.duration = animDuration
    cornerRadiusAnim.fromValue = animLayer.cornerRadius
    cornerRadiusAnim.toValue = 0;
    cornerRadiusAnim.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) // timing function to make it look nice

    // increases the width
    widthAnim.duration = animDuration
    widthAnim.fromValue = animLayer.frame.size.width
    widthAnim.toValue = rect.size.width
    widthAnim.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) // timing function to make it look nice

    // adds both animations to a group animation
    groupAnim.animations = [cornerRadiusAnim, widthAnim]
    groupAnim.duration = animDuration;
    groupAnim.autoreverses = true; // auto-reverses the animation once completed

}
Run Code Online (Sandbox Code Playgroud)

最后,我们可以在触摸视图时运行组动画,并且两个动画将同时运行(并在完成时自动反转).

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    animLayer.addAnimation(groupAnim, forKey: "anims") // runs both animations concurrently
}
Run Code Online (Sandbox Code Playgroud)

结果

在此输入图像描述


完整项目:https://github.com/hamishknight/Circle-to-Rect-Animation