2013-06-17 11 views
36

Ho una sottoclasse UIView che disegna un cerchio il cui raggio cambia (con belle animazioni rimbalzanti). La vista sta decidendo la dimensione del cerchio.Animate intrinsicContentSize changes

Voglio che questa sottoclasse UIView cambi le dimensioni del frame in modo che corrisponda alle modifiche animate al raggio del cerchio e voglio che queste modifiche modifichino qualsiasi NSLayoutConstraints connesso alla vista (in modo che le viste siano vincolate al bordo del cerchio si muoverà mentre il cerchio si ridimensiona).

Capisco che l'implementazione di -(CGSize)intrinsicContentSize e la chiamata di invalidateIntrinsicContentSize quando le modifiche del raggio informeranno i vincoli da aggiornare, ma non riesco a capire come animare le modifiche a intrinsicContentSize.

Chiamare invalidateIntrinsicContentSize dall'interno di un blocco [UIView animateWith ... aggiorna immediatamente il layout.

È persino possibile, ed esiste un approccio alternativo/migliore?

+0

Ho la sensazione che questo non sia possibile. Prendiamo l'esempio di 'UILabel' il suo' intrinsicContentSize' è una funzione della sua dimensione del carattere. Tuttavia non c'è un modo carino per animare un cambio di font. La soluzione alternativa per l'etichetta è di animare il cambio di trasformazione del suo livello (usando un 'CAAnimation') e quindi di cambiare il carattere dopo che l'animazione è stata completata - Non è bello. – Robert

risposta

44

invalidateIntrinsicContentSize funziona bene con animazioni e layoutIfNeeded. L'unica cosa che devi considerare è che la modifica della dimensione intrinseca del contenuto invalida il layout della superview. Quindi dovrebbe funzionare:

[UIView animateWithDuration:0.2 animations:^{ 
    [self invalidateIntrinsicContentSize]; 
    [self.superview setNeedsLayout]; 
    [self.superview layoutIfNeeded]; 
}]; 
+2

Si prega di contrassegnare come risposta. – rplankenhorn

+0

Non funziona per me. – Ash

+9

Ok, funziona se aggiungi la riga [self.superview setNeedsLayout] nel mezzo – Ash

3

Il vincolo di larghezza/altezza non aiuta? Tenere di riferimento di questo vincolo e ...

[NSLayoutConstraint constraintWithItem:view 
          attribute:NSLayoutAttributeWidth 
          relatedBy:NSLayoutRelationEqual 
           toItem:nil 
          attribute:NSLayoutAttributeNotAnAttribute 
          multiplier:1 
           constant:myViewInitialWidth]; 

... quando si vuole animare myView ridimensionamento, fare questo ...

self.viewWidthConstraint.constant = 100; // new width 
[UIView animateWithDuration:0.3 animations:^{ [view layoutIfNeeded]; }]; 

... fare la stessa cosa per l'altezza .

A seconda degli altri tuoi vincoli, forse sarai costretto ad aumentare la priorità di questi due vincoli.

Oppure è possibile sottoclasse UIView, aggiungere - (void)invalidateIntrinsicContentSize:(BOOL)animated e simulare da soli. Ottieni nuove dimensioni da - (CGSize)intrinsicContentSize e animale animando i vincoli di larghezza/altezza. Oppure aggiungi la proprietà per abilitare/disabilitare le animazioni e sovrascrivere invalidateIntrinsicContentSize e farlo all'interno di questo metodo. Molti modi ...

1

Nel codice seguente, la classe intrinseca è la classe che ha appena cambiato le sue dimensioni modificando una variabile. Per animare la classe intrinseca usa solo il codice qui sotto. Se influenza altri oggetti più in alto nella gerarchia della vista, allora sostituisci la classe self.intrinsic con la vista di livello superiore per setNeedsLayout e layoutIfNeeded.

[UIView animateWithDuration:.2 animations:^{ 
     self.intrinsicClass.numberOfWeeks=8; 
     [self.intrinsicClass setNeedsLayout]; 
     [self.intrinsicClass layoutIfNeeded]; 
    }]; 
1

Nessuno di questi ha funzionato per me. Ho un UILabel che sto impostando con NSAttributedString. Il testo è multilinea e avvolge i confini delle parole. Pertanto l'altezza è variabile. Ho provato questo:

[UIView animateWithDuration:1.0f animations:^{ 
    self.label = newLabelText; 
    [self.label invalidateIntrinsicContentSize]; 
    [self.view setNeedsLayout]; 
    [self.view layoutIfNeeded]; 
}]; 

E un certo numero di variazioni. Nessuno funziona. L'etichetta cambia immediatamente la sua dimensione e poi scivola nella sua nuova posizione. Quindi l'animazione della schermata delle posizioni delle etichette sta funzionando. Ma l'animazione del cambiamento delle dimensioni dell'etichetta non lo è.

1

Swift versione di risposta di @ stigi che ha funzionato per me:

UIView.animate(withDuration: 0.2, animations: { 
    self.invalidateIntrinsicContentSize() 
    self.superview?.setNeedsLayout() 
    self.superview?.layoutIfNeeded() 
}) 
0

Bene per Swift 4/3 questo funziona e credo che questo è delle migliori pratiche. Se si dispone di un UIView con un UILabel in esso e l'UIView adatta di telaio dal UILabel, usare questo:

self.theUILabel.text = "text update" 
UIView.animate(withDuration: 5.0, animations: { 
    self.theUIView.layoutIfNeeded() 
}) 

Il self.view.layoutIfNeeded normale() funzionerà la maggior parte del tempo pure.