CABasicAnimation 的 toValue 是否相对于初始位置?
Is CABasicAnimation's toValue relative to initial position?
我有一个 CALayer
,我正在明确地为一个新位置设置动画。我的 toValue
属性 似乎只相对于图层的初始位置。
CABasicAnimation *move = [CABasicAnimation animationWithKeyPath:@"position"];
move.fromValue = [NSValue valueWithCGPoint:CGPointMake(blueDot.position.x, blueDot.position.y)];
move.toValue = [NSValue valueWithCGPoint:CGPointMake(self.view.center.x, self.view.center.y)];
move.duration = 1.0;
[blueDot addAnimation:move forKey:@"myMoveAnimation"];
blueDot.position = CGPointMake(self.view.center.x, self.view.center.y);
因此此代码不会将图层重新绘制到视图的中心。看起来好像它真的是将图层重绘到 CGPointMake(self.view.center.x + blueDot.position.x, self.view.center.y + blueDot.position.y)
,就像它正在将 self.view.center
的 float
值添加到图层的起始位置。
toValue
属性 就应该这样吗?将我的 blueDot
移动到视图中心的最干净的方法是什么?
编辑:
-(void)viewDidLoad {
[super viewDidLoad];
blueDot = [CAShapeLayer layer];
[blueDot setPath:[[UIBezierPath bezierPathWithOvalInRect:CGRectMake(self.view.center.x - 60 - 5, 163.5, 10, 10)] CGPath]];
[blueDot setStrokeColor: [UIColor blueColor]CGColor];
[blueDot setFillColor:[UIColor blueColor]CGColor];
[[self.view layer] addSublayer:blueDot];
}
// 163.5 is a placeholder for another view's position value so it's more readable for you guys.
你在view
的superview的坐标系中设置了toValue
(因为使用了center
属性)。看起来这应该有效:
CABasicAnimation *move = [CABasicAnimation animationWithKeyPath:@"position"];
move.fromValue = [NSValue valueWithCGPoint:CGPointMake(blueDot.position.x, blueDot.position.y)];
move.toValue = [NSValue valueWithCGPoint:CGPointMake(CGRectGetMidX(view.bounds), CGRectGetMidY(view.bounds))];
move.duration = 1.0;
[blueDot addAnimation:move forKey:@"myMoveAnimation"];
blueDot.position = CGPointMake(CGRectGetMidX(view.bounds), CGRectGetMidY(view.bounds));
问题是您正在移动层的 frame
,但是此 CAShapeLayer
的蓝点 path
已在该层的 frame
内偏移通过 self.view.center.x - 60 - 5, 163.5
,您在为 CAShapeLayer
创建 path
时指定的坐标。因此,当您为图层的 position
设置动画时,蓝点仍会从这个新的 position
.
偏移该数量
修复方法是将CAShapeLayer
的path
定义在图层的左上角,例如
CAShapeLayer *blueDot = [CAShapeLayer layer];
blueDot.path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(5, 5) radius:5 startAngle:0 endAngle:M_PI * 2 clockwise:true].CGPath; // note that using arc often generates a better looking circle, probably not noticeable at this size, just probably good practice
blueDot.fillColor = [UIColor blueColor].CGColor;
现在当您移动 position
时,蓝点的原点将移动到那里。
顺便说一句,我通常会创建一个单独的 UIView
并将这个 CAShapeLayer
添加到那个。这样,您就可以享受各种不同的功能:
- 您可以享受
UIView
基于块的动画;
- 你可以使用
center
移动它,这样当你将它的 center
移动到它的父视图的 center
时,它就会真正居中(现在,如果你将层的 position
移动到 self.view.center
,它并不是真正居中,因为它将位于中心的蓝点层的左上角);
- 您可以使用 UIKit Dynamics 将其捕捉到位置或定义其他行为,
- 如果需要,您可以使用自动布局约束来指定位置,
- 您可以定义一个
UIView
子类,它是 IBDesignable
并将此点作为视图,以便您可以将它添加到故事板上并查看它的外观;等等
我有一个 CALayer
,我正在明确地为一个新位置设置动画。我的 toValue
属性 似乎只相对于图层的初始位置。
CABasicAnimation *move = [CABasicAnimation animationWithKeyPath:@"position"];
move.fromValue = [NSValue valueWithCGPoint:CGPointMake(blueDot.position.x, blueDot.position.y)];
move.toValue = [NSValue valueWithCGPoint:CGPointMake(self.view.center.x, self.view.center.y)];
move.duration = 1.0;
[blueDot addAnimation:move forKey:@"myMoveAnimation"];
blueDot.position = CGPointMake(self.view.center.x, self.view.center.y);
因此此代码不会将图层重新绘制到视图的中心。看起来好像它真的是将图层重绘到 CGPointMake(self.view.center.x + blueDot.position.x, self.view.center.y + blueDot.position.y)
,就像它正在将 self.view.center
的 float
值添加到图层的起始位置。
toValue
属性 就应该这样吗?将我的 blueDot
移动到视图中心的最干净的方法是什么?
编辑:
-(void)viewDidLoad {
[super viewDidLoad];
blueDot = [CAShapeLayer layer];
[blueDot setPath:[[UIBezierPath bezierPathWithOvalInRect:CGRectMake(self.view.center.x - 60 - 5, 163.5, 10, 10)] CGPath]];
[blueDot setStrokeColor: [UIColor blueColor]CGColor];
[blueDot setFillColor:[UIColor blueColor]CGColor];
[[self.view layer] addSublayer:blueDot];
}
// 163.5 is a placeholder for another view's position value so it's more readable for you guys.
你在view
的superview的坐标系中设置了toValue
(因为使用了center
属性)。看起来这应该有效:
CABasicAnimation *move = [CABasicAnimation animationWithKeyPath:@"position"];
move.fromValue = [NSValue valueWithCGPoint:CGPointMake(blueDot.position.x, blueDot.position.y)];
move.toValue = [NSValue valueWithCGPoint:CGPointMake(CGRectGetMidX(view.bounds), CGRectGetMidY(view.bounds))];
move.duration = 1.0;
[blueDot addAnimation:move forKey:@"myMoveAnimation"];
blueDot.position = CGPointMake(CGRectGetMidX(view.bounds), CGRectGetMidY(view.bounds));
问题是您正在移动层的 frame
,但是此 CAShapeLayer
的蓝点 path
已在该层的 frame
内偏移通过 self.view.center.x - 60 - 5, 163.5
,您在为 CAShapeLayer
创建 path
时指定的坐标。因此,当您为图层的 position
设置动画时,蓝点仍会从这个新的 position
.
修复方法是将CAShapeLayer
的path
定义在图层的左上角,例如
CAShapeLayer *blueDot = [CAShapeLayer layer];
blueDot.path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(5, 5) radius:5 startAngle:0 endAngle:M_PI * 2 clockwise:true].CGPath; // note that using arc often generates a better looking circle, probably not noticeable at this size, just probably good practice
blueDot.fillColor = [UIColor blueColor].CGColor;
现在当您移动 position
时,蓝点的原点将移动到那里。
顺便说一句,我通常会创建一个单独的 UIView
并将这个 CAShapeLayer
添加到那个。这样,您就可以享受各种不同的功能:
- 您可以享受
UIView
基于块的动画; - 你可以使用
center
移动它,这样当你将它的center
移动到它的父视图的center
时,它就会真正居中(现在,如果你将层的position
移动到self.view.center
,它并不是真正居中,因为它将位于中心的蓝点层的左上角); - 您可以使用 UIKit Dynamics 将其捕捉到位置或定义其他行为,
- 如果需要,您可以使用自动布局约束来指定位置,
- 您可以定义一个
UIView
子类,它是IBDesignable
并将此点作为视图,以便您可以将它添加到故事板上并查看它的外观;等等