Относительно ли CABasicAnimation toValue относительно начальной позиции?

У меня есть 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), как будто он добавляет float значения self.view.center к начальной позиции слоя.

Должно ли свойство 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.

person slider    schedule 31.05.2016    source источник
comment
Для управления этим есть свойство CAPropertyAnimation, которое называется additive. Если вы не меняете его, по умолчанию он должен быть отключен.   -  person jtbandes    schedule 31.05.2016
comment
Да, я не устанавливаю свойство additive.   -  person slider    schedule 31.05.2016
comment
Кроме того, похоже, что все это можно сделать с помощью неявной анимации, если вы просто хотите, чтобы положение изменилось.   -  person jtbandes    schedule 31.05.2016
comment
Неявная анимация у меня не работает. Я звоню blueDot.position = CGPointMake(x,y) внутрь [UIView animateWithDuration:], и синяя точка, кажется, прыгает туда. Явная анимация анимируется правильно, хотя и в неправильном положении.   -  person slider    schedule 31.05.2016
comment
@dperk Это не то, как вы делаете неявную анимацию слоя - это UIView анимация. Вы хотите сделать свою неявную анимацию внутри блока CATransaction. т.е. [CATransaction begin]; [CATransaction setAnimationDuration:1.0]; <your changes to the layer> [CATransaction commit];   -  person Hamish    schedule 31.05.2016
comment
@ originaluser2, для свойств слоя, поддерживающих неявную анимацию, вам вообще не нужно CATransaction begin / end. Вы просто меняете свойство, и изменение анимируется с настройками по умолчанию. Вызовы CATransaction необходимы только в том случае, если вам нужно изменить настройки анимации по умолчанию (замедление, продолжительность и т. Д.).   -  person Duncan C    schedule 31.05.2016
comment
Неявная анимация работает только со свойствами LAYER, но не со свойствами просмотра. Это ключевой момент.   -  person Duncan C    schedule 31.05.2016
comment
@DuncanC Конечно, CATransaction вам не нужен, если вас устраивают настройки по умолчанию, я просто переводил явную анимацию OP в неявную :)   -  person Hamish    schedule 31.05.2016
comment
@dperk Это для представлений с поддержкой уровня. Ваш blueDot не является нижележащим слоем данного представления - это просто слой. Следовательно, вы не можете использовать [UIView animateWithDuration:] на нем.   -  person Hamish    schedule 31.05.2016
comment
Для того, чего я пытаюсь достичь, я просто буду использовать UIView вместо CAShapeLayer. Легче неявно анимировать.   -  person slider    schedule 01.06.2016


Ответы (2)


Проблема в том, что вы перемещаете frame слоя, но синяя точка path этого CAShapeLayer была смещена в пределах frame этого слоя на self.view.center.x - 60 - 5, 163.5, координаты, которые вы указали при создании path для этого CAShapeLayer. Поэтому, когда вы анимируете position слоя, синяя точка все равно будет смещена на эту величину от этого нового position.

Исправление состоит в том, чтобы определить path из CAShapeLayer, чтобы он находился в верхнем левом углу слоя, например

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, с этой точкой в ​​качестве представления, чтобы вы могли добавить его в раскадровку и посмотреть, как он выглядит; и Т. Д.
person Rob    schedule 01.06.2016
comment
В качестве альтернативы можно установить границы слоя-фигуры как ограничивающую рамку его пути. - person David Rönnqvist; 01.06.2016

Вы устанавливаете toValue в системе координат супервизора view (из-за использования свойства 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));
person sgl0v    schedule 31.05.2016
comment
CGRectGetMidX(self.view.bounds) совпадает с self.view.center.x. К сожалению, это дает тот же результат. - person slider; 31.05.2016