iOS 动画/变形形状从圆形到方形 [英] iOS animate/morph shape from circle to square

查看:45
本文介绍了iOS 动画/变形形状从圆形到方形的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试将圆形变成正方形,反之亦然,我几乎就到了.但是,它没有按预期制作动画.我想同时对正方形的所有角进行动画/变形,但我得到的是以下内容:

我使用 CAShapeLayerCABasicAnimation 来为形状属性设置动画.

这是我创建圆形路径的方法:

- (UIBezierPath *)circlePathWithCenter:(CGPoint)center radius:(CGFloat)radius{UIBezierPath *circlePath = [UIBezierPath bezierPath];[circlePath addArcWithCenter:center radius:radius startAngle:0 endAngle:M_PI/2 顺时针:YES];[circlePath addArcWithCenter:center radius:radius startAngle:M_PI/2 endAngle:M_PI 顺时针:YES];[circlePath addArcWithCenter:center radius:radius startAngle:M_PI endAngle:3*M_PI/2 顺时针:YES];[circlePath addArcWithCenter:center radius:radius startAngle:3*M_PI/2 endAngle:M_PI 顺时针:YES];[circlePath closePath];返回圆路径;}

这是方形路径:

- (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];返回squarePath;}

我将圆形路径应用到我的视图层之一,设置填充等.它完美地绘制.然后在我的gestureRecognizer 选择器中创建并运行以下动画:

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"path"];动画.持续时间 = 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: 中注意到的那样,我遵循这里的建议(具有相同数量的段和控制点):平滑变形动画

动画看起来比上面的帖子更好,但它仍然不是我想要实现的:(

我知道我可以用简单的 CALayer 来做到这一点,然后设置适当的 cornerRadius 级别,用正方形/矩形制作一个圆圈,然后制作动画 cornerRadius 属性将其从圆形更改为方形,但我仍然非常好奇是否可以使用 CAShapeLayerpath 动画来实现.>

预先感谢您的帮助!

解决方案

在操场上玩了一会儿后,我注意到每个弧向贝塞尔曲线路径添加了两个部分,而不仅仅是一个.此外,调用 closePath 增加了两个.所以为了保持段的数量一致,我最终在我的方形路径中添加了假段.代码是用 Swift 写的,但我觉得没关系.

func circlePathWithCenter(center: CGPoint, radius: CGFloat) ->UIBezierPath {让 circlePath = UIBezierPath()circlePath.addArcWithCenter(center, radius: radius, startAngle: -CGFloat(M_PI), endAngle: -CGFloat(M_PI/2), 顺时针: true)circlePath.addArcWithCenter(center, radius: radius, startAngle: -CGFloat(M_PI/2), endAngle: 0, 顺时针: true)circlePath.addArcWithCenter(center, radius: radius, startAngle: 0, endAngle: CGFloat(M_PI/2), 顺时针: true)circlePath.addArcWithCenter(center, radius: radius, startAngle: CGFloat(M_PI/2), endAngle: CGFloat(M_PI), 顺时针: true)circlePath.closePath()返回圆路径}func squarePathWithCenter(center: CGPoint, side: CGFloat) ->UIBezierPath {让 squarePath = UIBezierPath()让 startX = center.x - side/2让 startY = center.y - side/2squarePath.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()返回方路径}

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/morphed at the same time but what I get is the following:

I use CAShapeLayer and CABasicAnimation in order to animate shape property.

Here is how I create the circle path:

- (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;
}

Here is the square path:

- (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;
}

I apply the circle path to one of my View's layers, set the fill etc. It draws perfectly. Then in my gestureRecognizer selector I create and run the following animation:

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

As you can notice in the circlePathWithCenter:radius: and squarePathWithCenter:size: I follow the suggestion from here (to have the same number of segments and control points): Smooth shape shift animation

The animation looks better then in the post from above but it is still not the one I want to achieve :(

I know that I can do it with simple CALayer and then set appropriate level of cornerRadius to make a circle out of square/rectangle and after that animate cornerRadius property to change it from circle to square but I'm still extremaly curious if it is even possible to do it with CAShapeLayer and path animation.

Thanks in advance for help!

解决方案

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
}

这篇关于iOS 动画/变形形状从圆形到方形的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