Obtener una fila de celda UITableView al presionar el botón

84

Tengo un controlador de vista de tabla que muestra una fila de celdas. Cada celda tiene 3 botones. He numerado las etiquetas de cada celda para que sean 1,2,3. El problema es que no sé cómo encontrar en qué celda se presiona un botón. Actualmente, solo obtengo la etiqueta del remitente cuando se presiona uno de los botones. ¿Hay alguna forma de obtener el número de fila de celda también cuando se presiona un botón?

minimalpop
fuente

Respuestas:

278

En su lugar, debería utilizar este método:

CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonPosition];

Versión rápida:

let buttonPosition = sender.convert(CGPoint(), to:tableView)
let indexPath = tableView.indexPathForRow(at:buttonPosition)

Eso le dará el indexPathbasado en la posición del botón que se presionó. Entonces simplemente llamaría cellForRowAtIndexPathsi necesita el celular o indexPath.rowsi necesita el número de fila.

Si está paranoico, puede comprobarlo if (indexPath) ...antes de usarlo en caso de indexPathque no se encuentre para ese punto en la vista de tabla.

Es probable que todas las demás respuestas se rompan si Apple decide cambiar la estructura de la vista.

Me han robado
fuente
8
esto, un millón de veces. ninguno de los otros funcionó, pero esto fue perfecto y, con mucho, la solución más simple
ine
2
Esta respuesta funciona porque es la solución correcta . Los otros son soluciones alternativas. ¡Gracias!
Bruno Philipe
1
En caso de que no tenga self.tableview , consulte mi respuesta en esta página.
Ashok
1
Esto funcionó para mí una vez que me di cuenta de que mi remitente era de la clase equivocada. Se corrigió para que se presionara el botón UIB, ¡y ahora está funcionando!
lordB8r
1
solo recuerda que el método convertPoint:*to*Viewno lo es convertPoint:*from*View. Usé el autocompletado de Xcode y terminé con el método fromView que solo llevó a que no funcionara ...
tGilani
40

Editar: esta respuesta está desactualizada. Utilice este método en su lugar


Prueba esto:

-(void)button1Tapped:(id)sender
{
    UIButton *senderButton = (UIButton *)sender;
    UITableViewCell *buttonCell = (UITableViewCell *)[senderButton superview];
    UITableView* table = (UITableView *)[buttonCell superview];
    NSIndexPath* pathOfTheCell = [table indexPathForCell:buttonCell];
    NSInteger rowOfTheCell = [pathOfTheCell row];
    NSLog(@"rowofthecell %d", rowOfTheCell);
}

Editar: si está usando contentView, use esto para buttonCell en su lugar:

UITableViewCell *buttonCell = (UITableViewCell *)senderButton.superview.superview;
usuario523234
fuente
1
No se supone que debe agregar subvistas a la celda en sí, sino solo a su contentViewpropiedad, por lo que esta solución realmente no funciona.
1
Estoy de acuerdo con @ H2CO3 y tampoco creo que esto deba hacerse haciendo referencia a las supervistas. Vea una mejor manera a continuación: stackoverflow.com/a/16270198/308315
iwasrobbed
@minimalpop, ¿puedes cambiar la respuesta correcta? para tener una mejor Q / A!
Thomas Besnehard
Esto no funciona en iOS 7. Use indexPathForRowAtPoint: respuesta a continuación
Austin
Probé la misma versión con un UICollectionView y funciona perfectamente. ¡Muchas gracias!
Claus
18

Recomendaría esta forma de obtener indexPath de la celda que tiene una subvista personalizada ( compatible con iOS 7 y todas las versiones anteriores )

-(void)button1Tapped:(id)sender {
//- (void)cellSubviewTapped:(UIGestureRecognizer *)gestureRecognizer {
//    UIView *parentCell = gestureRecognizer.view.superview;
    UIView *parentCell = sender.superview;

    while (![parentCell isKindOfClass:[UITableViewCell class]]) {   // iOS 7 onwards the table cell hierachy has changed.
        parentCell = parentCell.superview;
    }

    UIView *parentView = parentCell.superview;

    while (![parentView isKindOfClass:[UITableView class]]) {   // iOS 7 onwards the table cell hierachy has changed.
        parentView = parentView.superview;
    }


    UITableView *tableView = (UITableView *)parentView;
    NSIndexPath *indexPath = [tableView indexPathForCell:(UITableViewCell *)parentCell];

    NSLog(@"indexPath = %@", indexPath);
}

Esto tampoco requiere self.tablview.

Además, observe el código comentado que es útil si desea lo mismo a través de un @selector de UIGestureRecognizer agregado a su subvista personalizada.

