2014-07-16 119 views
11

我尝试将圆形更改为正方形,反之亦然,并且我快到了。然而,它并不像预期那样动画。我想一个正方形的各个角落进行动画/在同一时间演变,但我得到的是以下几点:从圆形到方形的iOS动画/变形形状

enter image description here

我以动画形状财产使用CAShapeLayerCABasicAnimation

这里是我创建的圈子路径:

- (UIBezierPath *)circlePathWithCenter:(CGPoint)center radius:(CGFloat)radius 
{  
    UIBezierPath *circlePath = [UIBezierPath bezierPath]; 
    [circlePath addArcWithCenter:center radius:radius startAngle:0 endAngle:M_PI/2 clockwise:YES]; 
    [circlePath addArcWithCenter:center radius:radius startAngle:M_PI/2 endAngle:M_PI clockwise:YES]; 
    [circlePath addArcWithCenter:center radius:radius startAngle:M_PI endAngle:3*M_PI/2 clockwise:YES]; 
    [circlePath addArcWithCenter:center radius:radius startAngle:3*M_PI/2 endAngle:M_PI clockwise:YES]; 
    [circlePath closePath]; 
    return circlePath; 
} 

下面是方形路径:

- (UIBezierPath *)squarePathWithCenter:(CGPoint)center size:(CGFloat)size 
{ 
    CGFloat startX = center.x-size/2; 
    CGFloat startY = center.y-size/2; 

    UIBezierPath *squarePath = [UIBezierPath bezierPath]; 
    [squarePath moveToPoint:CGPointMake(startX, startY)]; 
    [squarePath addLineToPoint:CGPointMake(startX+size, startY)]; 
    [squarePath addLineToPoint:CGPointMake(startX+size, startY+size)]; 
    [squarePath addLineToPoint:CGPointMake(startX, startY+size)]; 
    [squarePath closePath]; 
    return squarePath; 
} 

我申请的圆圈路径我的看法的一层,设置填充等。它完美地绘制。 然后在我gestureRecognizer选择创建并运行下面的动画:

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"path"]; 
    animation.duration = 1; 
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 

animation.fromValue = (__bridge id)(self.stateLayer.path); 
     animation.toValue = (__bridge id)(self.stopPath.CGPath); 
self.stateLayer.path = self.stopPath.CGPath; 

[self.stateLayer addAnimation:animation forKey:@"animatePath"]; 

正如你可以在circlePathWithCenter:radius:squarePathWithCenter:size:我按照建议从这里看到(有相同数量的段和控制点): Smooth shape shift animation

动画看起来更好,然后从上面的文章,但它仍然不是一个我想要达到:(

我知道,我可以用简单的CALayer做到这一点,然后设置一个cornerRadius的适当等级使圆形超出正方形/矩形,之后使用动画cornerRadius属性将其从圆形更改为方形,但如果甚至可以使用CAShapeLayerpath动画完成此操作,我仍然非常好奇。

在此先感谢您的帮助!

+0

它看起来像你有同样的问题,因为这问题[http://stackoverflow.com/questions/17429797/smooth-shape-shift-animation],基于动画 - 可能值得一看 –

+0

嗯..它可能是 - 我知道这个问题,并遵循接受的答案的建议,但我仍然是一个死亡为我结束。我有相同数量的细分/控制点,我认为它们有帮助,因为我的动画形状稍好一些,但是从那里开始的动画却没有线索如何改进。 – fgeorgiew

回答

7

在操场上玩了一会儿之后,我注意到每条弧线都在bezier路径上添加了两段,而不仅仅是一段。此外,致电closePath增加了两个。所以为了保持细分的数量一致,我最终在我的方形路径中添加了假段。代码在Swift中,但我认为这并不重要。

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

好的发现重新提出了两点,做了一个客观的c版本。 –

0

我强烈推荐图书馆CanvasPod,它也有一个预定义的“变身”动画和易于集成。您也可以在网站canvaspod.io上查看示例。

2

我知道这是一个古老的问题,但这可能有助于某人。

我认为它更好地动画角落半径来获得这种效果。

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

动画:

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

基于@Danchoys答案,在这里它是Objective-C的。

信息是60像素和infoVC的按钮是下一个视图控制器推:

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];