iOS: ¿Cómo se anima a una nueva restricción de auto-distribución (altura)

123

Nunca he trabajado con restricciones de autolayout antes. Tengo una nueva aplicación pequeña en la que estoy trabajando y noté que las vistas de la NIB están predeterminadas para la distribución automática. Entonces, pensé que aprovecharía la oportunidad para trabajar con él e intentar averiguar a dónde va Apple con esto.

Primer desafío:

Necesito cambiar el tamaño de un MKMapView y me gustaría animarlo a la nueva posición. Si hago esto como estoy acostumbrado:

[UIView animateWithDuration:1.2f
     animations:^{
         CGRect theFrame = worldView.frame;
         CGRect newFrame = CGRectMake(theFrame.origin.x, theFrame.origin.y, theFrame.size.width, theFrame.size.height - 170);
         worldView.frame = newFrame;
}];

... entonces el MKMapView se 'ajustará' a su altura original cada vez que se actualice una vista de hermanos (en mi caso, se está actualizando el título de un UISegmentedControl [myUISegmentedControl setTitle:newTitle forSegmentAtIndex:0]).

Entonces, lo que creo que quiero hacer es cambiar las restricciones de MKMapView de ser igual a la altura de la vista principal a ser relativa a la parte superior del control UISegmentedControl que estaba cubriendo:V:[MKMapView]-(16)-[UISegmentedControl]

Lo que quiero es que la altura de MKMapView se acorte para que se revelen algunos controles debajo de la vista del mapa. Para hacerlo, creo que necesito cambiar la restricción de una vista fija de tamaño completo a una donde la parte inferior esté restringida a la parte superior de un UISegmentedControl ... y me gustaría animarla a medida que la vista se reduce a un nuevo tamaño.

¿Cómo se hace esto?

Editar - esta animación es no animando a pesar de la parte inferior de la vista se mueve hasta 170 al instante:

    [UIView animateWithDuration:1.2f
         animations:^{
             self.nibMapViewConstraint.constant = -170;

    }];

y nibMapViewConstraintestá conectado en IB a la restricción de espacio vertical inferior.

Meltemi
fuente
1
Sé que puede cambiar fácilmente el valor constante de la restricción en un bloque [UIView animateWithDuration ..] para animar el cambio de altura. Debe crear un IBOutlet para esa restricción y conectarlo a su xib, o mantener una referencia si lo creó en código (o recorrer todas las restricciones para buscarlo). No estoy seguro de cómo animar los cambios relacionados, pero he leído que solo debe cambiar los valores constantes y no otros de una restricción (para otros valores, cree una nueva restricción).
yuf
Hmm pensé que podía pero no estoy animando. Cambia con éxito y está en el bloque de animación, ¡pero no está animando!
Meltemi el
Encontré mi respuesta aquí: < stackoverflow.com/questions/12926566/… >
Meltemi
1
No olvides el [view layoutIfNeeded], ese fue mi problema también jaja. Esa es la misma pregunta que resolvió mi problema.
yuf
Posible duplicado de ¿Cómo puedo animar cambios de restricción?
Senseful

Respuestas:

179

Después de actualizar su restricción:

[UIView animateWithDuration:0.5 animations:^{[self.view layoutIfNeeded];}];

Reemplace self.viewcon una referencia a la vista que lo contiene.

Ed McManus
fuente
44
eso funciona para la vista en sí, sin embargo, las vistas que tienen restricciones para esa vista simplemente se mueven instantáneamente. ¿Qué debo hacer? ty
dietbacon
77
necesita llamar al diseño si es necesario en esas vistas también. sin embargo, realmente no funciona correctamente, ya que esto animará la actualización de la vista también. ¿Cómo se anima el ajuste de restricción solo en las otras vistas?
ngb
3
Cuidado: si usa el UIViewAnimationOptionBeginFromCurrentStatediseño, las restricciones se establecerán ANTES de la animación.
Robert
12
En lugar de llamar layoutIfNeededa cada uno de esos puntos de vista, sólo tiene que llamar[[self.view superview] layoutIfNeeded];
Flying_Banana
2
@ngb necesita cambiar la constante de restricción dentro del bloque de animación. De esa manera, la restricción cambia con la animación y puede seguir usándola UIViewAnimationOptionBeginFromCurrentState.
Eran Goldin el
86

Esto funciona para mí (tanto iOS7 como iOS8 +). Haga clic en la restricción de diseño automático que desea ajustar (en el generador de interfaces, por ejemplo, la restricción superior). Luego haga de esto un IBOutlet;

@property (strong, nonatomic) IBOutlet NSLayoutConstraint *topConstraint;

Animar hacia arriba;

    self.topConstraint.constant = -100;    
    [self.viewToAnimate setNeedsUpdateConstraints]; 
    [UIView animateWithDuration:1.5 animations:^{
        [self.viewToAnimate layoutIfNeeded]; 
    }];

Animar de vuelta al lugar original

    self.topConstraint.constant = 0;    
    [self.viewToAnimate setNeedsUpdateConstraints];  
    [UIView animateWithDuration:1.5 animations:^{
        [self.viewToAnimate layoutIfNeeded];
    }];
DevC
fuente
2
¡¡GUAU!! ¡Esto realmente realmente funciona! Esta respuesta fue una revelación para mí. ¡Muchas gracias! - Erik
Erik van der Neut
2
@ErikvanderNeut también fue para mí, me alegro de que haya sido útil. Voy a animar las restricciones de ahora en adelante en lugar de la posición de los cuadros.
DevC
no te pierdas de agregar: [containerView layoutIfNeeded]; Asegura que todas las operaciones de diseño pendientes se hayan completado ANTES del bloque animateWithDuration.
ingconti
11

Hay un muy buen tutorial de Apple que explica cómo usar la animación con autolayout. Siga este enlace y luego encuentre el video llamado "Diseño automático por ejemplo". Ofrece algunas cosas interesantes sobre la distribución automática y la última parte trata sobre cómo usar la animación.

Glenn
fuente
1

La mayoría de las personas usa la distribución automática para diseñar elementos en sus vistas y modificar las restricciones de diseño para crear animaciones.

Una manera fácil de hacer esto sin mucho código es crear la UIView que desea animar en Storyboard y luego crear una UIView oculta donde desea que termine la UIView. Puede usar la vista previa en xcode para asegurarse de que ambas UIViews estén donde desea que estén. Después de eso, oculte la UIView final e intercambie las restricciones de diseño.

Hay un archivo de pod para intercambiar restricciones de diseño llamado SBP si no desea escribirlo usted mismo.

Aquí hay un tutorial .

Arjay Waran
fuente
0

No es necesario usar más IBOutlet referencede la restricción en lugar de esto, puede aplicar la restricción directamente accesso updateya sea aplicada por Programmaticallyo desde Interface Buildercualquier vista usando la KVConstraintExtensionsMasterbiblioteca. Esta biblioteca también gestiona el Cumulativecomportamiento deNSLayoutConstraint .

Para agregar restricción de altura en containerView

 CGFloat height = 200;
 [self.containerView applyHeightConstrain:height];

Para actualizar la restricción de altura de containerView con animación

[self.containerView accessAppliedConstraintByAttribute:NSLayoutAttributeHeight completion:^(NSLayoutConstraint *expectedConstraint){
        if (expectedConstraint) {
            expectedConstraint.constant = 100;

            /* for the animation */ 
            [self.containerView  updateModifyConstraintsWithAnimation:NULL];
      }
    }];
keshav vishwkarma
fuente