iOS animate/morph shape from circle to square

后端 未结 4 913
不思量自难忘°
不思量自难忘° 2020-12-03 03:38

I try to change a circle into a square and vice versa and I am almost there. However it doesn\'t animates as expected. I would like all corners of a square to be animated/mo

相关标签:
4条回答
  • 2020-12-03 04:15

    After playing with it for a little while in the playground I noticed that each arc adds two segments to the bezier path, not just one. Moreover, calling closePath adds two more. So to keep the number of segments consistent, I ended up with adding fake segments to my square path. The code is in Swift, but I think it doesn't matter.

    func circlePathWithCenter(center: CGPoint, radius: CGFloat) -> UIBezierPath {
        let circlePath = UIBezierPath()
        circlePath.addArcWithCenter(center, radius: radius, startAngle: -CGFloat(M_PI), endAngle: -CGFloat(M_PI/2), clockwise: true)
        circlePath.addArcWithCenter(center, radius: radius, startAngle: -CGFloat(M_PI/2), endAngle: 0, clockwise: true)
        circlePath.addArcWithCenter(center, radius: radius, startAngle: 0, endAngle: CGFloat(M_PI/2), clockwise: true)
        circlePath.addArcWithCenter(center, radius: radius, startAngle: CGFloat(M_PI/2), endAngle: CGFloat(M_PI), clockwise: true)
        circlePath.closePath()
        return circlePath
    }
    
    func squarePathWithCenter(center: CGPoint, side: CGFloat) -> UIBezierPath {
        let squarePath = UIBezierPath()
        let startX = center.x - side / 2
        let startY = center.y - side / 2
        squarePath.moveToPoint(CGPoint(x: startX, y: startY))
        squarePath.addLineToPoint(squarePath.currentPoint)
        squarePath.addLineToPoint(CGPoint(x: startX + side, y: startY))
        squarePath.addLineToPoint(squarePath.currentPoint)
        squarePath.addLineToPoint(CGPoint(x: startX + side, y: startY + side))
        squarePath.addLineToPoint(squarePath.currentPoint)
        squarePath.addLineToPoint(CGPoint(x: startX, y: startY + side))
        squarePath.addLineToPoint(squarePath.currentPoint)
        squarePath.closePath()
        return squarePath
    }
    

    enter image description here

    0 讨论(0)
  • 2020-12-03 04:17

    I know this is an old question but this might help someone.

    I think its better to animate corner radius to get this effect.

        let v1 = UIView(frame: CGRect(x: 100, y: 100, width: 50, height: 50))
        v1.backgroundColor = UIColor.green
        view.addSubview(v1)
    

    animation:

        let animation = CABasicAnimation(keyPath: "cornerRadius")
        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
        animation.fillMode = kCAFillModeForwards
        animation.isRemovedOnCompletion = false
        animation.fromValue = v1.layer.cornerRadius
        animation.toValue = v1.bounds.width/2
        animation.duration = 3
        v1.layer.add(animation, forKey: "cornerRadius")
    
    0 讨论(0)
  • 2020-12-03 04:26

    Based on @Danchoys answer, here it is for Objective-C.

    info is a button of 60px and infoVC is the next ViewController being pushed:

        UIBezierPath * maskPath = [UIBezierPath new];
        [maskPath addArcWithCenter:info.center radius:15.0f startAngle:DEGREES_TO_RADIANS(180) endAngle:DEGREES_TO_RADIANS(270) clockwise:true];
        [maskPath addArcWithCenter:info.center radius:15.0f startAngle:DEGREES_TO_RADIANS(270) endAngle:DEGREES_TO_RADIANS(0) clockwise:true];
        [maskPath addArcWithCenter:info.center radius:15.0f startAngle:DEGREES_TO_RADIANS(0) endAngle:DEGREES_TO_RADIANS(90) clockwise:true];
        [maskPath addArcWithCenter:info.center radius:15.0f startAngle:DEGREES_TO_RADIANS(90) endAngle:DEGREES_TO_RADIANS(180) clockwise:true];
        [maskPath closePath];
    
        UIBezierPath * endPath = [UIBezierPath new];
        [endPath moveToPoint:CGPointMake(0,0)];
        [endPath addLineToPoint:endPath.currentPoint];
        [endPath addLineToPoint:CGPointMake(w, 0)];
        [endPath addLineToPoint:endPath.currentPoint];
        [endPath addLineToPoint:CGPointMake(w, h)];
        [endPath addLineToPoint:endPath.currentPoint];
        [endPath addLineToPoint:CGPointMake(0, h)];
        [endPath addLineToPoint:endPath.currentPoint];
        [endPath closePath];
    
        CAShapeLayer *maskLayer = [CAShapeLayer layer];
        maskLayer.frame = info.bounds;
        maskLayer.path = maskPath.CGPath;
        _infoVC.view.layer.mask = maskLayer;
    
        CABasicAnimation * animation = [CABasicAnimation animationWithKeyPath:@"path"];
        animation.fromValue = (id)maskPath.CGPath;
        animation.toValue = (id)endPath.CGPath;
        animation.duration = 0.3f;
        [maskLayer addAnimation:animation forKey:nil];
        [maskLayer setPath:endPath.CGPath];
    
    0 讨论(0)
  • 2020-12-03 04:33

    I can highly recommend the library CanvasPod, it also has a predefined "morph" animation and is easy to integrate. You can also check out examples on the website canvaspod.io.

    0 讨论(0)
提交回复
热议问题