2009-09-06 12 views
20

Ho un UITableView dove in alcuni casi alcune sezioni hanno zero righe. Il mio obiettivo è che quando questo è vero, non voglio nessuno spazio sprecato nella vista tabella, dovrebbe apparire come se non ci fossero dati.UITableView non rispetta heightForHeaderInSection/heightForFooterInSection?

Il problema che sto avendo è con l'intestazione e il piè di pagina per le sezioni, che vengono visualizzati anche se non c'è nessuna riga e nonostante io sovrascrivi il metodo delegato per restituire 0.0f.

Ecco come appare: puoi vedere il ~ 20p di spazio grigio in alto lì, intestazioni e piè di pagina di circa 10p ciascuno per una sezione con 0 righe.

alt text http://www.hanchorllc.com/table_cells.png

Ecco il mio codice pseudo:

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { 
    if ([section hasRow]) { 
      return 10.0f; 
    } else { 
      return 0.0f; 
    } 
} 



- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { 
    if ([section hasRow]) { 
      return 10.0f; 
    } else { 
      return 0.0f; 
    } 
} 

Ho verificato che questi metodi sono chiamati e che il percorso di esecuzione corretta sta avvenendo.

Una ruga: questo controller di visualizzazione utilizza un XIB e UITableView ha i valori di intestazione di sezione e piè di pagina impostati su 10.0 (impostazione predefinita), anche se ho pensato che fosse sovrascritto dal metodo delegato, se implementato.

Questo è un targeting per app 3.0.

Cosa sto sbagliando?

risposta

24

In UITableView "raggruppato" su iPhone, verrà comunque visualizzata l'altezza minima per l'intestazione e il piè di pagina, ignorando in modo efficace il codice per impostarlo su zero. Non è collegato al predefinito XIB.

Ciò è dovuto al fatto che un'intestazione o un piè di pagina a altezza zero apparirebbe molto strano. Quindi Apple ha decretato che un'intestazione non può essere impostata su 0. E quindi più sezioni "vuote" renderanno stranamente come per il tuo screenshot.

Ho paura è tutto perché stai andando nel modo sbagliato per cancellare le dimensioni dell'intestazione quando non ci sono righe di dati; invece dovresti chiamare senza metodi per le sezioni vuote. È una tecnica sbagliata perché essenzialmente l'iPhone deve chiamare più metodi di quelli che dovrebbe, e anche il rendering di più intestazioni di quelle che vuoi (di solito - a volte le persone vogliono lasciare lì le intestazioni vuote, ad esempio per il trascinamento della selezione) .

Quindi, ad esempio, immaginiamo di avere un numero di sezioni, ma solo alcune di esse hanno più di una riga in (forse in base alle impostazioni/filtri utente).

Il sbagliato modo della sua applicazione è:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 
    return totalNumberOfPossibleSections; 
} 

e poi per ogni sezione si ha alcun risultato per:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 
    if (![section hasRow]) return 0; 
} 

e

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { 
    if (![section hasRow]) return 0.0f; 
} 

Il corretta via dell'imp lo è:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 
    return numberOfSectionsWhichHaveAtLeastOneRowInThem; 
} 

e quindi ogni sezione avrà almeno un risultato.In questo modo, le sezioni senza dati non vengono nemmeno renderizzate, i metodi non vengono nemmeno chiamati per loro. Nota: i miei due nomi di variabile sono composti per comunicare ciò che conterranno! Non sono speciali variabili di Apple ...

Sperare che aiuti!

+0

Sì, sembra ragionevole. Ho preso l'abitudine di dichiarare costanti enum per i miei layout di sezione di tabella e stavo cercando di forzare questo particolare controller in quel progetto, che non funziona molto bene con un numero sconosciuto di righe nelle sezioni. Dispari che la documentazione di Apple non indica da nessuna parte (che io possa trovare) che non accetterà 0.0 come valore, specialmente dal momento che * puoi * impostare 0.0 nell'XIB (e sì, sembra davvero strano). Posso archiviare un bug doco in quanto dovrebbe almeno notare che il valore deve essere maggiore di 0.0f. applausi. – Hunter

+0

Sembra davvero strano, anche io non l'ho visto in nessuna documentazione, quindi probabilmente vale la pena archiviarlo come un bug. – h4xxr

+0

Questa è una buona idea, ma ho avuto problemi nell'implementarlo. Ho istruzioni switch per la sezione in un mucchio dei miei metodi tableview. Restituire un numero variabile di sezioni a seconda del contenuto dei dati rovina davvero questa mappatura e non riesco a pensare ad un modo elegante (o persino semplice) per affrontarlo. – blindjesse

0

In realtà, con me sta succedendo il contrario. Ho assegnato l'intestazione di sezione a 10 in xib, ma per la prima sezione, voglio un'intestazione di intestazione dimensione. Sto usando questo metodo nel mio UITableViewCotroller

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    if(indexPath.section==0) 
     return 125; 
    return tableView.rowHeight; 
} 

Ma le altezze sezione di intestazione non vengono modificate, anche se il metodo è sempre chiamato.

3

Ho avuto un problema simile: Stavo caricando un UITableView da un XIB (come te), e fornito un 0 altezza per alcuni piè di pagina della sezione con tableView:heightForFooterInSection (come te), ma il valore è stato ignorato.

La correzione era semplice: impostare anche l'altezza del piè di pagina su 0.0 nell'XIB. (In Interface Builder seleziona la vista tabella, premi Comando-3 per visualizzare Impostazioni dimensioni, cerca il campo altezza piè di pagina nella parte superiore)

