2009-05-15 10 views
136

Estoy usando un UITableViewCell dibujado a medida, que incluye el mismo para el accessoryView de la celda. Mi configuración para el accessoryView pasa por el camino de algo como esto:Usando una imagen personalizada para un accesorioView de UITableViewCell y haciendo que responda a UITableViewDelegate

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 se inicializa el celular, utilizando initWithFrame:reuseIdentifier: me aseguré para establecer la siguiente propiedad:

self.userInteractionEnabled = YES; 

Desafortunadamente en mi UITableViewDelegate, mi método tableView:accessoryButtonTappedForRowWithIndexPath: (intente repetirlo 10 veces) no se activa. El delegado definitivamente está cableado correctamente.

¿Qué puede faltar?

Gracias a todos.

Respuesta

226

Lamentablemente, ese método no se invoca a menos que se toque el tipo de botón interno proporcionado cuando utiliza uno de los tipos predefinidos. Para usar el suyo, deberá crear su accesorio como un botón u otra subclase de 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 ligeramente, para que coincida con nuestra coloración verde azulado) que terminé haciendo mi propia subclase UITableViewController para mantener el código de utilidad para todas las demás vistas de tabla para usar (ahora subclases OPTableViewController).

En primer lugar, esta función devuelve un nuevo botón detalle divulgación 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é hecho, que a su vez alimenta la rutina UITableViewDelegate estándar para los 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.

+0

Gracias Jim. Es una pena que haya pasado más de 20 minutos preguntándome por qué no puedo hacerlo con un imageView personalizado. Acabo de ver cómo hacerlo en la aplicación de accesorios de muestra de Apple. Su respuesta está bien explicada y documentada, así que la estoy marcando y manteniéndola. Gracias de nuevo. :-) –

+0

¡Esta solución es genial! +1 –

+11

Solo para otras personas que miren esta respuesta, también pueden poner una etiqueta en el botón que corresponde a la fila (si tiene varias secciones, necesitarán hacer algunos cálculos) y luego simplemente sacar la etiqueta de el botón en la función. Creo que podría ser un poco más rápido que calcular el toque. – RyanJM

1

Debe utilizar un UIControl para obtener correctamente el envío del evento (por ejemplo, UIButton) en lugar de simplemente UIView/UIImageView.

75

me encontré con este sitio web a ser muy útil: custom accessory view for your uitableview in iphone

En resumen, utilizar 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; 

a continuación, poner en práctica 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]; 
    } 
} 
+3

¡Gracias! ¡Esto lo hizo por mí! – Marius

+4

Diría +1 por esto, ya que es lo que Apple recomienda hacer en su código de muestra en sus documentos: http://developer.apple.com/library/ios/#samplecode/Accessory/Listings/MyTableViewController_m.html#// apple_ref/doc/uid/DTS40008066-MyTableViewController_m-DontLinkElementID_6 – cleverbit

+0

Configurar el marco fue la pieza que me faltaba. También puede establecer la imagen (en lugar del fondo) siempre que no desee ningún texto. –

7

Mi enfoque es para crear una subclase UITableViewCell y encapsular la lógica que llamará al método habitual 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 
+0

Esta es la MEJOR respuesta. Pero 'button.superview',' cell.superview' y '[tableView.delegate tableView: ...]' no son lo suficientemente seguros. – iwill

1

Con Yanchenko enfoque he tenido que añadir: [accBtn setFrame:CGRectMake(0, 0, 20, 20)];

Si está usando el archivo xib para personalizar su TableCell continuación initWithStyle: reuseIdentifier: suele ser llamado.

lugar anular:

-(void)awakeFromNib 
{ 
//Put your code here 

[super awakeFromNib]; 

} 
2
  1. definir una macro para las etiquetas de los botones:

    #define AccessoryViewTagSinceValue 100000 // (AccessoryViewTagSinceValue * sections + rows) must be LE NSIntegerMax 
    
  2. botón Crear y configurar el cell.accessoryView al crear una célula

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

    cell.accessoryView.tag = indexPath.section * AccessoryViewTagSinceValue + indexPath.row; 
    
  4. Controlador de eventos para los 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. 
    } 
    
+0

Nadie debería usar 'tag' salvo que sea absolutamente necesario, busque otra solución. – Lifely

2

Cuando se toca el botón, se puede D tienen que llamar 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]]; 

} 
3

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

Tenga cuidado cuando se utiliza un UISearchBarController con su UITableView. En ese caso, debe verificar self.searchDisplayController.active y usar self.searchDisplayController.searchResultsTableView en 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]; 
} 
0

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

Cuestiones relacionadas