Вращающийся 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];
2 11

2 ответа:

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


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

Проблема

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

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

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

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

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

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

Ее решение...

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

Вот и я. отображение слоя с очень светлым серым фоном:

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

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

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

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

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

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

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"];
Итак, ваша проблема-это геометрия формы.