Detectar qué UIButton se presionó en un UITableView


Tengo un UITableView con 5 UITableViewCells. Cada celda contiene un UIButton que se configura de la siguiente manera:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
     NSString *identifier = @"identifier";
     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
     if (cell == nil) {
         cell = [[UITableView alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
         [cell autorelelase];

         UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(10, 5, 40, 20)];
         [button addTarget:self action:@selector(buttonPressedAction:) forControlEvents:UIControlEventTouchUpInside];
         [button setTag:1];
         [cell.contentView addSubview:button];

         [button release];
     }

     UIButton *button = (UIButton *)[cell viewWithTag:1];
     [button setTitle:@"Edit" forState:UIControlStateNormal];

     return cell;
}

Mi pregunta es esta: en el método buttonPressedAction:, cómo sé qué botón se ha presionado. He considerado usar etiquetas, pero no estoy seguro de que esta sea la mejor ruta. Me gustaría poder etiquetar de alguna manera el indexPath en el control.

- (void)buttonPressedAction:(id)sender
{
    UIButton *button = (UIButton *)sender;
    // how do I know which button sent this message?
    // processing button press for this row requires an indexPath. 
}

¿Cuál es la forma estándar de hacer esto?

Editar:

Lo he resuelto haciendo lo siguiente. Todavía me gustaría tener una opinión si esta es la forma estándar de hacerlo o hay una mejor manera?

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
     NSString *identifier = @"identifier";
     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
     if (cell == nil) {
         cell = [[UITableView alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
         [cell autorelelase];

         UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(10, 5, 40, 20)];
         [button addTarget:self action:@selector(buttonPressedAction:) forControlEvents:UIControlEventTouchUpInside];
         [cell.contentView addSubview:button];

         [button release];
     }

     UIButton *button = (UIButton *)[cell.contentView.subviews objectAtIndex:0];
     [button setTag:indexPath.row];
     [button setTitle:@"Edit" forState:UIControlStateNormal];

     return cell;
}

- (void)buttonPressedAction:(id)sender
{
    UIButton *button = (UIButton *)sender;
    int row = button.tag;
}

Lo que es importante tener en cuenta es que no puedo establecer la etiqueta en la creación de la celda, ya que la celda podría ser dequeued en su lugar. Se siente muy sucio. Debe haber una manera mejor.

Author: Paras Joshi, 2009-11-26

26 answers

En la muestra del accesorio de Apple se utiliza el siguiente método:

[button addTarget:self action:@selector(checkButtonTapped:) forControlEvents:UIControlEventTouchUpInside];

Luego, en touch handler, se recupera la coordenada táctil y la ruta del índice se calcula a partir de esa coordenada:

- (void)checkButtonTapped:(id)sender
{
    CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.tableView];
    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonPosition];
    if (indexPath != nil)
    {
     ...
    }
}
 390
Author: Vladimir,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-29 13:39:14

Encontré que el método de usar el superview de superview para obtener una referencia al indexPath de la celda funcionó perfectamente. Gracias a iphonedevbook.com (macnsmith) para la punta texto de enlace

-(void)buttonPressed:(id)sender {
 UITableViewCell *clickedCell = (UITableViewCell *)[[sender superview] superview];
 NSIndexPath *clickedButtonPath = [self.tableView indexPathForCell:clickedCell];
...

}
 48
Author: Cocoanut,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-06 02:54:37

Así es como lo hago. Simple y conciso:

- (IBAction)buttonTappedAction:(id)sender
{
    CGPoint buttonPosition = [sender convertPoint:CGPointZero
                                           toView:self.tableView];
    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonPosition];
    ...
 43
Author: Chris Schwerdt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-30 10:33:52

Encontró una buena solución a este problema en otro lugar, sin jugar con las etiquetas en el botón:

- (void)buttonPressedAction:(id)sender {

NSSet *touches = [event allTouches];
UITouch *touch = [touches anyObject];
CGPoint currentTouchPosition = [touch locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint: currentTouchPosition];

do stuff with the indexPath...
}
 6
