2012-05-29 17 views
15

¿Cuál es la mejor práctica para manejar un evento táctil de botón para un botón de un UITableViewCell personalizado?Objetivo c: la mejor práctica para manejar un evento táctil de botón para un botón de una UITableViewCell personalizada

mis clases: MyViewController, MyCustomCell

que se me ocurren tres opciones:

Primera opción- tienen el botón como una propiedad de MyCustomCell, y luego añadir un objetivo a ella en el MyViewController archivo .m con MyViewController como destino.

MyViewController archivo .m

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    static NSString *CellIdentifier = @"customCell"; 

    MyCustomCell *cell = (MyCustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
    if (cell == nil) { 
    cell = [[[MyCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; 

    [cell.theButton addTarget:self 
         action:@selector(theButtonTapped:) 
      forControlEvents:UIControlEventTouchUpInside]; 
    } 

    // Configure the cell...  
    [self configureCell:cell atIndexPath:indexPath]; 

    return cell; 
} 

- (void)theButtonTapped:(UIButton *)sender 
{ 
    MyCustomCell *selectedCell = (MyCustomCell *)sender.superview; 

    if (selectedCell) { 
     NSIndexPath *indexPath = [self.tableView indexPathForCell:selectedCell]; 
     MyModel *selectedModel = [self.model objectAtIndex:indexPath.row]; 

     // do something with the model... 
    } 
} 

Segunda opción- Si la celda personalizado se hizo en IB, Ajuste del archivo semilla propietario de ser MyViewController, implementar buttonTapped: método en el MyViewController y conecte el botón Touch Up Inside evento al método buttonTapped:.

Tercera opción- si la celda personalizado no se hizo en IB, agregue un destino para el botón en el archivo .m MyCustomCell con MyCustomCell como objetivo.
Defina MyCustomCellDelegate agregue @property (nonatomic, assign) id<MyCustomCellDelegate> delegate a MyCustomCell y llame a este delegado cuando se toca el botón.
Establezca MyViewController como el delegado de la celda al crear celdas e implemente el protocolo MyCustomCellDelegate.

MyCustomCell archivo .h

@class MyCustomCell; 

@protocol MyCustomCellDelegate <NSObject> 
- (void)buttonTappedOnCell:(MyCustomCell *)cell; 
@end 

@interface MyCustomCell : UITableViewCell 

@property (nonatomic, retain) UIButton *theButton; 
@property (nonatomic, assign) id<MyCustomCellDelegate> delegate; 

@end 

MyCustomCell archivo .m

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier 
{ 
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; 
    if (self) { 
     // Initialization code 
     self.theButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 
     self.theButton.frame = CGRectMake(10,10,50,30); 
     [self addSubview:self.theButton]; 

     [self.theButton addTarget:self 
          action:@selector(theButtonTapped:) 
       forControlEvents:UIControlEventTouchUpInside]; 
    } 
    return self; 
} 

- (void)theButtonTapped:(UIButton *)sender 
{ 
    [self.delegate buttonTappedOnCell:self]; 
} 

MyViewController archivo .m

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    static NSString *CellIdentifier = @"customCell"; 

    MyCustomCell *cell = (MyCustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
    if (cell == nil) { 
     cell = [[[MyCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; 

     cell.delegate = self; 
    } 

    // Configure the cell...  
    [self configureCell:cell atIndexPath:indexPath]; 

    return cell; 
} 

- (void)buttonTappedOnCell:(MyCustomCell *)selectedCell 
{ 
    if (selectedCell) { 
     NSIndexPath *indexPath = [self.tableView indexPathForCell:selectedCell]; 
     MyModel *selectedModel = [self.model objectAtIndex:indexPath.row]; 

     // do something with the model... 
    } 
} 
+1

Me gustaría ir con la opción 1. Parece la más legible para mí. Utilizo un enfoque similar, pero configuro el delegado en la celda personalizada y manejo el botón en la celda personalizada misma y luego invoco una función en el controlador de vista comprobando si el delegado está allí. –

Respuesta

11

tienda de la fila de la celda como tag propiedad de su botón personalizado .

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    // bla bla bla 
    if (!cell) 
    { 
     //bla bla bla 
     [cell.yourButton addTarget:self selector:@selector(yourButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; 
    } 
    // bla bla bla 
    cell.yourButton.tag = indexPath.row; 
} 

-(void)yourButtonTapped:(id)sender 
{ 
    int tag = [(UIButton *)sender tag]; 
    NSLog(@"tapped button in cell at row %i", tag); 
} 
+0

¿Hay algún beneficio haciendo esto y no lo que he hecho? MyCustomCell * selectedCell = (MyCustomCell *) sender.superview; – Eyal

+0

La última vez que verifiqué, un botón en una celda personalizada tendría la vista de contenido de la celda como superview. – Kreiri

+0

El botón debe agregarse a contentView, cuya supervista es la celda. – hwaxxer

1

El uso de la etiqueta, desde mi punto de vista, rompería el rigor de su código. Además, cuando tienes varias secciones, usar la etiqueta definitivamente haría un lío de tu código.

Para evitar este problema, puede crear la subclase UITableViewCell y hacerla contener una propiedad indexPath para que la celda conozca su posición exacta.

Otro problema aquí es, si UITableView invoca a la API insert o delete fila, tiene que actualizar los datos de posición celdas visibles

no creo que es la mejor práctica.

Existe una mejor manera.


recomiendo encarecidamente el uso de MVVM cuando se tiene que manejar diferentes eventos de toque en tu teléfono.

En este patrón, su UITableViewCell personalizada tendría una costumbre CellViewModel. Esta clase sería responsable de mantener todos los datos que usted asocia con la celda, para que pueda recuperar los datos y colocar la lógica de manejo de eventos dentro de la celda.

0

he implementado enfoque basado en bloques subclasificando UIButton:

typedef void (^ActionBlock)(id sender); 

@interface UIBlockButton : UIButton { 
    ActionBlock _actionBlock; 
} 

-(void)handleControlEvent:(UIControlEvents)event withBlock:(ActionBlock) action; 
​@end 

@implementation UIBlockButton 

-(void) handleControlEvent:(UIControlEvents)event withBlock:(ActionBlock) action 
    { 
     _actionBlock = action; 
     [self addTarget:self action:@selector(callActionBlock:) forControlEvents:event]; 
     } 

    -(void) callActionBlock:(id)sender{ 
    _actionBlock(sender); 
    } 

@end 

Y en delegado tableview:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    if (!cell) 
    { 
    cell.yourButton.tag = indexPath.row;// pass tag 
    [cell.yourButton handleControlEvent:UIControlEventTouchUpInside withBlock:^(id sender) { 
    // your selector action code 
    NSLog(@"tapped button in cell at row %i",[(UIButton *)sender tag]); 
    }]; 
    } 
} 
0

En algún momento el botón está girado, y en ese momento es una vista secundaria de una celda que es una subvista de alguna tabla vista.

Simplemente escriba un método que tome una vista, vaya por la cadena de supervista para encontrar la celda que lo contiene, vaya más arriba para encontrar la tabla vista, y luego solicite a la tabla el índice de la celda.

Es mucho más fácil y más confiable que almacenar una etiqueta que contenga una fila, porque no tiene problemas cuando se edita tableview, y es mucho mejor tener un código que averigüe qué indexPath es cuando lo necesita indexPath, y no en algún código completamente no relacionado cuando se crea la celda.

0

Swift 3.0 Solución

cell.btnRequest.tag = indexPath.row 

cell.btnRequest.addTarget(self,action:#selector(buttonClicked(sender:)), for: .touchUpInside) 

func buttonClicked(sender:UIButton) { 

    let buttonRow = sender.tag 
} 
Cuestiones relacionadas