2014-11-21 10 views
16

Ci sono molte domande simili su Stack Overflow sull'animazione di altezza UITableViewCell, ma non funziona per la nuova vista tabella di auto-layout iOS8. Il mio problema:Come animare l'altezza di UITableViewCell usando il layout automatico?

cella personalizzato:

@property (weak, nonatomic) IBOutlet iCarousel *carouselView; 
@property (weak, nonatomic) IBOutlet UIPageControl *pageControl; 
@property (weak, nonatomic) IBOutlet UIButton *seeAllButton; 
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *carouselHeightConstraint; 

Nota carouselHeightConstraint. Questo è un vincolo di altezza per la sottoview della vista del contenuto (l'unica sottoview).

L'altezza è impostata su 230.0f ad esempio. Al primo carico assomiglia: enter image description here

Poi, il Vedi tutti i azione che voglio espandere cellulare, il mio codice:

- (IBAction)seeAllButtonAction:(id)sender { 

    BOOL vertical = !self.carouselCell.carouselView.vertical; 
    self.carouselCell.carouselView.type = vertical ? iCarouselTypeCylinder : iCarouselTypeLinear; 
    self.carouselCell.carouselView.vertical = vertical; 

    [UIView transitionWithView:self.carouselCell.carouselView 
        duration:0.2 
        options:0 
        animations:^{ 

    self.carouselCell.carouselHeightConstraint.constant = vertical ? CGRectGetHeight(self.tableView.frame) : 230; 
    [self.carouselCell setNeedsUpdateConstraints]; 
    [self.carouselCell updateConstraintsIfNeeded]; 
    [self.tableView beginUpdates]; 
    [self.tableView endUpdates]; 

        completion:^(BOOL finished) { 
        }]; 
} 

Come potete vedere, cerco di utilizzare questo bene vecchia soluzione:
Can you animate a height change on a UITableViewCell when selected?

E il risultato:

enter image description here

La mia cella restringe-44.0f altezza.

Domanda:

Perché questo accade? Mi aspetto di vedere la mia cella espandersi senza problemi con la magia dell'auto-layot.

Nota:
ho Dont't desidera utilizzare -tableView:heightForRowAtIndexPath:. È l'era del layout automatico, giusto?

+0

È ancora necessario utilizzare 'tableView: heightForRowAtIndexPath:'. Questo non è un lavoro di layout automatico. – Astoria

+0

@Astoria, assomiglia molto al lavoro di impaginazione automatica. – orkenstein

+0

@orkenstein Sono assolutamente d'accordo che ora dovrebbe essere fatto con Auto-Layout. Sto provando a fare praticamente la stessa cosa: impostare i vincoli sul contenuto della cellaView e dire alla vista tabella di animare l'altezza. Tuttavia, non ho potuto farlo funzionare finora. Hai trovato una soluzione per questo problema? – Alex

risposta

38

Di seguito ha lavorato per me:

Preparazione:

  1. Sulla viewDidLoad dire la visualizzazione della tabella di utilizzare le cellule auto-dimensionamento:

    tableView.rowHeight = UITableViewAutomaticDimension; 
    tableView.estimatedRowHeight = 44; // Some average height of your cells 
    
  2. Aggiungi i vincoli come lo faresti normalmente, ma aggiungili al numero contentView della cella!

altezza Animate cambia:

Dire si cambia di constant un vincolo:

myConstraint.constant = newValue; 

... oppure aggiungere/rimuovere vincoli.

Per animare questo cambiamento, procedere come segue:

  1. Dite al contentView per animare il cambiamento:

    [UIView animateWithDuration: 0.3 animations: ^{ [cell.contentView layoutIfNeeded] }]; // Or self.contentView if you're doing this from your own cell subclass 
    
  2. poi dire la visualizzazione della tabella di reagire al cambiamento di altezza con un'animazione

    [tableView beginUpdates]; 
    [tableView endUpdates]; 
    

La durata di 0,3 sul primo passaggio è quella che sembra essere la durata che UITableView utilizza per le sue animazioni quando si chiama begin/endUpdates.

Bonus - altezza cambiamento senza animazione e senza ricaricare l'intera tabella:

Se si vuole fare la stessa cosa come sopra, ma senza un'animazione, quindi fare questo, invece:

[cell.contentView layoutIfNeeded]; 
[UIView setAnimationsEnabled: FALSE]; 
[tableView beginUpdates]; 
[tableView endUpdates]; 
[UIView setAnimationsEnabled: TRUE]; 

Sommario:

// Height changing code here: 
// ... 

if (animate) { 
    [UIView animateWithDuration: 0.3 animations: ^{ [cell.contentView layoutIfNeeded]; }]; 
    [tableView beginUpdates]; 
    [tableView endUpdates]; 
} 
else { 
    [cell.contentView layoutIfNeeded]; 
    [UIView setAnimationsEnabled: FALSE]; 
    [tableView beginUpdates]; 
    [tableView endUpdates]; 
    [UIView setAnimationsEnabled: TRUE]; 
} 

È possibile verificare la mia implementazione di una cella che si espande quando l'utente la seleziona. here (puro Swift & puro autolayout - davvero la via del futuro).

+0

Nella versione non animata: non chiamerebbe 'reloadRowsAtIndexPaths: withRowAnimation:' con 'UITableViewRowAnimationNone' nella vista tabella funziona? Invece di disabilitare le animazioni su 'UIView' e' beginUpdates'/'endUpdates'. –

+0

@ MichałCiuba Non ricordo esattamente di averlo provato, ma ricordo di aver pensato: "Sembra che' reloadRowsAtIndexPaths: withRowAnimation: 'non ricarichi le altezze delle celle. Suppongo che dovrò provare qualcos'altro" (potrebbe sono stato per animare l'altezza, però, non un aggiornamento istantaneo). – Alex

+1

Sì, intendevo: prima richiamare 'layoutIfNeeded' per aggiornare l'altezza della cella, quindi' reloadRowsAtIndexPaths: withRowAnimation: 'per aggiornare la vista tabella. –

1

Vorrei aggiungere alcuni punti alla risposta di Alex.

Se si chiama beginUpdates e endUpdates all'interno di cellForRowAtIndexPath o willDisplayCell, l'app si arresta in modo anomalo. Dopo aver animato l'aumento della cella, è possibile che rimanga invariata dopo averlo visualizzato su TableView. Potresti anche volere che il resto delle celle mantenga la loro altezza uguale. Ma ricorda che le celle sono riutilizzabili, quindi potresti ritrovarti con altre celle con altezza maggiore.

Come risultato, sarà necessario impostare la costante di vincolo all'interno di cellForRowAtIndexPath in base all'elemento che rappresenta. Ma se si chiama layoutIfNeeded in seguito, verrà visualizzato un avviso con i propri vincoli. La mia convinzione è che tenta di generare il layout della cella prima che venga calcolata la sua nuova altezza.

public func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 
... 
    myConstraint.constant = itemForCell.value == "x" ? 50 : 20 // stop right here 
    cell.layoutIfNeeded() <- don't do this or some of your constraints will break 
    beginUpdates() <-- if you do this your app will crash 
    endUpdates() <-- same here 
Problemi correlati