Author: Alpinista,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-10 23:32:15

Qué tal enviar la información como NSIndexPath en el UIButton usando inyección de tiempo de ejecución.

1) Necesita tiempo de ejecución en la importación

2) añadir constante estática

3) agregue NSIndexPath a su botón en tiempo de ejecución usando:

(void) setMetadata: (id)target withObject: (id)newObj

4) al presionar el botón obtener metadatos usando:

(id) Metadatos: (id)target

Disfruta

    #import <objc/runtime.h>
    static char const * const kMetaDic = "kMetaDic";


    #pragma mark - Getters / Setters

- (id)metaData:(id)target {
    return objc_getAssociatedObject(target, kMetaDic);
}

- (void)setMetaData:(id)target withObject:(id)newObj {
    objc_setAssociatedObject(target, kMetaDic, newObj, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}



    #On the cell constructor
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
    ....
    cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    ....
    [btnSocial addTarget:self
                                   action:@selector(openComments:)
                         forControlEvents:UIControlEventTouchUpInside];

    #add the indexpath here or another object
    [self setMetaData:btnSocial withObject:indexPath];

    ....
    }



    #The action after button been press:

    - (IBAction)openComments:(UIButton*)sender{

        NSIndexPath *indexPath = [self metaData:sender];
        NSLog(@"indexPath: %d", indexPath.row);

        //Reuse your indexpath Now
    }
 5
Author: magno cardona,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-01 05:00:30
func buttonAction(sender:UIButton!)
    {
        var position: CGPoint = sender.convertPoint(CGPointZero, toView: self.tablevw)
       let indexPath = self.tablevw.indexPathForRowAtPoint(position)
       let cell: TableViewCell = tablevw.cellForRowAtIndexPath(indexPath!) as TableViewCell
        println(indexPath?.row)
        println("Button tapped")
    }
 5
Author: Ankit Bansal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-31 05:58:11

La respuesta de To do (@Vladimir) es Rápida:

var buttonPosition = sender.convertPoint(CGPointZero, toView: self.tableView)
var indexPath = self.tableView.indexPathForRowAtPoint(buttonPosition)!

Aunque buscar indexPath != nil me da el dedo..."NSIndexPath no es un subtipo de NSString"

 5
Author: dennis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-24 16:27:59

Usaría la propiedad tag como dijiste, configurando la etiqueta de esta manera:

[button setTag:indexPath.row];

Luego obtener la etiqueta dentro del buttonPressedAction de la siguiente manera:

((UIButton *)sender).tag

O

UIButton *button = (UIButton *)sender; 
button.tag;
 3
Author: ACBurk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-26 10:16:38

Aunque me gusta la forma de etiqueta... si no quieres usar etiquetas por la razón que sea, puedes crear un miembro NSArray de botones prefabricados:

NSArray* buttons ;

Luego cree esos botones antes de renderizar la vista de tabla y púlselos en la matriz.

Luego dentro de la función tableView:cellForRowAtIndexPath: puedes hacer:

UIButton* button = [buttons objectAtIndex:[indexPath row] ] ;
[cell.contentView addSubview:button];

Entonces en la función buttonPressedAction:, puedes hacer

- (void)buttonPressedAction:(id)sender {
   UIButton* button = (UIButton*)sender ;
   int row = [buttons indexOfObject:button] ;
   // Do magic
}
 3
Author: Eld,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-01 05:00:59

PARA MANEJAR SECCIONES-Almacené el NSIndexPath en un UITableViewCell personalizado

EN CLKIndexPricesHEADERTableViewCell.xib

EN IB Agregue UIButton a XIB - ¡NO agregue acción!

Añadir outlet @ property (retain, nonatomic) IBOutlet UIButton * buttonIndexSectionClose;

NO CTRL + ARRASTRE una acción en IB (hecho en el código a continuación)

@interface CLKIndexPricesHEADERTableViewCell : UITableViewCell
...
@property (retain, nonatomic) IBOutlet UIButton *buttonIndexSectionClose;
@property (nonatomic, retain) NSIndexPath * indexPathForCell;
@end

