2010-04-01 8 views
6

Ho un controller di visualizzazione tabella con più controlli UISwitch in essi. Ho impostato il delegato sul controller di visualizzazione tabella con la stessa azione per tutti gli switch. Devo essere in grado di determinare quale switch è stato modificato, quindi creo una serie di stringhe che contiene il nome di ciascun interruttore. Gli indici dell'array verranno inseriti nella proprietà tag di ciascun UISwitch.Gestione di più controlli UISwitch in una vista tabella senza utilizzare la proprietà tag

Tuttavia, sono pronto ad utilizzare la proprietà tag per qualcos'altro, ovvero trovare il controllo corretto nella cella in cellForRowAtIndexPath con viewWithTag! (Ci sono diverse cose che ho bisogno di impostare all'interno di ogni cella.)

Quindi, sto pensando lungo le linee giuste qui? Sento che sono piuttosto limitato nel modo in cui scopro esattamente quale UISwitch ha cambiato il suo valore, quindi posso fare qualcosa di utile con esso.

risposta

5

Ho fissato questo sottoclasse UISwitch in questo modo:

@interface NamedUISwitch : UISwitch { 
NSString *name; 

}

Sembra elegante (nessun array indice obbligatori) e la proprietà tag è libero di fare ciò che vuole.

ho letto che bisogna stare attenti con la creazione di sottoclassi in Objective-C, anche se ...

+0

Ho fatto la stessa cosa, il mio unico commento sarebbe stato di nominare una proprietà. – typemismatch

0

Sei vicino al tuo approccio. Quello che ho fatto in situazioni simili è creare sottoclassi UITableViewCell separate, impostare il tag di UISwitch come index.row del percorso dell'indice e utilizzare solo la sottoclasse UITableViewCell in una sezione specifica della vista tabella. Questo ti permette di usare il tag della cella per determinare in modo univoco quale cella ha l'evento senza mantenere una lista di indici separata (come sembra che tu stia facendo).

Poiché il tipo di cella è univoco, è possibile accedere facilmente agli altri elementi della cella creando metodi/proprietà nella sottoclasse UITableViewCell.

Ad esempio:

@interface TableViewToggleCell : UITableViewCell { 
    IBOutlet UILabel *toggleNameLabel; 
    IBOutlet UILabel *detailedTextLabel; 
    IBOutlet UISwitch *toggle; 
    NSNumber *value; 
    id owner; 
} 

@property (nonatomic, retain) UILabel *toggleNameLabel; 
@property (nonatomic, retain) UILabel *detailedTextLabel; 
@property (nonatomic, retain) UISwitch *toggle; 
@property (nonatomic, retain) id owner; 

-(void) setLable:(NSString*)aString; 
-(void) setValue:(NSNumber*)aNum; 
-(NSNumber*)value; 
-(void) setTagOnToggle:(NSInteger)aTag; 

-(IBAction)toggleValue:(id)sender; 

@end 

In:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    // ... prior iniitalization code for creating cell is assumed 
toggleCell.owner = self; 
[toggleCell setLable:@"some string value"]; 
[toggleCell setTagOnToggle:indexPath.row]; 
toggleCell.owner = self; 
return toggleCell; 
    //... handle cell set up for other cell types as needed 
} 

proprietario è il delegato per la cella e può quindi essere utilizzato per avviare azioni nel vostro controller. Assicurarsi di collegare il vostro UISwitch all'azione toggleValue, in modo che è possibile avviare azioni nel delegato quando l'UISwitch cambia stato:

-(IBAction)toggleValue:(id)sender; 
{ 
    BOOL oldValue = [value boolValue]; 
    [value release]; 
    value = [[NSNumber numberWithBool:!oldValue] retain]; 
    [owner performSelector:@selector(someAction:) withObject:toggle]; 
} 

Passando l'UISwitch con la chiamata di metodo, è quindi possibile accedere al percorso di indice per la cellula. Si potrebbe anche bypassare l'uso della proprietà tag esplicitamente avendo un ivar per memorizzare NSIndexPath della cella e quindi passare l'intera cella con la chiamata di metodo.

+0

Come sulla sottoclasse di UISwitch e aggiungendo un identificatore di stringa ad esso? Sarebbe un cattivo design? – Thaurin

+0

Hmmm, un problema con il tuo approccio è che non sto usando IB, quindi aggiungo tutti i controlli al contenuto della cella personalmente. Quindi, quando ho bisogno di loro di nuovo nel controller della tabella per impostare i loro valori per la riga che viene mostrata, li riaverlo con viewWithTag. Questo è praticamente il problema, perché sto già usando il tag per identificare quale switch è stato cambiato. Con un NIB, basta collegare alcune prese. Mi sono perso qualcosa di vitale qui? Ora cercherò di creare sottoclassi di UISwitch, anche se non sono sicuro che UISwitch sia stato creato per essere mai sottoclassato. – Thaurin

+0

Consiglierei l'immersione in IB e la sottoclasse dell'intero UITableViewCell anziché solo di UISwitch. Sarà (credo) risultato in un codice più gestibile nel lungo periodo. Inoltre, una volta creata una sottoclasse tramite IB/XCode, diventa davvero un gioco da ragazzi. –

1

ho scritto una sottoclasse UISwitch con una curva a base di blocco per gli eventi di controllo delle modifiche del valore che può aiutare quando si cerca di tenere traccia quale valore dell'interruttore è cambiato. Idealmente, potremmo fare qualcosa di simile con la composizione piuttosto che la sottoclasse, ma questo funziona bene per i miei bisogni.

https://gist.github.com/3958325

Si può usare in questo modo:

ZUISwitch *mySwitch = [ZUISwitch alloc] init]; 

[mySwitch onValueChange:^(UISwitch *uiSwitch) { 
     if (uiSwitch.on) { 
      // do something 
     } else { 
      // do something else 
     } 
    }]; 

È anche possibile utilizzare da un file XIB, trascinando un interruttore sulla vostra vista, e poi cambiando la sua classe per ZUISwitch

+0

Questo è un ottimo approccio, specialmente per iterare su un numero sconosciuto di switch. Sono curioso del perché tu faccia il '[self commonInit]' in awakeFromNib e init. –

0

Mi rendo conto che sono circa tre anni in ritardo rispetto alla festa ma ho sviluppato una soluzione senza sottoclassi che penso sia preferibile (e più semplice). Sto lavorando con lo stesso identico scenario dello scenario descritto da Thaurin.

- (void)toggleSwitch:(id) sender 
{ 
    // declare the switch by its type based on the sender element 
    UISwitch *switchIsPressed = (UISwitch *)sender; 
    // get the indexPath of the cell containing the switch 
    NSIndexPath *indexPath = [self indexPathForCellContainingView:switchIsPressed]; 
    // look up the value of the item that is referenced by the switch - this 
    // is from my datasource for the table view 
    NSString *elementId = [dataSourceArray objectAtIndex:indexPath.row]; 
} 

Quindi si desidera dichiarare il metodo mostrato sopra, indexPathForCellContainingView. Questo è un metodo apparentemente inutile perché sembrerebbe a prima vista che tutto quello che dovete fare è individuare superview dello switch, ma c'è una differenza tra le superviews di iOS7 e versioni precedenti, quindi questo gestisce tutti:

- (NSIndexPath *)indexPathForCellContainingView:(UIView *)view { 
    while (view != nil) { 
     if ([view isKindOfClass:[UITableViewCell class]]) { 
      return [self.myTableView indexPathForCell:(UITableViewCell *)view]; 
     } else { 
      view = [view superview]; 
     } 
    } 
    return nil; 
} 
Problemi correlati