ios开发 方形到圆的动画,从圆圈的iOS动画/变形形状方

本文探讨了如何使用CAShapeLayer和CABasicAnimation实现圆形与正方形之间的平滑转换动画。通过调整UIBezierPath的创建方式,确保路径拥有相同数量的段和控制点,实现了更流畅的形状变化效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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:

ydF4T.gif

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

}

QwicB.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值