In viewForHeaderInSection (también debería funcionar para cellForRow.... etc si la tabla tiene solo 1 sección)

- viewForHeaderInSection is called for each section 1...2...3
- get the cell CLKIndexPricesHEADERTableViewCell 
- getTableRowHEADER just does the normal dequeueReusableCellWithIdentifier
- STORE the indexPath IN the UITableView cell
- indexPath.section = (NSInteger)section
- indexPath.row = 0 always (we are only interested in sections)

- (UIView *) tableView:(UITableView *)tableView1 viewForHeaderInSection:(NSInteger)section {


    //Standard method for getting a UITableViewCell
    CLKIndexPricesHEADERTableViewCell * cellHEADER = [self getTableRowHEADER];

...utilice el sección para obtener datos para su celda

...rellenar

   indexName        = ffaIndex.routeCode;
   indexPrice       = ffaIndex.indexValue;

   //

   [cellHEADER.buttonIndexSectionClose addTarget:self
                                          action:@selector(buttonDELETEINDEXPressedAction:forEvent:)
                                forControlEvents:UIControlEventTouchUpInside];


   cellHEADER.indexPathForCell = [NSIndexPath indexPathForRow:0 inSection:section];


    return cellHEADER;
}

EL USUARIO presiona el botón ELIMINAR en un encabezado de sección y esto llama a

- (void)buttonDELETEINDEXPressedAction:(id)sender forEvent:(UIEvent *)event
{
    NSLog(@"%s", __PRETTY_FUNCTION__);


    UIView *  parent1 = [sender superview];   // UiTableViewCellContentView
    //UIView *myContentView = (UIView *)parent1;

    UIView *  parent2 = [parent1 superview];  // custom cell containing the content view
    //UIView *  parent3 = [parent2 superview];  // UITableView containing the cell
    //UIView *  parent4 = [parent3 superview];  // UIView containing the table


    if([parent2 isMemberOfClass:[CLKIndexPricesHEADERTableViewCell class]]){
        CLKIndexPricesHEADERTableViewCell *myTableCell = (CLKIndexPricesHEADERTableViewCell *)parent2;

        //UITableView *myTable = (UITableView *)parent3;
        //UIView *mainView = (UIView *)parent4;

        NSLog(@"%s indexPath.section,row[%d,%d]", __PRETTY_FUNCTION__, myTableCell.indexPathForCell.section,myTableCell.indexPathForCell.row);

        NSString *key = [self.sortedKeysArray objectAtIndex:myTableCell.indexPathForCell.section];
        if(key){
            NSLog(@"%s DELETE object at key:%@", __PRETTY_FUNCTION__,key);
            self.keyForSectionIndexToDelete = key;
            self.sectionIndexToDelete = myTableCell.indexPathForCell.section;

            UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Remove Index"
                                                                message:@"Are you sure"
                                                               delegate:self
                                                      cancelButtonTitle:@"No"
                                                      otherButtonTitles:@"Yes", nil];
            alertView.tag = kALERTVIEW_REMOVE_ONE_INDEX;
            [alertView show];
            [alertView release];
            //------
        }else{
            NSLog(@"ERROR: [%s] key is nil for section:%d", __PRETTY_FUNCTION__,myTableCell.indexPathForCell.section);
        }

    }else{
        NSLog(@"ERROR: [%s] CLKIndexPricesHEADERTableViewCell not found", __PRETTY_FUNCTION__);
    }
}

En este ejemplo he añadido un botón Eliminar por lo que debe mostrar UIAlertView para confirmarlo

