Подтвердить что ты не робот

Анимация круговой UIBezierPath

У меня есть проект, в котором я анимация UIBezierPath на основе достигнутого прогресса. BezierPath находится в форме круга и находится в UIView, и анимация выполняется в drawRect с помощью CADisplayLink прямо сейчас. Проще говоря, на основе достигнутого прогресса x путь должен радиально расширяться (если x больше, чем раньше) или сжиматься (если x меньше).

self.drawProgress = (self.displayLink.timestamp - self.startTime)/DURATION;

CGFloat startAngle = -(float)M_PI_2;
CGFloat stopAngle = ((self.x * 2*(float)M_PI) + startAngle);
CGFloat currentEndAngle = ((self.oldX * 2*(float)M_PI) + startAngle);
CGFloat endAngle = currentEndAngle-((currentEndAngle-stopAngle)*drawProgress);

UIBezierPath *guideCirclePath = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];

Это относится к сокращению x с момента последнего обновления. Проблемы, которые я испытываю, на самом деле несколько:

  • Форма всегда начинает рисовать на 45º (если только я не поворачиваю представление). Я не нашел способа изменить это, и установка startAngle -45º не имеет никакого значения, потому что он всегда "всплывает" до 45. Есть ли что-нибудь, что я могу сделать по этому поводу, или мне нужно прибегать к другим методам чертежа?
  • Есть ли другой способ, который нужно оживить? Я много читал об использовании CAShapeLayer, но я не совсем понял фактическую разницу (с точки зрения недостатков и преимуществ) при использовании этих двух методов. Если бы кто-нибудь мог прояснить, я был бы очень обязан!

UPDATE: Я перевел код на CAShapeLayer, но теперь у меня другая проблема. Это лучше всего описывается с этим изображением:

enter image description here

Что происходит, когда слой должен сжиматься, тонкая внешняя линия все еще существует (независимо от направления движения). И когда стержень сжимается, дельта 1- x не удаляется, если я явно не сделаю над ней новую белую форму. Код для этого следует. Любые идеи?

UIBezierPath *circlePath = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startAngle endAngle:stopAngle clockwise:YES];
CAShapeLayer *circle = [CAShapeLayer layer];
circle.path = [circlePath CGPath];
circle.strokeStart = 0;
circle.strokeEnd = 1.0*self.progress;

// Colour and other customizations here.

if (self.progress > self.oldProgress) {
    drawAnimation.fromValue = @(1.0*self.oldProgress);
    drawAnimation.toValue = @(circle.strokeEnd);
} else { 
    drawAnimation.fromValue = @(1.0*self.oldProgress);
    drawAnimation.toValue = @(1.0*self.progress);
    circle.strokeEnd = 1.0*self.progress;
}

drawAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; //kCAMediaTimingFunctionEaseIn
[circle addAnimation:drawAnimation forKey:@"strokeEnd"];

ОБНОВЛЕНИЕ 2: Я убрал большинство других ошибок. Оказалось, что только я был довольно глупым все время и чрезмерно усложнял всю анимацию (не говоря уже о том, чтобы умножить на 1 везде, что?). Я сделал gif ошибки, которую я не могу решить:

radial control glitch

Любые идеи?

ОБНОВЛЕНИЕ 3: (и закрытие). Мне удалось избавиться от ошибки, вызвав

[self.layer.sublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];

И теперь все работает так, как должно. Спасибо за помощь!

4b9b3361

Ответ 1

Использование CAShapeLayer намного проще и чище. Причина в том, что CAShapeLayer включает в себя свойства strokeStart и strokeEnd. Эти значения варьируются от 0 (начало пути) до 1 (конец пути) и являются анимативными.

Изменяя их, вы можете легко нарисовать любую дугу своего круга (или любую часть произвольного пути, если на то пошло.) Свойства анимативны, поэтому вы можете создать анимацию растущего/сокращающегося кусочка пирога или раздела форму кольца. Это намного проще и эффективнее, чем реализация кода в drawRect.