2010-04-01 9 views
6

Tengo un controlador de vista de tabla con múltiples controles UISwitch en ellos. Configuro el delegado al controlador de vista de tabla con la misma acción para todos los switches. Necesito poder determinar qué cambio se cambió, así que creo una matriz de cadenas que contiene el nombre de cada interruptor. Los índices en la matriz se colocarán en la propiedad de etiqueta de cada UISwitch.Manejo de varios controles UISwitch en una vista de tabla sin usar la propiedad de etiqueta

Sin embargo, estoy listo usando la propiedad de etiqueta para otra cosa, concretamente para encontrar el control correcto en la celda en cellForRowAtIndexPath con viewWithTag! (Hay varias cosas que debo establecer dentro de cada celda.)

Entonces, ¿estoy pensando en la línea correcta aquí? Siento que estoy bastante limitado en cómo averiguo exactamente qué UISwitch cambió su valor, por lo que puedo hacer algo útil con él.

Respuesta

5

me fijo Esta subclase UISwitch así:

@interface NamedUISwitch : UISwitch { 
NSString *name; 

}

Parece elegante (no se requieren matrices de índice) y la propiedad de etiqueta es libre de hacer lo que quiera.

He leído que usted tiene que tener cuidado con la subclasificación en Objective-C, aunque ...

+0

Acabo de hacer lo mismo, mi único comentario sería convertir el nombre en una propiedad. – typemismatch

0

Usted está cerca en su enfoque. Lo que he hecho en situaciones similares es crear subclases UITableViewCell separadas, configurar la etiqueta del UISwitch para que sea el índice de la ruta del índice, y solo usar esa subclase UITableViewCell en una sección específica de la vista de tabla. Esto le permite usar la etiqueta de la celda para determinar de manera única qué celda tiene el evento sin mantener una lista de índices separada (como parece que está haciendo).

Como el tipo de celda es único, puede acceder fácilmente a los otros elementos de la celda creando métodos/propiedades en la subclase UITableViewCell.

Por ejemplo:

@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 

En:

- (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 
} 

propietario es el delegado para la célula y luego se puede utilizar para iniciar acciones en su controlador. Asegúrese de que conecta el UISwitch a la acción toggleValue, para que pueda iniciar acciones en el delegado cuando el UISwitch cambia de estado:

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

Con la aprobación de la UISwitch con la llamada al método, a continuación, puede acceder a la ruta del índice de la célula. También puede omitir el uso de la propiedad de etiqueta al tener explícitamente un ivar para almacenar el NSIndexPath de la celda y luego pasar la celda completa con la llamada al método.

+0

Cómo sobre subclasificar el UISwitch y agregarle un identificador de cadena? ¿Sería eso un mal diseño? – Thaurin

+0

Hmmm, un problema con su enfoque es que no estoy usando IB, así que agrego todos los controles al contenido de la celda. Luego, cuando los vuelva a necesitar en el controlador de tabla para establecer sus valores para la fila que se muestra, los recupero con viewWithTag. Ese es prácticamente el problema, porque ya estoy usando la etiqueta para identificar qué cambio se modificó. Con un NIB, solo conecta algunas salidas. ¿Echaba de menos algo vital aquí? Voy a intentar subclasificar UISwitch ahora, aunque no estoy seguro de si UISwitch fue construido para alguna vez ser subclasificado. – Thaurin

+0

Yo recomendaría bucear en IB y subclasificar todo UITableViewCell en lugar de solo UISwitch. Creo (creo) que resultará en un código más sostenible a largo plazo. Además, una vez que crea una subclase a través de IB/XCode, realmente se convierte en un complemento. –

1

He escrito una subclase UISwitch con un lanzador basado en bloques para eventos de control de cambio de valor que puede ayudar cuando se trata de realizar un seguimiento qué valor del interruptor ha cambiado. Idealmente, podríamos hacer algo similar con la composición en lugar de la subclasificación, pero esto funciona bien para mis necesidades.

https://gist.github.com/3958325

Se puede utilizar la siguiente manera:

ZUISwitch *mySwitch = [ZUISwitch alloc] init]; 

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

También puede utilizarlo desde un archivo XI ter, arrastrando un interruptor en su vista, y luego cambiar su clase con el ZUISwitch

+0

Este es un gran enfoque, especialmente para iterar sobre un número desconocido de conmutadores. Tengo curiosidad por qué haces el '[self commonInit]' en awakeFromNib, así como en init. –

0

Me doy cuenta de que llevo unos tres años tarde en la fiesta pero he desarrollado una solución sin subclases que creo que es preferible (y más simple). Estoy trabajando con el mismo escenario exacto que el escenario descrito por 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]; 
} 

Luego desea declarar el método que se muestra arriba, indexPathForCellContainingView. Este es un método aparentemente innecesaria, ya que parece a primera vista que todo lo que tiene que hacer es identificar supervista del interruptor, pero hay una diferencia entre los superviews de iOS7 y versiones anteriores, por lo que este se encarga de todo:

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