2010-09-12 9 views
13

Tengo un UIView con un montón de subvistas, todas posicionadas usando layoutSubviews. Cuando se cambia el tamaño del view, todas las posiciones relativas cambian. Me gustaría que estos recálculos ocurrieran durante un cambio de tamaño animado (usando + [UIView beginAnimations:] llamadas). Esto no parece estar sucediendo. ¿Algunas ideas?layoutSubviews durante una animación?

Respuesta

23

Supuesto: desea tener varios pasos de animación (es decir, la posición no cambia linealmente con el tamaño del fotograma).

Esto no es posible con una sola animación UIView "estándar". ¿Por qué? El marco/límites solo se establece una vez.

Core Animation tiene tres árboles "capa":

  • El árbol modelo es donde su aplicación piensa que las cosas son.
  • El árbol de presentación es aproximadamente lo que se muestra en la pantalla.
  • El árbol de representación es aproximadamente lo que Core Animation está componiendo.

UIView es una envoltura (algo delgada) alrededor de la capa del modelo. Durante una animación UIView, Core Animation actualiza el árbol de presentación/representación —, el árbol modelo representa el punto final de las animaciones. El resultado es que su código puede (en su mayor parte) tratar animaciones como — instantáneo moviendo una vista de A a B instantáneamente lo mueve a B; el cambio simplemente está animado para el usuario.

Hay cosas más complicadas que puedes hacer con CALayer/CAAnimation directamente, pero no he investigado tanto.

Puede encadenar múltiples animaciones utilizando - [UIView setAnimationDidStopSelector:]. (También podría intentar usar múltiples animaciones junto con setAnimationDelay :, pero no estoy seguro de lo que sucede con múltiples animaciones en la misma propiedad; puede tener suerte con setAnimationBeginsFromCurrentState :.)

Si desea un control realmente detallado , CADisplayLink (OS 3.1+) es un temporizador que se activa después de cada actualización de pantalla. Una opción alternativa (para soporte 3.0) es usar un NSTimer a 30/60 Hz más o menos.

+0

Gracias por la visión detallada de debajo de las sábanas. Si bien conocía periféricamente la jerarquía de los árboles, se formó una gran síntesis de por qué la arquitectura de Core Animation básicamente no permite lo que quiero hacer. –

4

Publicación para la integridad. Gracias a tc. para explicar que lo que quiero hacer, exactamente, no es compatible con Core Animation.

Finalmente se me ocurrió una solución razonable. En lugar de diseñar mis subvistas en -layoutSubviews, lo hago en -setBounds :. Luego, cuando envuelvo un -setBounds: invoco un bloque UIView + beginAnimations: esas llamadas de posicionamiento también son animadas, y el resultado final es que todo se anima adecuadamente hacia donde debería estar Dios.

+1

Oh ... Si ese es el caso, entonces leí mal lo que estaba diciendo. Pruebe 'view.frame = blah; [view layoutIfNeeded] ' –

+0

no, eso los moverá a su posición y luego animará los límites. Es lo que intenté inicialmente. –

+1

Estoy tratando de lograr algo similar, sin embargo, mi setBounds solo se llama una vez (con los límites finales), por lo que mis subvistas no se vuelven a alinear durante la animación. ¿Hay algo que extrañé? – alexleutgoeb

13

Sé que esta es una pregunta antigua, pero este código funciona muy bien para mí (adecuado para su ejemplo de cambio de fotograma).

-(void)layoutSubviews{ 
    [super layoutSubviews]; 
    // layout your subviews here, or whatever 
} 

-(void)someMethod{ 
    double duration=...; 
    [UIView animateWithDuration:duration animations:^{ 
     self.frame = ...; 
     [self layoutIfNeeded]; 
    }]; 
} 

Por supuesto que puede llamar a este método desde otro objeto. El "truco" es llamar layoutIfNeeded (o layoutSubviews directamente - lo mismo, si cambia el marco se llama a setNeedsLayout).

As tc.muy bien explicado los "árboles de capas", solo fuerza la capa de presentación para mostrar la etapa final de la capa del modelo con la animación.

La ventaja de este método es la posibilidad de controlar cuándo se modifica el marco/límites y cuándo es instantáneo.

Espero que esto ayude a alguien :).

+0

¡Esto fue muy útil! Nunca entendí esta parte de Core Animation hasta que leí tu respuesta. –

+0

@JohnWright: placer :) – JakubKnejzlik

+1

Puede que necesite llamar a setNeedsLayout antes del diseñoSi lo necesita. – Karmeye

11

Completando @ anwer de GrizzlyNetch, puede establecer la opción UIViewAnimationOptionLayoutSubviews animación, por lo que no es necesario llamar a layoutIfNeeded:

-(void)someMethod{ 
    double duration = ...; 
    [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionLayoutSubviews animations:^{ 
     self.frame = ...; 
    } completion:nil]; 
} 
Cuestiones relacionadas