Almaceno la sección y la clave en el diccionario almacenando información sobre la sección en un ivar en el VC

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
   if(alertView.tag == kALERTVIEW_REMOVE_ONE_INDEX){
        if(buttonIndex==0){
            //NO
            NSLog(@"[%s] BUTTON:%d", __PRETTY_FUNCTION__,buttonIndex);
            //do nothing
        }
        else if(buttonIndex==1){
            //YES
            NSLog(@"[%s] BUTTON:%d", __PRETTY_FUNCTION__,buttonIndex);
            if(self.keyForSectionIndexToDelete != nil){

                //Remove the section by key
                [self.indexPricesDictionary removeObjectForKey:self.keyForSectionIndexToDelete];

                //sort the keys so sections appear alphabetically/numbericsearch (minus the one we just removed)
                [self updateTheSortedKeysArray];                

                //Delete the section from the table using animation
                [self.tableView beginUpdates];

                [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:self.sectionIndexToDelete]
                              withRowAnimation:UITableViewRowAnimationAutomatic];
                [self.tableView endUpdates];

                //required to trigger refresh of myTableCell.indexPathForCell else old values in UITableViewCells
                [self.tableView reloadData];
            }else{
                NSLog(@"ERROR: [%s] OBJECT is nil", __PRETTY_FUNCTION__);
            }
        }
        else {
            NSLog(@"ERROR: [%s] UNHANDLED BUTTON:%d", __PRETTY_FUNCTION__,buttonIndex);
        }
    }else {
        NSLog(@"ERROR: [%s] unhandled ALERTVIEW TAG:%d", __PRETTY_FUNCTION__,alertView.tag);
    }
}
 2
Author: brian.clear,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-11 14:58:41
A better way would be to subclass your button and add a indexPath property to it.

//Implement a subclass for UIButton.

@interface NewButton:UIButton
@property(nonatomic, strong) NSIndexPath *indexPath;


Make your button of type NewButton in the XIB or in the code whereever you are initializing them.

Then in the cellForRowAtIndexPath put the following line of code.

button.indexPath = indexPath;

return cell; //As usual



Now in your IBAction

-(IBAction)buttonClicked:(id)sender{
   NewButton *button = (NewButton *)sender;

//Now access the indexPath by buttons property..

   NSIndexPath *indexPath = button.indexPath; //:)
}
 2
Author: mmmanishs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-19 08:06:31

Funciona para mí también, Gracias @ Cocoanut

Encontré que el método de usar el superview de superview para obtener una referencia al indexPath de la celda funcionó perfectamente. Gracias a iphonedevbook.com (macnsmith) para el texto de enlace de punta

-(void)buttonPressed:(id)sender {
 UITableViewCell *clickedCell = (UITableViewCell *)[[sender superview] superview];
 NSIndexPath *clickedButtonPath = [self.tableView indexPathForCell:clickedCell];
...

}
 1
Author: user366584,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-07 12:11:17

Puedes usar el patrón de etiquetas:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
     NSString *identifier = @"identifier";
     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
     if (cell == nil) {
         cell = [[UITableView alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
         [cell autorelelase];

         UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(10, 5, 40, 20)];
         [button addTarget:self action:@selector(buttonPressedAction:) forControlEvents:UIControlEventTouchUpInside];
         [button setTag:[indexPath row]]; //use the row as the current tag
         [cell.contentView addSubview:button];

         [button release];
     }

     UIButton *button = (UIButton *)[cell viewWithTag:[indexPath row]]; //use [indexPath row]
     [button setTitle:@"Edit" forState:UIControlStateNormal];

     return cell;
}

- (void)buttonPressedAction:(id)sender
{
    UIButton *button = (UIButton *)sender;
    //button.tag has the row number (you can convert it to indexPath)
}
 0
Author: Nir Levy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-26 10:16:46

¿Me estoy perdiendo algo? ¿No puedes usar el remitente para identificar el botón? El remitente le dará información como esta:

<UIButton: 0x4b95c10; frame = (246 26; 30 30); opaque = NO; tag = 104; layer = <CALayer: 0x4b95be0>>

Luego, si desea cambiar las propiedades del botón, diga la imagen de fondo que solo le dice al remitente:

[sender setBackgroundImage:[UIImage imageNamed:@"new-image.png"] forState:UIControlStateNormal];

Si necesitas la etiqueta entonces el método de ACBurk está bien.

 0
