【问题标题】:Is CABasicAnimation's toValue relative to initial position?CABasicAnimation 的 toValue 是否相对于初始位置?
【发布时间】:2023-04-08 17:58:01
【问题描述】:

我有一个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.centerfloat 值添加到图层的起始位置一样。

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.

【问题讨论】:

  • 另外,如果您只想改变位置,似乎这一切都可以使用隐式动画来完成。
  • @dperk 这不是你做层隐式动画的方式——那是UIView 动画。你想在 CATransaction 块内做你的隐式动画。即[CATransaction begin]; [CATransaction setAnimationDuration:1.0]; <your changes to the layer> [CATransaction commit];
  • @originaluser2,对于支持隐式动画的图层属性,您根本不需要 CATransaction 开始/结束。您只需更改属性,更改就会使用默认设置进行动画处理。仅当您需要更改默认动画设置(缓动、持续时间等)时才需要 CATransaction 调用
  • 隐式动画仅适用于 LAYER 属性,不适用于视图属性。这是关键。
  • @DuncanC 当然,如果您对默认设置感到满意,您肯定不需要 CATransaction,我只是将 OP 的显式动画转换为隐式动画 :)

标签: ios objective-c core-animation cabasicanimation


【解决方案1】:

问题是您正在移动图层的frame,但此CAShapeLayer 的蓝点path 已在该图层的frame 内偏移self.view.center.x - 60 - 5, 163.5,即您指定的坐标为该CAShapeLayer 创建path。因此,当您为图层的position 设置动画时,蓝点仍会从这个新的position 偏移该数量。

解决方法是将CAShapeLayerpath 定义在图层的左上角,例如

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 时,它就会真正居中(现在,如果您移动图层的positionself.view.center,它并没有完全居中,因为它将位于中心的蓝点图层的左上角);
  • 您可以使用 UIKit Dynamics 将其捕捉到位置或定义其他行为,
  • 如果需要,您可以使用自动布局约束来指定位置,
  • 您可以定义一个UIView 子类,即IBDesignable,并使用此点作为视图,以便您可以将其添加到情节提要中并查看它的外观;等

【讨论】:

  • 另外,可以将形状层的边界设置为其路径的边界框。
【解决方案2】:

您在view 的父视图的坐标系中设置了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));

【讨论】:

  • CGRectGetMidX(self.view.bounds)self.view.center.x 相同。所以不幸的是,这会产生相同的结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-12-02
  • 2014-09-28
  • 1970-01-01
  • 2014-02-06
  • 2011-08-28
  • 2016-04-05
  • 2017-04-17
相关资源
最近更新 更多