如何制作线轨动画 CALayer?
How to make line track animating CALayer?
我有很多动画 CALayer,我想在制作动画时排列其中的一对。
假设有两个动画圈CALayer。我想画一条线来跟踪 CALayers 的中心。我提出了两种可能的解决方案。
1 每当圆形层添加什么动画时,计算直线对应的动画。
2 使用时间计算控制整个动画,灵感来自objc.io。在每一步中计算圆如何移动和移动到,以及线。
有问题,解决方案一,控制圆圈层数过多,代码会很差,而且不同的圆圈动画,应该有不同的对应。如果圈子多,动画种类多,那就更糟了,我也是这种情况。
解决方案二,我必须放弃Core Animation,从头开始做,这样会增加复杂度,以后也很难再做一些调整。
有没有更简单优雅的方法来做到这一点,也许是核心动画背后的一些技巧。非常感谢。
更新:
根据@Duncan C 指出的,我正在尝试使用具有相同时间功能的 3 层。
我根据圆圈创建了线条动画。动画需要添加,以便处理多个动画。但是动画添加到行 CAShaperLayer 使整个视图变黑。有什么问题吗?
这是一些代码。 TIA.
- (void)startHorizontalAnimation:(int)duplicateNum {
// circle animation
const double distance = 30;
int totalTime = 600;
int timeEachDirection = 5;
double zInterpolation = self.zPosition / duplicateNum;
double position = distance * 2 * zInterpolation - distance;
CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
animation.keyPath = @"position.x";
NSMutableArray *valueArr = [[NSMutableArray alloc] initWithObjects:@0, nil];
for (int i = 0; i < totalTime / (timeEachDirection * 2); ++i) {
[valueArr addObject:[NSNumber numberWithDouble:position]];
[valueArr addObject:[NSNumber numberWithDouble:-position]];
}
[valueArr addObject:@0];
animation.values = valueArr;
animation.additive = YES;
animation.duration = totalTime;
NSMutableArray *animationArr = [[NSMutableArray alloc] init];
for (int i = 0; i < [valueArr count] - 1; ++i) {
[animationArr addObject:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
}
animation.timingFunctions = animationArr;
animation.delegate = self.delegate;
[self addAnimation:animation forKey:ANIMI_HORIZONTALD_DISPERSE];
// line animation
CAAnimation *startAnimation = [self copyPositionFrom:animation modifyStart:YES onDirectionX:YES];
CAAnimation *endAnimation = [self copyPositionFrom:animation modifyStart:NO onDirectionX:YES];
[self.lineFrom addAnimation:startAnimation forKey:nil];
[self.lineTo addAnimation:endAnimation forKey:nil];
}
// create line animation according to the circle animation, changing the start point or end point on direction x or y.
- (CAAnimation *)copyPositionFrom:(CAKeyframeAnimation *)animation modifyStart:(BOOL)modifyStart onDirectionX:(BOOL)directionX {
CAKeyframeAnimation *newAnimation = [CAKeyframeAnimation animationWithKeyPath:@"path"];
newAnimation.additive = animation.additive;
newAnimation.duration = animation.duration;
newAnimation.timingFunction = animation.timingFunction;
newAnimation.delegate = animation.delegate;
CGPathRef lineCGPath = ((CAShapeLayer *)self.lineFrom).path;
NSMutableArray *bezierPoints = [NSMutableArray array];
// MyCGPathApplierFunc is according to
CGPathApply(lineCGPath, (__bridge void *)(bezierPoints), MyCGPathApplierFunc);
__block NSMutableArray *pathArray = [NSMutableArray array];
[animation.values enumerateObjectsUsingBlock:^(NSNumber *value, NSUInteger idx, BOOL *stop) {
CGPoint startPoint = [[bezierPoints objectAtIndex:0] CGPointValue];
CGPoint endPoint = [[bezierPoints objectAtIndex:1] CGPointValue];
// modify the position additively
if (modifyStart) {
if (directionX) {
startPoint.x += [value floatValue];
} else {
startPoint.y += [value floatValue];
}
} else {
if (directionX) {
endPoint.x += [value floatValue];
} else {
endPoint.y += [value floatValue];
}
}
UIBezierPath *linePath = [UIBezierPath bezierPath];
[linePath moveToPoint:startPoint];
[linePath addLineToPoint:endPoint];
[pathArray addObject:linePath];
}];
newAnimation.values = pathArray;
return newAnimation;
}
@interface CircleShapeLayer : CAShapeLayer
@property (nonatomic, weak) CAShapeLayer *lineFrom; // the line goes from the circle
@property (nonatomic, weak) CAShapeLayer *lineTo; // the line goes to the circle
@end
我建议您以相同的时序成套制作动画。
要为 2 个圆和它们之间的一条线设置动画,请将每个圆层的位置 属性 设置为单独的 CABasicAnimation 和第三个 CABasicAnimation 以设置线的动画(您可以使用设置动画的 CAShapeLayer 执行此操作形状图层中路径的起点和终点。)
或者,您可以对圆圈和连接线使用一个形状层,并立即对路径的所有更改进行动画处理(让路径包含 2 个圆圈和直线,并创建一个动画来更改控件一次得 3 分。)
我有很多动画 CALayer,我想在制作动画时排列其中的一对。
假设有两个动画圈CALayer。我想画一条线来跟踪 CALayers 的中心。我提出了两种可能的解决方案。
1 每当圆形层添加什么动画时,计算直线对应的动画。
2 使用时间计算控制整个动画,灵感来自objc.io。在每一步中计算圆如何移动和移动到,以及线。
有问题,解决方案一,控制圆圈层数过多,代码会很差,而且不同的圆圈动画,应该有不同的对应。如果圈子多,动画种类多,那就更糟了,我也是这种情况。
解决方案二,我必须放弃Core Animation,从头开始做,这样会增加复杂度,以后也很难再做一些调整。
有没有更简单优雅的方法来做到这一点,也许是核心动画背后的一些技巧。非常感谢。
更新: 根据@Duncan C 指出的,我正在尝试使用具有相同时间功能的 3 层。
我根据圆圈创建了线条动画。动画需要添加,以便处理多个动画。但是动画添加到行 CAShaperLayer 使整个视图变黑。有什么问题吗?
这是一些代码。 TIA.
- (void)startHorizontalAnimation:(int)duplicateNum {
// circle animation
const double distance = 30;
int totalTime = 600;
int timeEachDirection = 5;
double zInterpolation = self.zPosition / duplicateNum;
double position = distance * 2 * zInterpolation - distance;
CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
animation.keyPath = @"position.x";
NSMutableArray *valueArr = [[NSMutableArray alloc] initWithObjects:@0, nil];
for (int i = 0; i < totalTime / (timeEachDirection * 2); ++i) {
[valueArr addObject:[NSNumber numberWithDouble:position]];
[valueArr addObject:[NSNumber numberWithDouble:-position]];
}
[valueArr addObject:@0];
animation.values = valueArr;
animation.additive = YES;
animation.duration = totalTime;
NSMutableArray *animationArr = [[NSMutableArray alloc] init];
for (int i = 0; i < [valueArr count] - 1; ++i) {
[animationArr addObject:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
}
animation.timingFunctions = animationArr;
animation.delegate = self.delegate;
[self addAnimation:animation forKey:ANIMI_HORIZONTALD_DISPERSE];
// line animation
CAAnimation *startAnimation = [self copyPositionFrom:animation modifyStart:YES onDirectionX:YES];
CAAnimation *endAnimation = [self copyPositionFrom:animation modifyStart:NO onDirectionX:YES];
[self.lineFrom addAnimation:startAnimation forKey:nil];
[self.lineTo addAnimation:endAnimation forKey:nil];
}
// create line animation according to the circle animation, changing the start point or end point on direction x or y.
- (CAAnimation *)copyPositionFrom:(CAKeyframeAnimation *)animation modifyStart:(BOOL)modifyStart onDirectionX:(BOOL)directionX {
CAKeyframeAnimation *newAnimation = [CAKeyframeAnimation animationWithKeyPath:@"path"];
newAnimation.additive = animation.additive;
newAnimation.duration = animation.duration;
newAnimation.timingFunction = animation.timingFunction;
newAnimation.delegate = animation.delegate;
CGPathRef lineCGPath = ((CAShapeLayer *)self.lineFrom).path;
NSMutableArray *bezierPoints = [NSMutableArray array];
// MyCGPathApplierFunc is according to
CGPathApply(lineCGPath, (__bridge void *)(bezierPoints), MyCGPathApplierFunc);
__block NSMutableArray *pathArray = [NSMutableArray array];
[animation.values enumerateObjectsUsingBlock:^(NSNumber *value, NSUInteger idx, BOOL *stop) {
CGPoint startPoint = [[bezierPoints objectAtIndex:0] CGPointValue];
CGPoint endPoint = [[bezierPoints objectAtIndex:1] CGPointValue];
// modify the position additively
if (modifyStart) {
if (directionX) {
startPoint.x += [value floatValue];
} else {
startPoint.y += [value floatValue];
}
} else {
if (directionX) {
endPoint.x += [value floatValue];
} else {
endPoint.y += [value floatValue];
}
}
UIBezierPath *linePath = [UIBezierPath bezierPath];
[linePath moveToPoint:startPoint];
[linePath addLineToPoint:endPoint];
[pathArray addObject:linePath];
}];
newAnimation.values = pathArray;
return newAnimation;
}
@interface CircleShapeLayer : CAShapeLayer
@property (nonatomic, weak) CAShapeLayer *lineFrom; // the line goes from the circle
@property (nonatomic, weak) CAShapeLayer *lineTo; // the line goes to the circle
@end
我建议您以相同的时序成套制作动画。
要为 2 个圆和它们之间的一条线设置动画,请将每个圆层的位置 属性 设置为单独的 CABasicAnimation 和第三个 CABasicAnimation 以设置线的动画(您可以使用设置动画的 CAShapeLayer 执行此操作形状图层中路径的起点和终点。)
或者,您可以对圆圈和连接线使用一个形状层,并立即对路径的所有更改进行动画处理(让路径包含 2 个圆圈和直线,并创建一个动画来更改控件一次得 3 分。)