ios objective-c core-animation uibezierpath cadisplaylink

ios - Animando una UIBezierPath circular



objective-c core-animation (1)

Tengo un proyecto en el que estoy animando un UIBezierPath basado en un progreso establecido. El BezierPath tiene la forma de un círculo y se encuentra en una vista UIV y la animación se realiza en drawRect usando CADisplayLink ahora mismo. En pocas palabras, en función de un progreso establecido x el camino debe extenderse radialmente (si x es más grande que antes) o reducir (si x es más pequeño).

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];

Esto es en el caso de la reducción de x desde nuestra última actualización. Los problemas que estoy experimentando son en realidad algunos:

  1. La forma siempre comienza a dibujarse a 45º (a menos que yo gire la vista). No he encontrado ninguna forma de cambiar esto, y establecer startAngle en -45º realmente no hace ninguna diferencia porque siempre aparece "45". ¿Hay algo que pueda hacer al respecto o debo recurrir a otros métodos de dibujo? ?
  2. ¿Hay alguna otra manera de animar estas cosas? He leído mucho sobre el uso de CAShapeLayer pero no he entendido bien la diferencia real (en términos de inconvenientes y beneficios) en el uso de estos dos métodos. ¡Si alguien pudiera aclarar estaría muy agradecido!

ACTUALIZACIÓN: migré el código a CAShapeLayer en su lugar, pero ahora estoy enfrentando un problema diferente. Se describe mejor con esta imagen:

Lo que está sucediendo es que cuando se supone que la capa se encoge, la delgada línea externa aún está allí (independientemente de la dirección del movimiento). Y cuando la barra se contrae, el delta de 1- x no se elimina a menos que explícitamente haga una nueva forma blanca sobre ella. El código para esto sigue. ¿Algunas ideas?

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"];

ACTUALIZACIÓN 2: He solucionado la mayoría de los otros errores. Resultó que era solo que yo era bastante tonto todo el tiempo y complicaba demasiado toda la animación (sin mencionar que se multiplicaba por 1 en todas partes, ¿qué?). He hecho un gif del error que no puedo resolver:

¿Algunas ideas?

ACTUALIZACIÓN 3: (y cierre). Me las arreglé para deshacerme del error llamando

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

Y ahora todo funciona como debería. ¡Gracias por toda la ayuda!


Usar CAShapeLayer es mucho más fácil y limpio. La razón es que CAShapeLayer incluye las propiedades strokeStart y strokeEnd. Estos valores van desde 0 (el comienzo de la ruta) a 1 (el final de la ruta) y son animables.

Al cambiarlos, puede dibujar fácilmente cualquier arco de su círculo (o cualquier parte de un camino arbitrario, en realidad). Las propiedades son animables, por lo que puede crear una animación de una porción de corte circular o sección de una forma de anillo. . Es mucho más fácil y más eficaz que implementar código en drawRect.