Usar una imagen personalizada para una accessView de UITableViewCell y hacer que responda a UITableViewDelegate

Estoy usando una UITableViewCell dibujada a medida, que incluye la misma para la vista de accessoryView la celda. Mi configuración para el accesorioView sucede por el camino de algo como esto:

 UIImage *accessoryImage = [UIImage imageNamed:@"accessoryDisclosure.png"]; UIImageView *accImageView = [[UIImageView alloc] initWithImage:accessoryImage]; accImageView.userInteractionEnabled = YES; [accImageView setFrame:CGRectMake(0, 0, 28.0, 28.0)]; self.accessoryView = accImageView; [accImageView release]; 

También cuando la celda se inicializa, usando initWithFrame:reuseIdentifier: me initWithFrame:reuseIdentifier: de establecer la siguiente propiedad:

 self.userInteractionEnabled = YES; 

Lamentablemente en mi UITableViewDelegate, mi tableView:accessoryButtonTappedForRowWithIndexPath: ( tableView:accessoryButtonTappedForRowWithIndexPath: 10 veces) no se activa. El delegado definitivamente está cableado correctamente.

¿Qué puede faltar?

Gracias a todos.

Lamentablemente, ese método no se llama a menos que se toque el tipo de botón interno proporcionado cuando utiliza uno de los tipos predefinidos. Para usar el suyo, tendrá que crear su accesorio como un botón u otra subclase UIControl (recomendaría un botón usando -buttonWithType:UIButtonTypeCustom y configurando la imagen del botón, en lugar de usar UIImageView).

Aquí hay algunas cosas que uso en Outpost, que personaliza suficientes widgets estándar (solo un poco, para que coincida con nuestra coloración verde azulado) que terminé haciendo mi propia subclase intermediario UITableViewController para mantener el código de utilidad para todas las otras vistas de tabla para usar (ahora subclases OPTableViewController).

En primer lugar, esta función devuelve un nuevo botón de divulgación de detalles utilizando nuestro gráfico personalizado:

 - (UIButton *) makeDetailDisclosureButton { UIButton * button = [UIButton outpostDetailDisclosureButton]; [button addTarget: self action: @selector(accessoryButtonTapped:withEvent:) forControlEvents: UIControlEventTouchUpInside]; return ( button ); } 

El botón llamará a esta rutina cuando esté lista, y luego alimentará la rutina UITableViewDelegate estándar para botones de accesorios:

 - (void) accessoryButtonTapped: (UIControl *) button withEvent: (UIEvent *) event { NSIndexPath * indexPath = [self.tableView indexPathForRowAtPoint: [[[event touchesForView: button] anyObject] locationInView: self.tableView]]; if ( indexPath == nil ) return; [self.tableView.delegate tableView: self.tableView accessoryButtonTappedForRowWithIndexPath: indexPath]; } 

Esta función ubica la fila obteniendo la ubicación en la vista de tabla de un toque del evento proporcionado por el botón y preguntando a la vista de tabla por la ruta de índice de la fila en ese punto.

Encontré que este sitio web es muy útil: vista de accesorios personalizados para su uitableview en iphone

En resumen, use esto en cellForRowAtIndexPath: :

 UIImage *image = (checked) ? [UIImage imageNamed:@"checked.png"] : [UIImage imageNamed:@"unchecked.png"]; UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; CGRect frame = CGRectMake(0.0, 0.0, image.size.width, image.size.height); button.frame = frame; [button setBackgroundImage:image forState:UIControlStateNormal]; [button addTarget:self action:@selector(checkButtonTapped:event:) forControlEvents:UIControlEventTouchUpInside]; button.backgroundColor = [UIColor clearColor]; cell.accessoryView = button; 

luego, implementa este método:

 - (void)checkButtonTapped:(id)sender event:(id)event { NSSet *touches = [event allTouches]; UITouch *touch = [touches anyObject]; CGPoint currentTouchPosition = [touch locationInView:self.tableView]; NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint: currentTouchPosition]; if (indexPath != nil) { [self tableView: self.tableView accessoryButtonTappedForRowWithIndexPath: indexPath]; } } 

