2013-04-03 9 views
7

Ho creato un elenco di selezione multipla che consente la selezione di più ingredienti.UITableViewCell Riutilizzo: cella visualizzata in modo errato - non riutilizzata come previsto

Nella mia vista tabella, le celle possono essere abilitate o disabilitate in base alla proprietà elenco di un ingrediente. Se la proprietà dell'elenco Ingredient è impostata, la cella sarà disabilitata.

Tuttavia, quando una cella viene riutilizzata, non viene visualizzata come mi aspetterei. Le immagini sottostanti spiegano il problema in modo più efficace di me.

(Gli ingredienti che non devono essere abilitati sono: Glassa, latte condensato e Cournflour.)

  1. La prima immagine mostra i tre ingredienti disabili e annotati come previsto.

  2. Tuttavia, nella seconda immagine, lo scorrimento verso il basso rivela che alcuni ingredienti sono disabilitati (ma è possibile selezionarli e hanno un'interazione completa).

  3. La terza immagine mostra l'elenco dopo averlo fatto scorrere in alto. Alcuni ingredienti sono stati disattivati ​​e si noti come Cornflour è visualizzato come abilitato, anche se non è possibile interagire/selezionarlo.

Il problema ha a che fare con il riutilizzo delle celle. Sembra che la cella non venga "ripristinata" quando viene riutilizzata, e quindi mantiene alcuni dei suoi "vecchi" aspetti.

Di seguito è il codice da cellForRowAtIndexPath:, come sono sicuro che questo è dove il problema è (anche se non riesco a vedere cosa c'è che non va).

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    static NSString *CellIdentifier = @"Cell"; 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 

    if (cell == nil) 
    { 
     cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; 
    }  

    // Fetches the corresponding Ingredient from the ingredientArray 
    Ingredient *ingredient = [self.ingredientArray objectAtIndex:indexPath.row]; 

    if ([ingredient.list isEqualToString:@"Lardr"]) 
    { 
     cell.userInteractionEnabled = NO; 
     cell.detailTextLabel.text = @" Already in your Lardr"; 
    } 
    else if ([ingredient.list isEqualToString:@"Shopping List"]) 
    { 
     cell.userInteractionEnabled = NO; 
     cell.detailTextLabel.text = @" Already on your Shopping List"; 
    } 
    else 
    { 
     cell.userInteractionEnabled = YES; 
     cell.detailTextLabel.text = @""; 
    } 

    // Add a checkmark accessory to the cell if the ingredient is on the selectedIngredients array 
    if ([self.selectedIngredients containsObject:ingredient]) 
     cell.accessoryType = UITableViewCellAccessoryCheckmark; 
    else 
     cell.accessoryType = UITableViewCellAccessoryNone; 

    cell.textLabel.text = ingredient.name; 

    return cell; 
} 

Sono alla fine del mio ingegno cercando di capire questo fuori, e ho letto tutto così domande che sono neanche lontanamente legati, ma senza alcun risultato. Qual è il problema?!


mia logica è che per ogni cella, le proprietà textLabel, detailTextLabel, userInteractionEnabled e accessoryType sono impostati, non importa quale esecuzione percorso attraverso il if, quindi non posso vedere perché, anche dopo il riutilizzo, il la cella non viene visualizzata correttamente.


EDIT: Nel tentativo di capire la radice del problema, ho provato "reset" cella nuovo esso è predefinito aggiungendo il seguente proprio sopra la linea che recupera il corrispondente Ingrediente: ma senza risultato.

cell.userInteractionEnabled = YES; 
cell.textLabel.text = nil; 
cell.detailTextLabel.text = nil; 
cell.accessoryType = UITableViewAccessoryNone; 

Tuttavia, ciò che è interessante e completamente illogica - quando ho spostato la seguente linea cell.textLabel.text = ingredient.name a direttamente sotto la riga Ingredient *ingredient = [self.ingredientArray objectAtIndex:indexPath.row];, assolutamente NO styling è applicato a qualsiasi cella, anche se UserInteraction è impostato più avanti (e le celle rilevanti sono disabilitate come previsto).

Sto pensando, l'ordine in cui sono impostate le proprietà di una cella è importante? So che non dovrebbe, ma l'aspetto cambia in base a quanto sopra.


Aggiornamento: ho risolto il problema; vedi la mia risposta qui sotto.

+0

Stai usando StoryBoards? –

+0

Cosa sta facendo diventare grigio il testo? –

+0

Non c'è niente di sbagliato in quel codice che hai postato. L'impostazione dell'interazione dell'utente su NO non rende il testo più grigio. Penso che il tuo problema risieda probabilmente in qualunque metodo tu stia usando per farlo. – rdelmar

risposta

2

ho risolto il problema. Il problema era che stavo impostando userInteractionEnabled PRIMA di impostare il testo della cella (grazie a un link di Carl Veazey nei commenti).

Ho risolto il problema impostando il testo della cella prima di regolare la proprietà userInteractionEnabled. Tuttavia, non è stato applicato alcuno stile alla cella (anche se la cella era disabilitata). Ho quindi dovuto modellare manualmente la cella impostando il testo del colore della cella. Di seguito è riportato il codice corretto con i commenti.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    static NSString *CellIdentifier = @"Cell"; 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 

    if (cell == nil) 
    { 
     cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; 
    } 

    // Fetches the relevent ingredient from the ingredientArray 
    Ingredient *ingredient = [self.ingredientArray objectAtIndex:indexPath.row]; 
    cell.textLabel.text = ingredient.name; // Moved this line before setting userInteractionEnabled 

    if ([ingredient.list isEqualToString:@"Lardr"]) 
    { 
     cell.userInteractionEnabled = NO; 
     cell.detailTextLabel.text = @" Already in your Lardr"; 
     cell.textLabel.textColor = [UIColor grayColor]; // Update the color accordingly 
    } 
    else if ([ingredient.list isEqualToString:@"Shopping List"]) 
    { 
     cell.userInteractionEnabled = NO; 
     cell.detailTextLabel.text = @" Already on your Shopping List"; 
     cell.textLabel.textColor = [UIColor grayColor]; 
    } 
    else 
    { 
     cell.userInteractionEnabled = YES; 
     cell.detailTextLabel.text = @""; 
     cell.textLabel.textColor = [UIColor blackColor]; 
    } 

    // Add a checkmark accessory to the cell if the ingredient is on the selectedIngredients array 
    if ([self.selectedIngredients containsObject:ingredient]) 
     cell.accessoryType = UITableViewCellAccessoryCheckmark; 
    else 
     cell.accessoryType = UITableViewCellAccessoryNone; 

    return cell; 
} 

