我的灵感来自于您的示例,尝试使用您的答案中提及的技术和一些链接来圈选动画。我打算将其扩展为多边形动画的更一般的圆,但目前它只适用于正方形。我有一个名为RDPolyCircle(CAShapeLayer的子类)的类,它负担繁重。下面是它的代码,
@interface RDPolyCircle()
@property (strong,nonatomic) UIBezierPath *polyPath;
@property (strong,nonatomic) UIBezierPath *circlePath;
@end
@implementation RDPolyCircle {
double cpDelta;
double cosR;
}
-(instancetype)initWithFrame:(CGRect) frame numberOfSides:(NSInteger)sides isPointUp:(BOOL) isUp isInitiallyCircle:(BOOL) isCircle {
if (self = [super init]) {
self.frame = frame;
_isPointUp = isUp;
_isExpandedPolygon = !isCircle;
double radius = (frame.size.width/2.0);
cosR = sin(45 * M_PI/180.0) * radius;
double fractionAlongTangent = 4.0*(sqrt(2)-1)/3.0;
cpDelta = fractionAlongTangent * radius * sin(45 * M_PI/180.0);
_circlePath = [self createCirclePathForFrame:frame];
_polyPath = [self createPolygonPathForFrame:frame numberOfSides:sides];
self.path = (isCircle)? self.circlePath.CGPath : self.polyPath.CGPath;
self.fillColor = [UIColor clearColor].CGColor;
self.strokeColor = [UIColor blueColor].CGColor;
self.lineWidth = 6.0;
}
return self;
}
-(UIBezierPath *)createCirclePathForFrame:(CGRect) frame {
CGPoint ctr = CGPointMake(frame.origin.x + frame.size.width/2.0, frame.origin.y + frame.size.height/2.0);
// create a circle using 4 arcs, with the first one symmetrically spanning the y-axis
CGPoint leftUpper = CGPointMake(ctr.x - cosR, ctr.y - cosR);
CGPoint cp1 = CGPointMake(leftUpper.x + cpDelta, leftUpper.y - cpDelta);
CGPoint rightUpper = CGPointMake(ctr.x + cosR, ctr.y - cosR);
CGPoint cp2 = CGPointMake(rightUpper.x - cpDelta, rightUpper.y - cpDelta);
CGPoint cp3 = CGPointMake(rightUpper.x + cpDelta, rightUpper.y + cpDelta);
CGPoint rightLower = CGPointMake(ctr.x + cosR, ctr.y + cosR);
CGPoint cp4 = CGPointMake(rightLower.x + cpDelta, rightLower.y - cpDelta);
CGPoint cp5 = CGPointMake(rightLower.x - cpDelta, rightLower.y + cpDelta);
CGPoint leftLower = CGPointMake(ctr.x - cosR, ctr.y + cosR);
CGPoint cp6 = CGPointMake(leftLower.x + cpDelta, leftLower.y + cpDelta);
CGPoint cp7 = CGPointMake(leftLower.x - cpDelta, leftLower.y - cpDelta);
CGPoint cp8 = CGPointMake(leftUpper.x - cpDelta, leftUpper.y + cpDelta);
UIBezierPath *circle = [UIBezierPath bezierPath];
[circle moveToPoint:leftUpper];
[circle addCurveToPoint:rightUpper controlPoint1:cp1 controlPoint2:cp2];
[circle addCurveToPoint:rightLower controlPoint1:cp3 controlPoint2:cp4];
[circle addCurveToPoint:leftLower controlPoint1:cp5 controlPoint2:cp6];
[circle addCurveToPoint:leftUpper controlPoint1:cp7 controlPoint2:cp8];
[circle closePath];
circle.lineCapStyle = kCGLineCapRound;
return circle;
}
-(UIBezierPath *)createPolygonPathForFrame:(CGRect) frame numberOfSides:(NSInteger) sides {
CGPoint leftUpper = CGPointMake(self.frame.origin.x, self.frame.origin.y);
CGPoint cp1 = CGPointMake(leftUpper.x + cpDelta, leftUpper.y);
CGPoint rightUpper = CGPointMake(self.frame.origin.x + self.frame.size.width, self.frame.origin.y);
CGPoint cp2 = CGPointMake(rightUpper.x - cpDelta, rightUpper.y);
CGPoint cp3 = CGPointMake(rightUpper.x, rightUpper.y + cpDelta);
CGPoint rightLower = CGPointMake(self.frame.origin.x + self.frame.size.width, self.frame.origin.y + self.frame.size.height);
CGPoint cp4 = CGPointMake(rightLower.x , rightLower.y - cpDelta);
CGPoint cp5 = CGPointMake(rightLower.x - cpDelta, rightLower.y);
CGPoint leftLower = CGPointMake(self.frame.origin.x, self.frame.origin.y + self.frame.size.height);
CGPoint cp6 = CGPointMake(leftLower.x + cpDelta, leftLower.y);
CGPoint cp7 = CGPointMake(leftLower.x, leftLower.y - cpDelta);
CGPoint cp8 = CGPointMake(leftUpper.x, leftUpper.y + cpDelta);
UIBezierPath *square = [UIBezierPath bezierPath];
[square moveToPoint:leftUpper];
[square addCurveToPoint:rightUpper controlPoint1:cp1 controlPoint2:cp2];
[square addCurveToPoint:rightLower controlPoint1:cp3 controlPoint2:cp4];
[square addCurveToPoint:leftLower controlPoint1:cp5 controlPoint2:cp6];
[square addCurveToPoint:leftUpper controlPoint1:cp7 controlPoint2:cp8];
[square closePath];
square.lineCapStyle = kCGLineCapRound;
return square;
}
-(void)toggleShape {
if (self.isExpandedPolygon) {
[self restore];
}else{
CABasicAnimation *expansionAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
expansionAnimation.fromValue = (__bridge id)(self.circlePath.CGPath);
expansionAnimation.toValue = (__bridge id)(self.polyPath.CGPath);
expansionAnimation.duration = 0.5;
expansionAnimation.fillMode = kCAFillModeForwards;
expansionAnimation.removedOnCompletion = NO;
[self addAnimation:expansionAnimation forKey:@"Expansion"];
self.isExpandedPolygon = YES;
}
}
-(void)restore {
CABasicAnimation *contractionAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
contractionAnimation.fromValue = (__bridge id)(self.polyPath.CGPath);
contractionAnimation.toValue = (__bridge id)(self.circlePath.CGPath);
contractionAnimation.duration = 0.5;
contractionAnimation.fillMode = kCAFillModeForwards;
contractionAnimation.removedOnCompletion = NO;
[self addAnimation:contractionAnimation forKey:@"Contraction"];
self.isExpandedPolygon = NO;
}
从视图控制器,我创建这个层的一个实例,并将其添加到一个简单视图的图层,然后做一个按钮推动画,
#import "ViewController.h"
#import "RDPolyCircle.h"
@interface ViewController()
@property (weak, nonatomic) IBOutlet UIView *circleView; // a plain UIView 150 x 150 centered in the superview
@property (strong,nonatomic) RDPolyCircle *shapeLayer;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// currently isPointUp and numberOfSides are not implemented (the shape created has numberOfSides=4 and isPointUp=NO)
// isInitiallyCircle is implemented
self.shapeLayer = [[RDPolyCircle alloc] initWithFrame:self.circleView.bounds numberOfSides: 4 isPointUp:NO isInitiallyCircle:YES];
[self.circleView.layer addSublayer:self.shapeLayer];
}
- (IBAction)toggleShape:(UIButton *)sender {
[self.shapeLayer toggleShape];
}
该项目可在这里找到,http://jmp.sh/iK3kuVs。
感谢您的例子,以及您的问题中的所有链接。阅读围绕这个问题的讨论很有意思,也很有帮助。 – rdelmar 2015-02-10 17:12:57
如何在动画命令中设置tovalue(myBezierTrivial.CGPath)? – ABJ 2018-01-01 06:08:20