Author: Michael Morrison,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-22 22:48:41
// how do I know which button sent this message?
// processing button press for this row requires an indexPath.

Bastante sencillo en realidad:

- (void)buttonPressedAction:(id)sender
{
    UIButton *button = (UIButton *)sender;
    CGPoint rowButtonCenterInTableView = [[rowButton superview] convertPoint:rowButton.center toView:self.tableView];
    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:rowButtonCenterInTableView];
    MyTableViewItem *rowItem = [self.itemsArray objectAtIndex:indexPath.row];
    // Now you're good to go.. do what the intention of the button is, but with
    // the context of the "row item" that the button belongs to
    [self performFooWithItem:rowItem];
}

Trabajando bien para mí :P

Si desea ajustar la configuración de la acción de destino, puede incluir el parámetro event en el método y, a continuación, utilizar los toques de ese evento para resolver las coordenadas del toque. Las coordenadas aún deben resolverse en los límites de la vista táctil, pero eso puede parecer más fácil para algunas personas.

 0
Author: ohhorob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-14 02:24:02

Cree un array nsmutable y coloque el botón all en ese array usint[array addObject:yourButton];

En el método de pulsación del botón

-

 (void)buttonPressedAction:(id)sender
{
    UIButton *button = (UIButton *)sender;

for(int i=0;i<[yourArray count];i++){

if([buton isEqual:[yourArray objectAtIndex:i]]){

//here write wat u need to do

}
}
 0
Author: rajesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-12-07 10:02:52

Una ligera variación en la respuesta de Cocoanuts (que me ayudó a resolver esto) cuando el botón estaba en el pie de página de una tabla (lo que evita que encuentre la 'celda pulsada':

-(IBAction) buttonAction:(id)sender;
{
    id parent1 = [sender superview];   // UiTableViewCellContentView
    id parent2 = [parent1 superview];  // custom cell containing the content view
    id parent3 = [parent2 superview];  // UITableView containing the cell
    id parent4 = [parent3 superview];  // UIView containing the table

    UIView *myContentView = (UIView *)parent1;
    UITableViewCell *myTableCell = (UITableViewCell *)parent2;
    UITableView *myTable = (UITableView *)parent3;
    UIView *mainView = (UIView *)parent4;

    CGRect footerViewRect = myTableCell.frame;
    CGRect rect3 = [myTable convertRect:footerViewRect toView:mainView];    

    [cc doSomethingOnScreenAtY:rect3.origin.y];
}
 0
Author: software evolved,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-09 16:53:42

Siempre uso etiquetas.

Necesitas subclasificar el UITableviewCell y manejar la presión del botón desde allí.

 0
Author: Chris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-01 05:01:31

Es simple; hacer una celda personalizada y tomar una salida de botón

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
         NSString *identifier = @"identifier";
        customCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];

    cell.yourButton.tag = indexPath.Row;

- (void)buttonPressedAction:(id)sender

Cambie el id en el método anterior a (UIButton *)

Puede obtener el valor que el botón que se está tocando haciendo remitente.etiqueta.

 0
Author: piyush Bageria,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-01 05:02:10

Subclase el botón para almacenar el valor requerido, tal vez crear un protocolo (ControlWithData o algo). Establezca el valor cuando agregue el botón a la celda de la vista de tabla. En tu evento de retoque, comprueba si el remitente obedece el protocolo y extrae los datos. Normalmente almaceno una referencia al objeto real que se representa en la celda de la vista de tabla.

 0
Author: Jerome Chan Yeow Heong,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-06 02:59:31

ACTUALIZACIÓN DE SWIFT 2

Aquí está cómo averiguar qué botón fue pulsado + enviar datos a otro ViewController de ese botón indexPath.row como estoy asumiendo que es el punto para la mayoría!

@IBAction func yourButton(sender: AnyObject) {


     var position: CGPoint = sender.convertPoint(CGPointZero, toView: self.tableView)
        let indexPath = self.tableView.indexPathForRowAtPoint(position)
        let cell: UITableViewCell = tableView.cellForRowAtIndexPath(indexPath!)! as
        UITableViewCell
        print(indexPath?.row)
        print("Tap tap tap tap")

    }

Para aquellos que están usando una clase ViewController y agregaron una tableView, estoy usando un ViewController en lugar de un TableViewController, así que agregué manualmente la tableView para acceder a ella.

Aquí está el código para pasar datos a otro VC al tocar ese botón y pasar la celda indexPath.row

@IBAction func moreInfo(sender: AnyObject) {

    let yourOtherVC = self.storyboard!.instantiateViewControllerWithIdentifier("yourOtherVC") as! YourOtherVCVIewController



    var position: CGPoint = sender.convertPoint(CGPointZero, toView: self.tableView)
    let indexPath = self.tableView.indexPathForRowAtPoint(position)
    let cell: UITableViewCell = tableView.cellForRowAtIndexPath(indexPath!)! as
    UITableViewCell
    print(indexPath?.row)
    print("Button tapped")


    yourOtherVC.yourVarName = [self.otherVCVariable[indexPath!.row]]

    self.presentViewController(yourNewVC, animated: true, completion: nil)

}
 0
Author: lukaivicev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-07 10:21:55

Nota aquí estoy usando una celda personalizada este código funciona perfectamente para mí

 @IBAction func call(sender: UIButton)
    {
        var contentView = sender.superview;
        var cell = contentView?.superview as EmployeeListCustomCell
        if (!(cell.isKindOfClass(EmployeeListCustomCell)))
        {
            cell = (contentView?.superview)?.superview as EmployeeListCustomCell
        }

        let phone = cell.lblDescriptionText.text!
        //let phone = detailObject!.mobile!
        let url:NSURL = NSURL(string:"tel://"+phone)!;
        UIApplication.sharedApplication().openURL(url);
    }
 0
Author: Gaurav,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-18 19:36:01

La solución de Chris Schwerdt pero luego en Swift funcionó para mí:

@IBAction func rateButtonTapped(sender: UIButton) {
    let buttonPosition : CGPoint = sender.convertPoint(CGPointZero, toView: self.ratingTableView)
    let indexPath : NSIndexPath = self.ratingTableView.indexPathForRowAtPoint(buttonPosition)!

    print(sender.tag)
    print(indexPath.row)
}
 0
Author: Rutger Huijsmans,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-17 12:10:18

Este problema tiene dos partes:

1) Obtener la ruta del índice de UITableViewCell que contiene presionado UIButton

