2016-01-12 10 views
8

Come si possono inserire righe in un UITableView nella parte superiore senza che il resto delle celle venga spostato verso il basso - quindi la posizione di scorrimento non sembra cambiare affatto?Inserire le righe nella parte superiore di UITableView senza modificare la posizione di scorrimento quando si utilizza UITableViewAutomaticDimension

Proprio come Facebook e Twitter quando vengono inviati nuovi messaggi, questi vengono inseriti nella parte superiore ma la posizione di scorrimento rimane fissa.

La mia domanda è simile a questa this question. Ciò che rende unica la mia domanda da quella domanda è che non sto usando una tabella con altezze di riga fisse - Sto usando UITableViewAutomaticDimension e un estimatedRowHeight. Pertanto le risposte suggerite non funzioneranno perché non riesco a determinare l'altezza della riga.

Ho provato questa soluzione che non considera l'altezza della riga in considerazione, ma il contentSize non è ancora corretto dopo il ricaricamento, perché il set contentOffset non è la stessa posizione relativa - le celle sono ancora spinte verso il basso dove erano prima dell'inserto. Questo perché la cella non è stata renderizzata sullo schermo, quindi iOS non si preoccupa di calcolare l'altezza appropriata per esso fino a quando non sta per apparire, quindi contentSize non è preciso.

CGSize beforeContentSize = tableView.contentSize; 
[tableView reloadData]; 
CGSize afterContentSize = tableView.contentSize; 
CGPoint afterContentOffset = tableView.contentOffset; 
tableView.contentOffset = CGPointMake(afterContentOffset.x, afterContentOffset.y + afterContentSize.height - beforeContentSize.height); 

Alain indicate rectForCellAtIndexPath che costringe IOS per calcolare l'altezza adeguata. Ora posso determinare l'altezza corretta per le celle inserite, ma la vista di scorrimento contentSize non è ancora corretta, come si evince quando eseguo un'iterazione su tutte le celle e sommando le altezze che sono maggiori di contentSize.height. Alla fine, quando imposto manualmente lo contentOffset, non si sta scorrendo nella posizione corretta.

Codice originale:

//update data source 
[tableView beginUpdates]; 
[tableView insertRowsAtIndexPaths:newIndexPaths withRowAnimation:UITableViewRowAnimationAutomatic]; 
[tableView endUpdates]; 

In questo scenario, cosa si può fare per ottenere il comportamento desiderato?

+0

hai trovato una soluzione? –

+0

@AndreyGordeev No. Ho finito per non utilizzare più l'altezza stimata delle righe e invece di calcolare manualmente l'altezza necessaria per ogni riga. – Joey

+0

Come sei riuscito a gestire il problema ContentSize errato? – goldengil

risposta

0

Penso che la tua soluzione fosse quasi arrivata. Dovresti aver basato il nuovo offset Y sulla "prima" scostamento Y piuttosto che sul "dopo".

..., beforeContentOffset.y + afterContentSize.height - beforeContentSize.height

(si avrebbe bisogno di salvare il punto beforeContentOffset prima che i dati di ricarica però)

+0

Questo non ha funzionato. Lo spinge verso il basso ancora probabilmente a causa della complessità nel calcolare la dimensione del contenuto corretta quando si utilizzano altezze di riga dinamiche. – Joey

+0

Forse questo funzionerebbe meglio con il tuo codice originale. La mia sensazione è che dovresti trovare un evento che viene attivato dopo il rendering/i calcoli della cella per riposizionare l'offset come ad esempio DidEndDisplayingCell o su un timer .. –

+0

Ciò comporterebbe un flash . Se inserisco una cella, la inserirà immediatamente e riposizionerà le celle, quindi imposto l'offset del contenuto dopo un po 'di tempo per tornare al punto in cui si trovavano, sarà abbastanza evidente. – Joey

1

Incontra lo stesso problema e ancora non trovare un modo elegante per risolvere it.Here è il mio modo, supponiamo che io voglio inserire moreData.count cellule sopra la cella corrente.

// insert the new data to self.data 
for (NSInteger i = moreData.count-1; i >= 0; i--) { 
    [self.data insertObject:moreData[i] atIndex:0]; 
} 

//reload data or insert row at indexPaths 
[self.tableView reloadData]; 

//after 0.1s invoke scrollToRowAtIndexPath:atScrollPosition:animated: 
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 
    [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:moreData.count inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO]; 
}); 

Il vantaggio è fissato la posizione prima e dopo l'inserimento di nuovi dati.Lo svantaggio è che possiamo vedere lo schermo lampeggiare (la cella più in alto mostra e salire)

6

In ritardo per la festa ma funziona anche quando le celle hanno altezze dinamiche (ovvero UITableViewAutomaticDimension), non c'è bisogno di scorrere le celle per calcolare le loro dimensioni , ma funziona solo quando gli elementi vengono aggiunti, proprio all'inizio della tableView e non v'è nessuna intestazione, con un po 'di matematica è probabilmente possibile adattare questo per ogni situazione:

func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) { 
     if indexPath.row == 0 { 
      self.getMoreMessages() 
     } 
} 

private func getMoreMessages(){ 
     var initialOffset = self.tableView.contentOffset.y 
     self.tableView.reloadData() 
     //@numberOfCellsAdded: number of items added at top of the table 
     self.tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: numberOfCellsAdded, inSection: 0), atScrollPosition: .Top, animated: false) 
     self.tableView.contentOffset.y += initialOffset 
} 
+2

Questa è l'unica soluzione che potrebbe aiutarmi tra le tante che sono già là fuori! C'è tuttavia un problema: lo scorrimento inerziale viene immediatamente interrotto. C'è un modo per mantenere la velocità di scorrimento corrente? – Nickkk

+0

Non sono ancora riuscito a risolvere questo problema, se trovi una soluzione per favore fammelo sapere – Ezechiele

Problemi correlati