Ios 圆到矩形变换动画

Ios 圆到矩形变换动画,ios,swift,core-animation,cashapelayer,cabasicanimation,Ios,Swift,Core Animation,Cashapelayer,Cabasicanimation,我对iOS非常陌生,我需要制作以下动画: 圆到矩形的变换应该是平滑的,但在上面的动画中它不是很平滑 我所做的是使用以下代码创建一个圆和一个矩形: 但是我不知道如何制作动画,有人能帮我吗?为了获得平滑的动画效果,你想看看如何制作cornerRadius属性的动画,而不是乱搞贝塞尔路径。 所以动画是这样的: 设置角半径从当前值到零的动画 将宽度设置为屏幕宽度 反向宽度动画 反向角半径动画 那么,让我们从定义一些我们将要使用的属性开始: class ViewController: UIViewCon

我对iOS非常陌生,我需要制作以下动画:

圆到矩形的变换应该是平滑的,但在上面的动画中它不是很平滑

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


但是我不知道如何制作动画,有人能帮我吗?

为了获得平滑的动画效果,你想看看如何制作
cornerRadius
属性的动画,而不是乱搞贝塞尔路径。

所以动画是这样的:

  • 设置角半径从当前值到零的动画
  • 将宽度设置为屏幕宽度
  • 反向宽度动画
  • 反向角半径动画
  • 那么,让我们从定义一些我们将要使用的属性开始:

    class ViewController: UIViewController {
    
        let animLayer = CALayer() // the layer that is going to be animated
        let cornerRadiusAnim = CABasicAnimation(keyPath: "cornerRadius") // the corner radius reducing animation
        let cornerRadiusUndoAnim = CABasicAnimation(keyPath: "cornerRadius") // the corner radius increasing animation
        let widthAnim = CABasicAnimation(keyPath: "bounds.size.width") // the 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)
    
        ...
    
    在这里,我们定义了要使用的层、动画、动画“片段”的持续时间以及
    CALayer
    的大小

    接下来,让我们在
    viewDidLoad

    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: kCAMediaTimingFunctionEaseIn) // timing function to make it look nice
    
    
        // inverse of the cornerRadiusAnim
        cornerRadiusUndoAnim.duration = animDuration
        cornerRadiusUndoAnim.fromValue = 0;
        cornerRadiusUndoAnim.toValue = animLayer.cornerRadius
        cornerRadiusUndoAnim.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut) // timing function to make it look nice
    
        // increases the width, and autoreverses on completion
        widthAnim.duration = animDuration
        widthAnim.fromValue = animLayer.frame.size.width
        widthAnim.toValue = rect.size.width
        widthAnim.autoreverses = true
        widthAnim.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) // timing function to make it look nice
        widthAnim.delegate = self // so that we get notified when the width animation finishes
    
    }
    
    这里没有什么太难的,我们只是定义层和动画属性。我还添加了一些计时功能,以使动画看起来漂亮和平滑,而不是线性

    接下来,让我们开始我们的动画。我将在
    touchesbeated
    功能中执行此操作,但您可以将其放在任何位置

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        widthAnim.beginTime = CACurrentMediaTime()+animDuration // starts after the corner radius anim has finished
    
        animLayer.addAnimation(widthAnim, forKey: "widthAnim")
        animLayer.addAnimation(cornerRadiusAnim, forKey: "cornerRadius")
    
        CATransaction.begin()
        CATransaction.setDisableActions(true) // disables implicit animations
        animLayer.cornerRadius = 0
        CATransaction.commit()
    }
    
    同样,我们使用
    CATransaction
    corneradius
    设置回其原始值。就这样


    最终结果



    完整项目:

    如果您希望同时进行缩放和角半径减小,可以显著简化

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

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

    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)
    
        ...        
    
    现在,我们可以添加
    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
    
    }
    
    最后,我们可以在触摸视图时运行组动画,两个动画将同时运行(完成后自动反转)

    覆盖函数触摸开始(触摸:设置,withEvent事件:UIEvent?){
    addAnimation(groupAnim,forKey:“anims”)//同时运行两个动画
    }
    

    结果



    完整项目:

    您对如何在放大的同时减小转弯半径有何想法?这两种情况都应该发生一次。我添加了另一个答案(因为这个答案已经足够长了!)说明您将如何执行此操作:)嗨,我对您的代码有一个问题:我删除了自动反转,但当动画结束时,我的视图会立即返回到其原始状态。。。有什么想法吗?谢谢
    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)
    
        ...        
    
    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
    
    }
    
    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        animLayer.addAnimation(groupAnim, forKey: "anims") // runs both animations concurrently
    }