2012-02-07 14 views
6

Ho un UITableView che presenta alcune impostazioni all'utente. Alcune celle sono nascoste a meno che un UISwitch sia nella posizione "On". Ho il seguente codice:Mostrare e nascondere UITableViewCell con UISwitch arresti anomali troppo veloci

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 
    return switchPush.on ? 6 : 1; 
} 

// Hooked to the 'Value Changed' action of the switchPush 
- (IBAction)togglePush:(id)sender { 
    NSMutableArray *indexPaths = [NSMutableArray arrayWithCapacity:0]; 
    for(int i = 1; i <= 5; i++) { 
     [indexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]]; 
    } 

    [tableView beginUpdates]; 
    if(switchPush.on) { 
     [tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic]; 
    } else { 
     [tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic]; 
    } 
    [tableView endUpdates]; 
} 

Questo funziona come previsto, fino a quando posso passare l'UISwitch due volte in rapida successione (toccando due volte), nel qual caso l'applicazione si blocca con un

Invalid table view update. The application has requested an update to the table view that is inconsistent with the state provided by the data source. 

So che è causato dal valore di ritorno errato di numberOfRowsInSection quando l'interruttore ritorna nella sua posizione originale mentre l'animazione della cella è ancora in riproduzione. Ho provato a disabilitare il commutatore e ad agganciare il codice sotto altri gestori di eventi, ma nulla sembra impedire l'arresto anomalo. Usare reloadData invece dell'animazione risolve anche il problema ma preferirei le animazioni carine.

Qualcuno conosce un modo corretto per implementare questo?

+0

Che cos'è un UIToggle? Intendi un 'UISwitch'? – Mundi

+0

Sì, l'ho fatto, ho corretto la domanda. –

risposta

2

Impostare semplicemente la proprietà enabled dello switch su NO fino a quando gli aggiornamenti non sono terminati.

+2

Ho provato questo, ma è ancora possibile riattivare l'interruttore prima che la disattivazione abbia effetto. –

+0

Aggiungi un nuovo '@ selector' per l'evento' UIControlEventTouchDown' e disabilitalo lì. – Mundi

+0

Lo hai fatto funzionare in questo modo? Si prega di considerare barrando il segno di spunta. – Mundi

2

Ho riscontrato questo problema sul mio e il modo per evitare l'arresto anomalo è di non utilizzare esplicitamente l'uiswitch, anziché inoltrare le informazioni in un booleano, ecco come l'ho fatto.

Aggiungi un valore booleano alla parte superiore del vostro file di implementazione

bool _showRows = NO; 

aggiornare il codice uiswitch

- (IBAction)SwitchDidChange:(id)sender { 

NSArray *aryTemp = [[NSArray alloc] initWithObjects:[NSIndexPath indexPathForRow:1 inSection:0], 
        [NSIndexPath indexPathForRow:2 inSection:0], 
        [NSIndexPath indexPathForRow:3 inSection:0], 
        [NSIndexPath indexPathForRow:4 inSection:0],nil]; 

if (_showRows) { 
    _showRows = NO; 
    _switch.on = NO; 
    [_tblView deleteRowsAtIndexPaths:aryTemp withRowAnimation:UITableViewRowAnimationTop]; 
} 
else { 
    _showRows = YES; 
    _switch.on = YES; 
    [_tblView insertRowsAtIndexPaths:aryTemp withRowAnimation:UITableViewRowAnimationBottom]; 
} 
} 

E, infine aggiornare il numberOfRowsInSection

- (NSInteger)tableView:(UITableView *)tableView 
numberOfRowsInSection:(NSInteger)section 
{ 
if (section == 0) { 

    if (_showRows) { 
     return 5; 
    } 
    else { 
     return 1; 

    }  
} 
return 0; 
} 
3

Un'altra soluzione (più elegante) il problema è questo:

ho modificato il metodo di Alan MacGregor - (IBAction)SwitchDidChange:(id)sender in questo modo:

- (IBAction)SwitchDidChange:(UISwitch *)source { 
    if (_showRows != source.on) { 
     NSArray *aryTemp = [[NSArray alloc] initWithObjects: 
        [NSIndexPath indexPathForRow:1 inSection:0], 
        [NSIndexPath indexPathForRow:2 inSection:0], 
        [NSIndexPath indexPathForRow:3 inSection:0], 
        [NSIndexPath indexPathForRow:4 inSection:0],nil]; 
     [_tblView beginUpdates]; 
     _showRows = source.on; 
     if (_showRows) { 
      [_tblView insertSections:aryTemp withRowAnimation:UITableViewRowAnimationFade]; 
     } 
     else { 
      [_tblView deleteSections:aryTemp withRowAnimation:UITableViewRowAnimationFade]; 
     } 
     [_tblView endUpdates]; 
    } 
} 

Le altre parti rimangono invariati.

0

Gli eventi UIControlEventValueChanged si verificano anche quando il valore di un controllo non cambia in realtà. così togglePush viene chiamato anche quando il valore dell'interruttore non cambia. quando si attiva rapidamente l'interruttore, non sempre si passa da acceso> spento> attivo> spento, ecc. è possibile disattivare> on> on> off.

quindi quello che sta succedendo è che stai ottenendo due in una fila che causano due insertSections uno dopo l'altro. che è ovviamente cattivo.

per risolvere questo problema, è necessario ricordare quale era lo stato precedente del pulsante (in un ivar, forse) e solo eseguire l'inserimento (o eliminare) se il nuovo valore (source.on) è diverso dal precedente valore.

Problemi correlati