Hay algunas sugerencias como:

  • Actualizando UIButton's tag en el método cellForRowAtIndexPath: usando el valor row de la ruta de índice. Esta no es una buena solución ya que requiere actualizar tag continuamente y no funciona con vistas de tabla con más de una sección.

  • Agregar una propiedad NSIndexPath a la celda personalizada y actualizarla en lugar de UIButton's tag en el método cellForRowAtIndexPath:. Esto resuelve el problema de varias secciones, pero todavía no es bueno, ya que requiere una actualización siempre.

  • Mantener una referencia débil a parent UITableView en la celda personalizada mientras la crea y usa el método indexPathForCell: para obtener la ruta del índice. Parece un poco mejor, no hay necesidad de actualizar nada en el método cellForRowAtIndexPath:, pero aún requiere establecer una referencia débil cuando se crea la celda personalizada.

  • Usar la propiedad superView de cell para obtener una referencia al padre UITableView. No es necesario agregar ninguna propiedad a la celda personalizada, y no es necesario establecer/actualizar nada en la creación/más tarde. Pero superView de cell depende de los detalles de la implementación de iOS. Por lo tanto, no se puede utilizar directamente.

Pero esto se puede lograr usando un bucle simple, ya que estamos seguros de que la celda en cuestión tiene que estar en un UITableView:

UIView* view = self;
while (view && ![view isKindOfClass:UITableView.class])
    view = view.superview;
UITableView* parentTableView = (UITableView*)view;

Por lo tanto, estas sugerencias se pueden combinar en un método de celda personalizado simple y seguro para obtener la ruta del índice:

- (NSIndexPath *)indexPath
{
    UIView* view = self;

    while (view && ![view isKindOfClass:UITableView.class])
        view = view.superview;

    return [(UITableView*)view indexPathForCell:self];
}

De ahora en adelante, este método se puede utilizar para detectar que UIButton se presiona.

2) Informar a otras partes sobre el evento de pulsación de botones

Después de saber internamente qué UIButton se presiona en qué celda personalizada con la ruta de índice exacta, esta información debe enviarse a otras partes (lo más probable es que el controlador de vista maneje el UITableView). Por lo tanto, este evento de clic en el botón se puede manejar en un nivel de abstracción y lógica similar al método didSelectRowAtIndexPath: del delegado UITableView.

Dos se pueden utilizar enfoques para esto:

A) Delegación: la celda personalizada puede tener una propiedad delegate y puede definir un protocolo. Cuando se presiona el botón, simplemente realiza sus métodos delegados en su propiedad delegate. Pero esta propiedad delegate debe establecerse para cada celda personalizada cuando se crean. Como alternativa, la celda personalizada también puede elegir realizar sus métodos delegados en su vista de tabla principal delegate.

B) Centro de notificaciones: las celdas personalizadas pueden definir un nombre de notificación personalizado y publique esta notificación con la ruta del índice y la información de la vista de la tabla principal proporcionada en el objeto userInfo. No es necesario establecer nada para cada celda, solo agregar un observador para la notificación de la celda personalizada es suficiente.

 0
Author: erkanyildiz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-27 05:19:55

Utilizo una solución que subclase UIButton y pensé que debería compartirla aquí, códigos en Swift:

class ButtonWithIndexPath : UIButton {
    var indexPath:IndexPath?
}

Luego recuerde actualizar su indexPath en cellForRow(at:)

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let returnCell = tableView.dequeueReusableCell(withIdentifier: "cellWithButton", for: indexPath) as! cellWithButton
    ...
    returnCell.button.indexPath = IndexPath
    returnCell.button.addTarget(self, action:#selector(cellButtonPressed(_:)), for: .touchUpInside)

    return returnCell
}

Así que cuando respondas al evento del botón puedes usarlo como

func cellButtonPressed(_ sender:UIButton) {
    if sender is ButtonWithIndexPath {
        let button = sender as! ButtonWithIndexPath
        print(button.indexPath)
    }
}
 0
Author: Ben Ong,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-24 10:21:30

Con Swift 4.2 e iOS 12, UITableView tiene un método llamado indexPathForRow(at:). indexPathForRow(at:) tiene la siguiente declaración:

func indexPathForRow(at point: CGPoint) -> IndexPath?

Devuelve una ruta de índice que identifica la fila y la sección en el punto dado.


El siguiente código completo muestra cómo implementar indexPathForRow(at:) para obtener el IndexPath correspondiente de a UIButton ubicado en a UITableViewCell:

import UIKit

class CustomCell: UITableViewCell {

    let button = UIButton(type: .system)

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)

        button.setTitle("Tap", for: .normal)
        contentView.addSubview(button)

        button.translatesAutoresizingMaskIntoConstraints = false
        button.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
        button.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
        button.topAnchor.constraintEqualToSystemSpacingBelow(contentView.topAnchor, multiplier: 1).isActive = true
        button.leadingAnchor.constraintGreaterThanOrEqualToSystemSpacingAfter(contentView.leadingAnchor, multiplier: 1).isActive = true
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}
import UIKit

class TableViewController: UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(CustomCell.self, forCellReuseIdentifier: "Cell")
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 3
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CustomCell
        cell.button.addTarget(self, action: #selector(printIndexPath), for: .touchUpInside)
        return cell
    }

    @objc func printIndexPath(_ sender: UIButton) {
        let point = sender.convert(CGPoint.zero, to: tableView)
        guard let indexPath = tableView.indexPathForRow(at: point) else { return }
        print(indexPath)
    }

}
 0
Author: Imanou Petit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-07 21:46:33