Ashok
fuente
¿Y si necesito datos que se encuentren en uitableviewcontroller?
iosMentalist
Buena respuesta. Si tiene una barra de búsqueda y le gustaría saber qué tabla se usa en este momento, también puede usarla.
Suraj K Thomas
¿Cambió la jerarquía de celdas de la tabla? ¿Puede ayudarme a comprender qué cambios se han producido y se pueden cambiar más?
Kamaldeep singh Bhatia
3

Hay dos maneras:

  1. @ H2CO3 tiene razón. Puede hacer lo que sugirió @ user523234, pero con un pequeño cambio, para respetar el UITableViewCellContentView que debería estar entre UIButton y UITableViewCell. Entonces, para modificar su código:

    - (IBAction)button1Tapped:(id)sender
    {
        UIButton *senderButton = (UIButton *)sender;
        UITableViewCellContentView *cellContentView = (UITableViewCellContentView *)senderButton.superview;
        UITableViewCell *tableViewCell = (UITableViewCell *)cellContentView.superview;
        UITableView* tableView = (UITableView *)tableViewCell.superview;
        NSIndexPath* pathOfTheCell = [tableView indexPathForCell:tableViewCell];
        NSInteger rowOfTheCell = pathOfTheCell.row;
        NSLog(@"rowofthecell %d", rowOfTheCell);
    }
    
  2. Si crea una UITableViewCell personalizada (su propia subclase), simplemente puede llamar selfa IBAction. Puede vincular la función IBAction a su botón utilizando un guión gráfico o mediante programación cuando configure la celda.

    - (IBAction)button1Tapped:(id)sender
    {
        UITableView* tableView = (UITableView *)self.superview;
        NSIndexPath* pathOfTheCell = [tableView indexPathForCell:self];
        NSInteger rowOfTheCell = pathOfTheCell.row;
        NSLog(@"rowofthecell %d", rowOfTheCell);
    }
    
Sr. T
fuente
2

Supongo que agrega botones a la celda cellForRowAtIndexPath, luego lo que haría es crear una subclase de clase personalizada UIButton, agregar una etiqueta llamada rowNumbery agregar esos datos mientras agrega un botón a la celda.

Derek Li
fuente
3
Esto está bien, pero no hay razón para crear una subclase UIButtonpara ello. tages una propiedad común de UIView.
Rob Napier
No sé en qué estaba pensando y asumir la interfaz de usuario algo que no es una interfaz de usuario , gracias por la corrección!
Derek Li
2

Otra forma sencilla:

  • Obtenga el punto de contacto en tableView

  • Luego obtenga la ruta del índice de la celda en el punto

  • La ruta del índice contiene el índice de la fila

El codigo es:

- (void)buttonTapped:(id)sender {
    UITapGestureRecognizer *tap = (UITapGestureRecognizer *)sender;
    CGPoint point = [tap locationInView:theTableView];

    NSIndexPath *theIndexPath = [theTableView indexPathForRowAtPoint:point];

    NSInteger theRowIndex = theIndexPath.row;
    // do your stuff here
    // ...
}
vietstone
fuente
1

Swift 3

Nota: Esto realmente debería ir en la respuesta aceptada anterior, excepto que meta frunce el ceño ante tales ediciones.

@IBAction func doSomething(_ sender: UIButton) {
   let buttonPosition = sender.convert(CGPoint(), to: tableView)
   let index = tableView.indexPathForRow(at: buttonPosition)
}

Dos comentarios menores:

  1. La función predeterminada tiene el tipo de remitente como Cualquiera, que no tiene conversión.
  2. CGPointZero puede ser reemplazado por CGPoint ()
Roy Falk
fuente
Funciona perfectamente.
0

Una solución podría ser verificar la etiqueta de la supervista del botón o incluso más arriba en la jerarquía de vista (si el botón está en la vista de contenido de la celda).

Jakob W
fuente
0

Me gustaría compartir el código en rápido.

extension UITableView
{
    func indexPathForCellContainingView(view1:UIView?)->NSIndexPath?
    {
        var view = view1;
        while view != nil {
            if (view?.isKindOfClass(UITableViewCell) == true)
            {
                return self.indexPathForCell(view as! UITableViewCell)!
            }
            else
            {
                view = view?.superview;
            }
        }
        return nil
    }
}
Anupam Mishra
fuente
0

En rápido:

@IBAction func buttonAction(_ sender: UIButton) {
    guard let indexPath = tableView.indexPathForRow(at: sender.convert(CGPoint(), to: tableView)) else {
        return
    }
    // do something
}
Leszek Szary
fuente