2011-01-03 24 views
17

Vi algo de material en la web, pero todavía no puedo llegar a donde quiero. Necesito animar mi vista hacia abajo, haciendo que sea más grande.Cómo animar al redimensionar UIView

Aquí está mi código hasta ahora. Lo que está sucediendo aquí, es que en lugar de cambiar el tamaño de mi vista, solo está cambiando un poco su ubicación. Si cambio la propiedad en lugar de "bounds.size" para que sea "transform.scale.y", es un poco mejor, solo que esta vez expande la vista tanto hacia arriba como hacia abajo, no solo hacia abajo.

Otra cosa que no soy: ¿estas claves son solo propiedades de CALayer? donde puedo encontrar una lista de estas claves?

Realmente agradecería ayuda aquí. ¡Gracias!

int x = self.btnHead.frame.origin.x; 
int y = self.btnHead.frame.origin.y; 
int height = self.btnHead.frame.size.height; 
int width = self.btnHead.frame.size.width; 


CABasicAnimation *resizeAnimation = [CABasicAnimation animationWithKeyPath:@"bounds.size"]; 
[resizeAnimation setToValue:[NSValue valueWithCGSize:CGSizeMake(width,height+50)]]; 
resizeAnimation.fillMode = kCAFillModeForwards; 
resizeAnimation.removedOnCompletion = NO; 

CAAnimationGroup *animationGroup = [CAAnimationGroup animation]; 
animationGroup.animations = [NSArray arrayWithObjects:resizeAnimation,nil]; 
animationGroup.removedOnCompletion = NO; 
animationGroup.fillMode = kCAFillModeForwards; 
animationGroup.removedOnCompletion=NO; 
animationGroup.duration = 0.1; 

[self.btnHead.layer addAnimation:animationGroup forKey:@"animations"]; 

Editar: la publicación de mi primer código conforme a lo solicitado - Esto sólo cambiará el tamaño de mi punto de vista, pero no tendrá la animación, sin importar la duración entro.

int x = self.btnHead.frame.origin.x; 
    int y = self.btnHead.frame.origin.y; 
    int height = self.btnHead.frame.size.height; 
    int width = self.btnHead.frame.size.width; 


    [UIView beginAnimations:nil context:nil]; 
    [UIView setAnimationDuration:10]; 
    CGRect rect = CGRectMake(x,y,width ,height+BUTTON_HEIGH*2); 

    self.btnHead.frame = rect; 

    [UIView commitAnimations]; 

Respuesta

10
btnHead.clipsToBounds=YES 

Se ha solucionado el problema. No estoy seguro exactamente por qué.

+0

Supongo que la configuración 'btnHead.clipsToBounds = YES' fuerza efectivamente un redibujado como lo haría la configuración 'btnHead.contentMode = UIViewContentModeRedraw'. Sin embargo, no menciona nada sobre eso en la documentación. Esto probablemente ocurra porque es muy probable que al cambiar los 'límites 'de una vista con el recorte activado, se muestren partes de su jerarquía de vista que antes no eran visibles. Así es como funcionan las vistas de desplazamiento. –

9

No se puede simplemente cambiar el marco dentro de un bloque de animación UIView. Parece que CABasicAnimation no es necesario en este caso.

 
[UIView beginAnimations:@"resize_animation" context:NULL]; 
// set your duration. a long duration is better to debug 
// 0.1 is really short to understand what is going wrong 
[UIView setAnimationDuration:2]; 

btnHead.frame = newFrame; 

[UIView commitAnimations]; 
+0

¿No te encanta la simplicidad? – Jake

+0

¡No! Intenté eso primero. no funciona cambia el tamaño del marco, pero no se anima. – Idan

+0

Por favor, publique el código. Puede haber algún otro problema. – taskinoor

53

Animación de la propiedad frame puede ser problemático, pero debería funcionar correctamente, siempre que el transform es la identidad (es decir, que no ha cambiado). Acabo de probar el siguiente código, y funcionó como se esperaba:

[UIView animateWithDuration:.1f animations:^{ 
    CGRect theFrame = myView.frame; 
    theFrame.size.height += 50.f; 
    myView.frame = theFrame; 
}]; 

Una vez más, esto no funcionará como se espera si ha cambiado la propiedad transform en cualquier momento. Para una versión más a prueba de balas de esta animación, debe animar la propiedad bounds como lo intentó con Core Animation. Sin embargo, todavía no necesita ingresar a Core Animation.

Lo importante a entender aquí es la relación entre las propiedades bounds y center. Todas las transformaciones afines (traducir, escalar o rotar) necesitan un punto de referencia sobre el cual realizar la transformación. En el caso de un UIView que es el punto center. CALayer le permite mover el punto de referencia a través de la propiedad anchorPoint, pero no tenemos que preocuparnos por eso en este caso.

La razón por la que la vista se escala en ambas direcciones es que la operación de escalado ocurre alrededor del center. Lo más fácil para entonces es mover el centery por la mitad del delta de altura. De esta manera:

myView.contentMode = UIViewContentModeRedraw; 
[UIView animateWithDuration:.4f animations:^{ 
    CGRect theBounds = myView.bounds; 
    CGPoint theCenter = myView.center; 
    theBounds.size.height += 50.f; 
    theCenter.y += 25.f; 
    myView.bounds = theBounds; 
    myView.center = theCenter; 
}]; 

La consideración final está forzando la vista para volver a dibujar cuando los cambios bounds. Por motivos de rendimiento, la vista no se volverá a dibujar cuando cambie su bounds. Sin embargo, se vuelve a dibujar cuando se cambia la propiedad frame (otra característica más de la propiedad frame). Para forzar un rediseño en el cambio bounds, debe configurar el contentMode como lo hice en la primera línea del fragmento anterior. Es probable que desee volver a configurarlo una vez que finalice la animación, pero eso depende de usted. Esta es también la razón por la cual su versión Core Animation solo cambia la ubicación y no el tamaño.Necesita esta línea en su código en alguna parte antes de ejecutar la animación:

self.btnHead.layer.needsDisplayOnBoundsChange = YES; 

Espero que todo esto tenga sentido. Las propiedades frame, bounds y center pueden ser un poco confusas al principio.

+0

Primero, gracias por la excelente respuesta. Ahora, para sus puntos, ¿por qué no necesita cambiar el punto central cuando cambia el marco, mientras que sí lo necesita cuando cambia los límites? De todos modos, resultó que comenzó a animarse después de poner btnHead.clipsToBounds = SÍ ... No estoy seguro de por qué. – Idan

+4

El 'frame' es una propiedad de conveniencia (allí para facilitar el trazado de vistas) que describe el rectángulo de la vista en el espacio de coordenadas de sus padres. El valor 'frame' nunca se almacena. Se calcula a partir de 'bounds' y' center'. Entonces, cuando cambias el 'frame', en realidad estás cambiando los' bounds' y 'center'. Los 'bounds' describen el rectángulo delimitador de la vista en su propio espacio de coordenadas (por eso su origen es usualmente {0, 0}), y el' center' describe la posición de la vista en el espacio de coordenadas de sus padres. Entonces, los dos ejemplos de código realmente hacen exactamente lo mismo. –

+0

Hola, ¿Eso significa que, por lo general, no debo tocar los límites.origin, sino solo los límites. Tamaño y centro cuando quiero cambiar su posición en la pantalla (es (x, y))? Creo que cambiar el marco es mucho más fácil de todos modos. – Idan

2

clipsToBounds es la solución.

Explicación: ClipToBounds es una propiedad que especifica si subvistas deben ser recortadas o no. Por lo tanto, si una subvista es más grande que su supervista, se recortará si establece "superview.clipToBounds=YES". En el caso de esta publicación, la supervista se redimensionó, pero no hubo una diferencia visible para el usuario, ya que se crearon subvistas aunque estuvieran fuera del marco.

Es un poco complicado, porque no hay un vínculo visible con la animación, pero es por eso que esta propiedad hace la diferencia.