Mi enfoque es crear una subclase UITableViewCell y encapsular la lógica que llamará al UITableViewDelegate habitual de UITableViewDelegate dentro de ella.

 // CustomTableViewCell.h @interface CustomTableViewCell : UITableViewCell - (id)initForIdentifier:(NSString *)reuseIdentifier; @end // CustomTableViewCell.m @implementation CustomTableViewCell - (id)initForIdentifier:(NSString *)reuseIdentifier; { // the subclass specifies style itself self = [super initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:reuseIdentifier]; if (self) { // get the button elsewhere UIButton *accBtn = [ViewFactory createTableViewCellDisclosureButton]; [accBtn addTarget: self action: @selector(accessoryButtonTapped:withEvent:) forControlEvents: UIControlEventTouchUpInside]; self.accessoryView = accBtn; } return self; } #pragma mark - private - (void)accessoryButtonTapped:(UIControl *)button withEvent:(UIEvent *)event { UITableViewCell *cell = (UITableViewCell*)button.superview; UITableView *tableView = (UITableView*)cell.superview; NSIndexPath *indexPath = [tableView indexPathForCell:cell]; [tableView.delegate tableView:tableView accessoryButtonTappedForRowWithIndexPath:indexPath]; } @end 

Una extensión de la respuesta de Jim Dovey anterior:

Tenga cuidado cuando use un UISearchBarController con su UITableView. En ese caso, debe verificar self.searchDisplayController.active y usar self.searchDisplayController.searchResultsTableView lugar de self.tableView . De lo contrario, obtendrá resultados inesperados cuando SearchDisplayController esté activo, especialmente cuando se desplazan los resultados de la búsqueda.

Por ejemplo:

 - (void) accessoryButtonTapped:(UIControl *)button withEvent:(UIEvent *)event { UITableView* tableView = self.tableView; if(self.searchDisplayController.active) tableView = self.searchDisplayController.searchResultsTableView; NSIndexPath * indexPath = [tableView indexPathForRowAtPoint:[[[event touchesForView:button] anyObject] locationInView:tableView]]; if(indexPath) [tableView.delegate tableView:tableView accessoryButtonTappedForRowWithIndexPath:indexPath]; } 
  1. Defina una macro para tags de botones:

     #define AccessoryViewTagSinceValue 100000 // (AccessoryViewTagSinceValue * sections + rows) must be LE NSIntegerMax 
  2. Crear botón y establecer cell.accessoryView al crear una celda

     UIButton *accessoryButton = [UIButton buttonWithType:UIButtonTypeContactAdd]; accessoryButton.frame = CGRectMake(0, 0, 30, 30); [accessoryButton addTarget:self action:@selector(accessoryButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; cell.accessoryView = accessoryButton; 
  3. Establezca cell.accessoryView.tag por indexPath en el método UITableViewDataSource -tableView: cellForRowAtIndexPath:

     cell.accessoryView.tag = indexPath.section * AccessoryViewTagSinceValue + indexPath.row; 
  4. Manejador de eventos para botones

     - (void) accessoryButtonTapped:(UIButton *)button { NSIndexPath *indexPath = [NSIndexPath indexPathForRow:button.tag % AccessoryViewTagSinceValue inSection:button.tag / AccessoryViewTagSinceValue]; [self.tableView.delegate tableView:self.tableView accessoryButtonTappedForRowWithIndexPath:indexPath]; } 
  5. Implementar el método UITableViewDelegate

     - (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath { // do sth. } 

Cuando se toca el botón, puede hacer que llame al siguiente método dentro de una subclase UITableViewCell

  -(void)buttonTapped{ // perform an UI updates for cell // grab the table view and notify it using the delegate UITableView *tableView = (UITableView *)self.superview; [tableView.delegate tableView:tableView accessoryButtonTappedForRowWithIndexPath:[tableView indexPathForCell:self]]; } 

Con el enfoque yanchenko, tuve que agregar: [accBtn setFrame:CGRectMake(0, 0, 20, 20)];

Si está utilizando un archivo xib para personalizar su TableCell, entonces initWithStyle: reuseIdentifier: no se llamará.

En lugar de anular:

 -(void)awakeFromNib { //Put your code here [super awakeFromNib]; } 

Debe usar un UIControl para obtener el despacho del evento adecuadamente (por ejemplo, un UIButton ) en lugar del simple UIView/UIImageView .

A partir de iOS 3.2 puedes evitar los botones que otros aquí están recomendando y en su lugar usar tu UIImageView con un reconocedor de gestos de toque. Asegúrese de habilitar la interacción del usuario, que está desactivada por defecto en UIImageViews.