Ovviamente, l'ordine in cui si impostano le proprietà di una cella dovrebbe essere irrilevante, e quindi sono sicuro che si tratta di un bug. Spero che questo aiuti per chiunque altro si imbatta nello stesso problema.

0

Mantenere l'elenco della cella selezionata nella vista tabella, mentre riutilizzando la cella è sufficiente controllare che la cella sia già presente nell'elenco di selezione. Se SÌ, fai la tua personalizzazione laggiù. Prova così.

Dichiarazione

TableViewCell *_selectedCell; 

personalizzare la riga per memorizzare la cella selezionata e mantenere la lista di selezione.

_selectedCell = (TableViewCell*)[self.ItemTable cellForRowAtIndexPath:[NSIndexPath indexPathForRow:rowIndex inSection:0]]; 

Nel controllo cellForRowAtIndexPath cella corrente è nel

if(_selectedCell) 
     [cell setBackgroundColor:[UIColor whiteColor]];// Customize the cell 
0

Utilizzando il seguente codice con un controller vista tabella dallo storyboard, tutto funzionava bene. Sembra che ci sia qualche bug con la visualizzazione della tabella che si ottiene per impostazione predefinita quando non si usa uno storyboard:

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    static NSString *CellIdentifier = @"Cell"; 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; 

    // Fetches the corresponding Ingredient from the ingredientArray 
    Ingredient *ingredient = [self.ingredientArray objectAtIndex:indexPath.row]; 

    if ([ingredient.list isEqualToString:@"Lardr"]) 
    { 
     cell.userInteractionEnabled = NO; 
     cell.detailTextLabel.text = @" Already in your Lardr"; 
     cell.textLabel.textColor = [UIColor lightGrayColor]; 
    } 
    else if ([ingredient.list isEqualToString:@"Shopping List"]) 
    { 
     cell.userInteractionEnabled = NO; 
     cell.detailTextLabel.text = @" Already on your Shopping List"; 
     cell.textLabel.textColor = [UIColor lightGrayColor]; 
    } 
    else 
    { 
     cell.userInteractionEnabled = YES; 
     cell.detailTextLabel.text = @""; 
     cell.textLabel.textColor = [UIColor blackColor]; 
    } 

    if ([self.selectedIngredients containsObject:ingredient]) 
     cell.accessoryType = UITableViewCellAccessoryCheckmark; 
    else 
     cell.accessoryType = UITableViewCellAccessoryNone; 

    cell.textLabel.text = ingredient.name; 

    return cell; 
} 

Si noti che io uso dequeueReusableCellWithIdentifier: forIndexPath: invece di dequeueReusableCellWithIdentifier :, ed eliminare la clausola if. Questo non ha nulla a che fare con il tuo problema, ma è l'ultimo modo di farlo per una vista tabella in uno storyboard.

+0

hai dimostrato il bug? in altre parole, hai visto questo codice funzionare in modo diverso quando applicato a storyboard e tabelle non storyboard? sarebbe molto sorprendente. – danh

+0

@danh, sì, ho dimostrato il bug usando quasi lo stesso codice sopra - poiché non ha uno storyboard, ho aggiunto la solita clausola if (cell == nil). Ma a parte questo, il codice era identico a quello che ho postato sopra. Ho appena assegnato init'd a un controller di visualizzazione tabella nel delegato dell'app e ho visto lo stesso comportamento di quello pubblicato dall'OP. – rdelmar

2

impostare il colore del tuo cellulare in modo esplicito nel willDisplayCell

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{ 

Ingredient *ingredient = [self.ingredientArray objectAtIndex:indexPath.row]; 

    if ([ingredient.list isEqualToString:@"Lardr"]) 
    { 
     cell.textLabel.textColor = [UIColor lightGrayColor]; 
    } 
    else if ([ingredient.list isEqualToString:@"Shopping List"]) 
    { 
     cell.textLabel.textColor = [UIColor lightGrayColor]; 
    } 
    else 
    { 
     cell.textLabel.textColor = [UIColor blackColor]; 
    } 

} 
+1

Ho appena implementato il tuo suggerimento. Non ha ancora risolto il problema. – TeaPow

+0

Volevo impostare il colore di sfondo nella mia cella e su cellForRowAtIndexPath non funzionava, ma con questo funziona come un incantesimo. Grazie –

Problemi correlati