core animation - CABasicAnimation with CALayer ruta no se anima
core-animation uibezierpath (3)
Encontré una solución realmente elegante de Andrew Wagner here .
Esencialmente, el sistema manejará todas las animaciones de cambio de ruta, todo lo que necesita es:
- Implementar una subclase CAShapeLayer
- Anular e implementar
actionForKey
- Actualiza la ruta como de costumbre y obtendrás tus animaciones!
Estoy tratando de animar la transición de un CALayer de esquinas normales a esquinas redondeadas. Solo quiero redondear las esquinas superiores, así que estoy usando un UIBezierPath. Aquí está el código:
UIRectCorner corners = UIRectCornerTopLeft | UIRectCornerTopRight;
UIBezierPath* newPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:corners cornerRadii:CGSizeMake(8.0f, 8.0f)];
UIBezierPath* oldPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:corners cornerRadii:CGSizeMake(0.0f, 0.0f)];
CAShapeLayer* layer = [CAShapeLayer layer];
layer.frame = self.bounds;
layer.path = oldPath.CGPath;
self.layer.mask = layer;
CABasicAnimation* a = [CABasicAnimation animationWithKeyPath:@"path"];
[a setDuration:0.4f];
[a setFromValue:(id)layer.path];
[a setToValue:(id)newPath.CGPath];
layer.path = newPath.CGPath;
[layer addAnimation:a forKey:@"path"];
Pero cuando ejecuto esto, las esquinas se redondean, pero no hay animación, sucede al instante. He visto algunas preguntas similares aquí en SO, pero no resolvieron mi problema.
Animar la propiedad shadowPath de CALayer
Estoy seguro de que solo estoy haciendo una pequeña cosa mal que está causando el problema, pero por mi vida no puedo resolverlo.
Solución:
- (void)roundCornersAnimated:(BOOL)animated {
UIRectCorner corners = UIRectCornerTopLeft | UIRectCornerTopRight;
UIBezierPath* newPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:corners cornerRadii:CGSizeMake(8.0f, 8.0f)];
UIBezierPath* oldPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:corners cornerRadii:CGSizeMake(0.0001f, 0.0001f)];
CAShapeLayer* layer = [CAShapeLayer layer];
layer.frame = self.bounds;
self.layer.mask = layer;
if(animated) {
CABasicAnimation* a = [CABasicAnimation animationWithKeyPath:@"path"];
[a setDuration:0.4f];
[a setFromValue:(id)oldPath.CGPath];
[a setToValue:(id)newPath.CGPath];
layer.path = newPath.CGPath;
[layer addAnimation:a forKey:@"path"];
} else {
layer.path = newPath.CGPath;
}
}
Realmente todo lo que tenía que hacer era establecer un valor "de" adecuado para la animación.
Intenta poner:
layer.path = newPath.CGPath;
después:
[layer addAnimation:a forKey:@"path"];
Me parece que estás creando una capa de forma que no tiene una ruta, y luego intentas animarla agregándole una ruta. Las capas de forma son un caso especial, y no funcionan de esa manera.
Debe tener una ruta en la capa de forma antes y después de la animación, y la ruta debe tener el mismo número de puntos antes y después.
Necesitaría crear una ruta de rectángulo redondeada con un radio de esquina de 0 (manualmente, usando una serie de arcos de esquinas y lados), y luego construir una nueva ruta con radios distintos de cero para las esquinas que desea redondear e instalar esa ruta como tu animacion
Sin embargo, incluso eso podría no funcionar, ya que la ruta debe tener exactamente el mismo número de puntos, y sospecho que los arcos se simplificarán a los puntos cuando el radio sea cero.
Acabo de encontrar una llamada UIBezierPath que creará un rectángulo donde puede seleccionar qué esquinas redondear. La llamada es bezierPathWithRoundedRect: byRoundingCorners: cornerRadii:
Eso creará un rectángulo con tantas esquinas redondeadas como quieras. Sin embargo, no estoy seguro de si funcionará para la animación de ruta. Es posible que deba solicitar que todas las esquinas estén redondeadas con las 2 esquinas no redondeadas configuradas en cero radio. De esa manera, PUEDE obtener una ruta con el mismo número de puntos que una ruta de rectángulo redondeado para que la animación de la ruta funcione correctamente. Tendrás que probarlo.