2009-08-30 3 views
14

Ho alcune UITableViewCells che devono cambiare la loro altezza in base alla lunghezza delle stringhe all'interno. Sto calcolando l'altezza necessaria all'interno di tableView:cellForRowAtIndexPath:, quindi la memorizzo in una variabile (self.specialRowHeight). Poi ho:Ottieni tableView: heightForRowAtIndexPath: si verifica dopo tableView: cellForRowAtIndexPath :?

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 
    if (indexPath.section == SPECIAL_SECTION) { 
     return self.specialRowHeight; 
    } 
    else { 
     return 44; 
    } 
} 

Solo che sembra essere sempre chiamato prima il bit tableView:cellForRowAtIndexPath:, quindi è sempre zero.

C'è un modo per aggirare questo, o forse un modo diverso di farlo?

Grazie!

risposta

11

Andando rispondere alla mia domanda qui:

Originariamente ero abbastanza sicuro che i calcoli di altezza erano legate al metodo tableView:cellForRowAtIndexPath:, e non potevano essere spostati altrove. Con un po 'di ristrutturazione, però, sono stato in grado di ottenere quella roba da lì e in tableView:heightForRowAtIndexPath:, che risolve tutto.

Per chiunque altro che sta cercando di ottenere cellule auto-regolati in altezza per lavorare, ecco qualche codice che potrebbe aiutare:

// Inside tableView:cellForRowAtIndexPath: 
cell.textLabel.lineBreakMode = UILineBreakModeWordWrap; 
cell.textLabel.numberOfLines = self.numberOfTextRows; 
// numberOfTextRows is an integer, declared in the class 

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 

    CGSize theSize = [theObject.theStringToDisplay sizeWithFont:[UIFont systemFontOfSize:18.0f] constrainedToSize:CGSizeMake(265.0f, 9999.0f) lineBreakMode:UILineBreakModeWordWrap]; 
    // This gets the size of the rectangle needed to draw a multi-line string 
    self.numberOfTextRows = round(theSize.height/18); 
    // 18 is the size of the font used in the text label 
    // This will give us the number of lines in the multi-line string 

    if ((indexPath.section == FIXED_HEIGHT_SECTION) || (self.numberOfTextRows < 2)) { 
     return 44; 
     // 44 is the default row height; use it for empty or one-line cells (or in other table sections) 
    } else { 
     return theSize.height + 16; 
     // 16 seems to provide a decent space above/below; tweak to taste 
    } 
} 

Se si può pensare a un modo più preciso per calcolare l'altezza della cella corretta, Sono tutto orecchie. :)

+0

Io non sono davvero sicuro perché devi dividere l'altezza del retto per 18 e poi moltiplicarlo di nuovo, ma a parte questo lo faccio più o meno allo stesso modo. –

+0

Bene, la prima divisione è scoprire quante righe sono necessarie, quindi posso impostare 'cell.textLabel.numberOfLines' correttamente; se non lo imposto, viene stampato su un'unica riga. Ma sì, credo che potrei usare 'theSize.height' nell'ultimo bit lì, invece di' self.numberOfTextRows'. – Triz

+0

Modificato la risposta per chiarezza e semplificazione. Funziona davvero bene ora. – Triz

0

Si potrebbe semplicemente impostare self.numberOfLines su 0 una volta e funzionerebbe allo stesso modo. (Se NumberOfLines è impostato a 0, allora l'etichetta usa tante righe quanti sono necessari.)

+0

Um ... numberOfTextRows è una proprietà di classe personalizzata, quindi non farà nulla di diverso da quello che dico. Stai pensando a cell.textLabel.numberOfLines? – Triz

+0

In ogni caso, si può impostare 'cell.textLabel.numberOfLines' su' 0', ma è comunque utile scoprire il numero effettivo che verrà usato (per calcolare l'altezza della riga appropriata, come qui, per esempio) . Inoltre trovo che il codice risultante sia molto più chiaro, poiché "0" non è affatto utile semanticamente a colpo d'occhio. – Triz

-7

La mia soluzione era quella di chiamare il tableView:cellForRowAtIndexPath: all'interno della realizzazione di tableView:heightForRowAtIndexPath: come segue

- (CGFloat)tableView:(UITableView *)aTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 

    [self tableView:aTableView cellForRowAtIndexPath:indexPath]; 
    return headerHeight; 
} 
+3

'tableView: heightForRowAtIndexPath:' viene chiamato per ogni (!) Riga singola nella tabellaView. Per questo motivo, chiamate costose come 'tableView: cellForRowAtIndexPath:' non devono essere utilizzate. –

+0

Non sono sicuro del motivo per cui è stato votato perché questo metodo consente di verificare l'altezza effettiva della cella anche se l'etichetta non è l'unico contenuto. Questo è comunque molto costoso. – Kyle