iOS: come si anima in base al nuovo vincolo di layout automatico (altezza)


123

Non ho mai lavorato prima con i vincoli del layout automatico . Ho una nuova piccola app su cui sto lavorando e ho notato che le visualizzazioni del NIB sono predefinite per il layout automatico. Quindi, ho pensato di cogliere l'occasione per lavorare con esso e cercare di capire dove Apple sta con questo.

Prima sfida:

Devo ridimensionare un MKMapView e vorrei animarlo nella nuova posizione. Se lo faccio nel modo in cui sono abituato a:

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

... quindi MKMapView tornerà alla sua altezza originale ogni volta che viene aggiornata una vista di pari livello (nel mio caso il titolo di un UISegmentedControl viene aggiornato [myUISegmentedControl setTitle:newTitle forSegmentAtIndex:0] ).

Quindi, quello che penso di voler fare è cambiare i vincoli di MKMapView dall'essere uguale all'altezza della vista genitore all'essere relativo alla parte superiore dell'UISegmentedControl che stava coprendo:V:[MKMapView]-(16)-[UISegmentedControl]

Quello che voglio è che l'altezza di MKMapView si accorci in modo che vengano rivelati alcuni controlli sotto la visualizzazione della mappa. Per fare ciò penso di aver bisogno di cambiare il vincolo da una vista a grandezza intera fissa a una in cui la parte inferiore è vincolata alla parte superiore di un UISegmentedControl ... e mi piacerebbe che si animasse quando la vista si restringe a una nuova dimensione.

Come si fa a farlo?

Modifica: questa animazione non si anima anche se la parte inferiore della vista si sposta verso l'alto di 170 istantaneamente:

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

    }];

ed nibMapViewConstraintè cablato in IB al vincolo di spazio verticale inferiore.


1
So che puoi facilmente modificare il valore della costante del vincolo in un blocco [UIView animateWithDuration ..] per animare il cambio di altezza. Devi creare un IBOutlet per quel vincolo e collegarlo al tuo xib, o altrimenti mantenere un riferimento ad esso se lo hai creato nel codice (o scorrere tutti i vincoli per cercarlo). Non sono sicuro di come animare le modifiche relatedBy, ma ho letto che dovresti cambiare solo i valori costanti e non altri di un vincolo (per altri valori, crea un nuovo vincolo).
yuf

Hmm. pensavo di poterlo fare, ma non sto animando. Cambia, con successo, ed è nel blocco di animazione, ma non si anima!?!
Meltemi

Ho trovato la mia risposta qui: < stackoverflow.com/questions/12926566/… >
Meltemi

1
Non dimenticare la [view layoutIfNeeded], anche questo era il mio problema ahah. Questa è la stessa domanda che ha risolto il mio problema.
yuf

Risposte:


179

Dopo aver aggiornato il tuo vincolo:

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

Sostituisci self.viewcon un riferimento alla vista contenitore.


4
funziona per la vista stessa, tuttavia le viste che hanno vincoli a quella vista si spostano immediatamente. Cosa faccio? ty
dietbacon

7
è necessario chiamare layout se necessario anche su quelle viste. tuttavia non funziona correttamente in quanto ciò animerà anche l'aggiornamento della vista. Come si anima la regolazione del vincolo solo nelle altre viste?
ngb

3
Attenzione: se si utilizza il UIViewAnimationOptionBeginFromCurrentStatelayout i vincoli verranno impostati PRIMA dell'animazione!
Robert

12
Invece di richiedere layoutIfNeededciascuna di queste visualizzazioni, chiama semplicemente[[self.view superview] layoutIfNeeded];
Flying_Banana

2
@ngb è necessario modificare la costante del vincolo all'interno del blocco di animazione. In questo modo il vincolo cambia con l'animazione e puoi continuare a usare UIViewAnimationOptionBeginFromCurrentState.
Eran Goldin

86

Questo funziona per me (sia iOS7 che iOS8 +). Fare clic sul vincolo di layout automatico che si desidera regolare (nel generatore di interfacce, ad esempio vincolo superiore). Quindi rendilo un IBOutlet;

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

Animare verso l'alto;

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

Torna alla posizione originale

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

2
WOW!! In realtà funziona davvero! Questa risposta mi ha aperto gli occhi. Grazie mille! - Erik
Erik van der Neut

2
@ErikvanderNeut era anche per me, contento che sia stato utile. D'ora in poi animerò i vincoli piuttosto che la posizione dei frame.
DevC

da non perdere per aggiungere: [containerView layoutIfNeeded]; Assicura che tutte le operazioni di layout in sospeso siano state completate PRIMA del blocco animateWithDuration.
ingconti

11

C'è un ottimo tutorial della stessa Apple che spiega come usare l'animazione con il layout automatico. Segui questo link e poi trova il video denominato "Layout automatico con esempio". Fornisce alcune cose interessanti sull'autolayout e l'ultima parte riguarda come usare l'animazione.



1

La maggior parte delle persone utilizza il layout automatico per disporre gli elementi nelle viste e modificare i vincoli del layout per creare animazioni.

Un modo semplice per farlo senza molto codice è creare la UIView che vuoi animare in Storyboard e quindi creare una UIView nascosta dove vuoi che la UIView finisca. Puoi usare l'anteprima in xcode per assicurarti che entrambe le viste UIV siano dove vuoi che siano. Successivamente, nascondi la UIView finale e scambia i vincoli di layout.

C'è un podfile per scambiare i vincoli di layout chiamato SBP se non vuoi scriverlo da solo.

Ecco un tutorial .


0

Non è necessario utilizzare più IBOutlet referencedel vincolo invece di questo è possibile direttamente accesso updategià applicato vincolo applicato da Programmaticallyo da Interface Builderqualsiasi vista utilizzando la KVConstraintExtensionsMasterlibreria. Questa libreria gestisce anche il Cumulativecomportamento di NSLayoutConstraint.

Per aggiungere un vincolo di altezza su containerView

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

Per aggiornare il vincolo di altezza di containerView con l'animazione

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

            /* for the animation */ 
            [self.containerView  updateModifyConstraintsWithAnimation:NULL];
      }
    }];
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.