Una volta eseguito, l'altezza del piè di pagina personalizzata è stata rispettata come previsto. (Forse si tratta l'altezza piè di pagina XIB come minimo?)

+0

In IB, l'altezza minima della sezione che è possibile impostare per una vista tabella raggruppata è 1. Quindi questo non cambia nulla. –

1

Funziona per me:

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section 
{ 
    tableView.sectionHeaderHeight = (section == 0 ? 10 : 0); 
    return tableView.sectionHeaderHeight; 
} 

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section 
{ 
    tableView.sectionFooterHeight = (section == 0 ? 20 : 4); 
    return tableView.sectionFooterHeight; 
} 
9

Sembra che la tabella rispetta tableView:heightForHeaderInSection: solo se tableView:viewForHeaderInSection: non è nil, o se tableView:titleForHeaderInSection: non è nil o @"". Lo stesso vale per le altezze dei piedi.

Quindi supponendo che non si dispone di alcuna vista sezione di intestazione o titoli, basta aggiungere questo al vostro tavolo delegato:

- (UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { 
    return [[[UIView alloc] initWithFrame:CGRectZero] autorelease]; 
} 
+0

Questo non è vero.Se restituisci 0 in tableView: heightForHeaderInSection: otterrai un piè di pagina di 10 punti di altezza. Dovrai specificare un numero leggermente più grande come 0.00001f come @Juris menziona nella sua risposta. – Klaas

0

La mia soluzione a questo problema è on e off come h4xxr sta descrivendo però, ho un approccio leggermente diverso alla costruzione di un numero dinamico di sezioni.

In primo luogo, definisco un metodo che descriverà la struttura dei miei dati e segnalerà che i dati devono essere mostrati o meno nella tabella. Questo flag è memorizzato in una matrice in modo che io possa includere il numero minimo o il numero di sezioni che mi piace. Posso descrivere questa implementazione un po 'meglio se ci concentrassimo solo sul numero di celle per ogni sezione:

Supponiamo che la mia prima sezione sia i dettagli di contatto con nome, cognome ed età. Definirò questa sezione con un id di '1' (anche se tecnicamente, come spiegherò in seguito, questo potrebbe essere qualsiasi numero). Ora, se il mio metodo determina che questa sezione dovrebbe essere visibile, spingo il valore '1' su un array.

La sezione successiva che desidero mostrare è l'indirizzo e può avere 3-4 righe/celle. Come sopra, la logica del mio metodo determina se l'indirizzo debba essere visibile spingendo "2" sull'array.

Ora .. ..se volevamo entrambe le sezioni visibili, avremmo un array con una lunghezza di 2 e due elementi [1,2]. Se volessimo solo vedere i dettagli del contatto, il nostro array avrebbe una lunghezza pari a 1 con gli articoli [1] e [2] solo per l'indirizzo.

Ora possiamo restituire la lunghezza del nostro array per definire il numero di sezioni che vogliamo.

nostra istruzione switch sarebbe ora assomigliare a qualcosa di simile:

switch(ourArray[indexPath.section]){ 
    case 1: 
     <Return the number of rows for the contact details which we said would be 3> 
     break; 
    case 2: 
     <Return the number of rows for the address details which we said would be 4> 
     break; 
    case 3: 
     <Return another number for some section that is referenced by the id '3'> 
     break; 
} 

Avviso ho messo caso 3 nel mio interruttore. Poiché la matrice nel nostro esempio contiene solo i valori "1" e "2", il caso 3 non verrebbe mai abbinato e quindi ignorato a meno che non decidessimo di aggiungere/abilitare questo caso spingendolo all'array.

Nota anche che nel nostro metodo possiamo definire la logica di quali sezioni sono visibili, modificare l'ordine delle sezioni inserendole/spingendole in posizioni diverse nella matrice.

Uso religiosamente il precedente, in quanto consente di disaccoppiare l'indicizzazione e la costruzione delle sezioni.

Infine, prima di aggiornare il mio tavolo usando 'reloadData' chiamerò il mio metodo che costruirà l'array e fornirà la lunghezza e la sequenza corrette degli id ​​di sezione per consentire al mio tableview di sapere come si costruisce da solo. Se i miei dati cambiano o vengono filtrati in qualche modo, chiamerò di nuovo questo metodo e ricostruirò l'array.

32

Questo è un po 'complicato, poiché il valore 0.0f non è accettato. ma qualsiasi cosa abbastanza vicina a zero farà il trucco. Se decidi di non essere pixel perfetto e vuoi i numeri tondi, allora 1.0f farà quasi la stessa cosa, dato che la differenza in altezza di 1pz sarà abbastanza evidente.

-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{ 
    if(section == 1) 
     return 0.000001f; 
    else return 44.0f; // put 22 in case of plain one.. 
} 

-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{ 
    return 0.000001f; //removing section footers 
} 
+0

Wow. È così difficile ma funziona. – nonamelive

+1

Questo hack non sembra funzionare su iOS 7. – crishoj

+1

Uno scherzo di un trucco.Dopo aver trascorso un giorno su heightForHeaderInSection e heightForFooterInSection questo ha funzionato per me.E funziona anche su iOS 7 :) – Machete

1

ho scoperto che nel mio caso sono stati necessari 2 cose da uccidere il piè di pagina fantasma:

1) l'impostazione della visualizzazione della tabella sectionFooterHeight-0, cioè in viewDidLoad aggiungendo:

tableView.sectionFooterHeight = 0 

2) aggiungendo il metodo delegate:

override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { 
    return UIView(frame: CGRect.zero) 
} 

(utilizzando Swift 2.2)

Problemi correlati