Вращение CAShapeLayer также перемещает позицию

Я создаю CAShapeLayer. Я добавляю к нему анимацию вращения. Как-то результат трансформации является странным. Детский слой перемещается вместе с вращением. Мне нужно, чтобы он находился в фиксированном центре/положении (якорь) и вращался. Я знаю, что он испортил геометрические преобразования, но я не могу понять это правильно.

Я попытался установить опорную точку. Я также последовал за этим сообщением

Вот код:

UIBezierPath *circle = [UIBezierPath bezierPathWithArcCenter:CGPointMake(75, 125)
                                                      radius:50
                                                  startAngle:0
                                                    endAngle:1.8 * M_PI
                                                   clockwise:YES];

CAShapeLayer *circleLayer = [CAShapeLayer layer];
[circleLayer setFrame:CGRectMake(200 - 50, 300 - 50, 100, 100)];
circleLayer.path   = circle.CGPath;
circleLayer.strokeColor = [UIColor orangeColor].CGColor;
[circleLayer setFillColor:[UIColor clearColor].CGColor];
circleLayer.lineWidth   = 3.0;

if ([circleLayer animationForKey:@"SpinAnimation"] == nil) {
    CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
    animation.fromValue = [NSNumber numberWithFloat:0.0f];
    animation.toValue = [NSNumber numberWithFloat: 2 * M_PI];
    animation.duration = 10.0f;
    animation.repeatCount = INFINITY;
    animation.removedOnCompletion = NO;
    [circleLayer addAnimation:animation forKey:@"SpinAnimation"];
}

[self.view.layer addSublayer:circleLayer];

Ответ 1

tl; dr: в вашем слое формы отсутствует фрейм (возможно, ограничивающий прямоугольник его пути).


Путаница возникает из-за того, что вращающийся слой не имеет рамки. Это означает, что его размер равен 0⨉0. Это в сочетании с тем, что слой формы позволяет рисовать фигуру за пределами ее границ, делает ее похожей на то, что вращение происходит вокруг внешней точки. Но это не так.

Проблема

Без каких-либо изменений в точку привязки, преобразование происходит относительно центра слоя собственных границ. Для слоя без размера центр совпадает с началом ((x+width/2, y+height/2) совпадает с (x, y), когда оба width и height равны 0).

Локальное происхождение (относительно границ слоя) также находится там, где путь обращается относительно. Точка (0, 0) для пути находится в начале слоя формы.

Если бы мы отображали центр (и в этом случае источник) слоя, это было бы так.

enter image description here

Это также точка, в которой форма вращается вокруг.

enter image description here

Решение...

По сути, это два способа решения этой проблемы, заставляя ее вращаться вокруг центра круга. Один из них - изменить путь так, чтобы центр окружности находился в (0,0), в начале координат. Другое решение, которое я обычно предпочитаю, - это дать размеру слоя, который соответствует размеру его пути, ограничивающий прямоугольник:

circleLayer.bounds = CGPathGetBoundingBox(circle.CGPath);

Здесь я показываю слой с очень светло-серым цветом фона:

введите описание изображения здесь

Мне иногда кажется полезным придать слою формы фоновый цвет во время разработки в качестве инструмента отладки, чтобы я мог видеть, что его кадр соответствует моим ожиданиям.

Обратите внимание, что при изменении границ слоя или вида он изменяется относительно его положения. Это означает, что центральная точка остается прежней, а начало координат перемещается, что означает, что путь будет эффективно перемещаться.

Теперь, когда слой имеет размер, а центр границ совпадает с центром круга, он будет выглядеть так, как бы круг вращается вокруг него, когда вы вращаете слой формы.

введите описание изображения здесь

Когда вы видите, что все работает, вы можете снова удалить цвет фона.

Ответ 2

Это работает правильно. Просто включите кадр для вашего слоя:

circleLayer.borderWidth = 1;
circleLayer.borderColor = [UIColor redColor].CGColor;

И вы видите, что рамка поворачивается вправо. Также лучше использовать byValue здесь:

CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
animation.byValue = @(2 * M_PI);
animation.duration = 10.0f;
animation.repeatCount = INFINITY;
animation.removedOnCompletion = NO;
[circleLayer addAnimation:animation forKey:@"SpinAnimation"];

Итак, ваша проблема - это геометрия формы.