ios objective-c uitableview uibutton

ios - Haz clic en el botón dentro de UITableViewCell



objective-c uibutton (14)

Tengo un controlador de vista con una vista de tabla y una punta separada para la plantilla de celda de tabla. La plantilla de celda tiene algunos botones. Quiero acceder al botón hacer clic junto con el índice de la celda que se hizo clic dentro del controlador de vista donde he definido la vista de tabla.

Así que tengo ViewController.h ViewController.m donde tengo UITableView y TableTemplate.h , TableTemplate.m y TableTemplate.xib donde tengo el plumín definido. Quiero que el botón haga clic en evento con índice de celda en ViewController.m .

¿Alguna ayuda sobre cómo puedo hacer eso?


Swift 2.2

Necesita agregar un objetivo para ese botón.

myButton.addTarget(self, action: #selector(ClassName.FunctionName(_:), forControlEvents: .TouchUpInside)

Nombre de la función: conectado // por ejemplo

Y, por supuesto, debe establecer la etiqueta de ese botón, ya que lo está usando.

myButton.tag = indexPath.row

Puede lograr esto subclasificando UITableViewCell. Úselo en el constructor de interfaz, suelte un botón en esa celda, conéctelo a través de la toma de corriente y listo.

Para obtener la etiqueta en la función conectada:

func connected(sender: UIButton) { let buttonTag = sender.tag // Do any additional setup }


1) En su método cellForRowAtIndexPath: asigne la etiqueta del botón como índice:

cell.yourbutton.tag = indexPath.row;

2) Agregue el objetivo y la acción para su botón de la siguiente manera:

[cell.yourbutton addTarget:self action:@selector(yourButtonClicked:) forControlEvents:UIControlEventTouchUpInside];

3) Codifique acciones basadas en el índice como se muestra a continuación en ViewControler :

-(void)yourButtonClicked:(UIButton*)sender { if (sender.tag == 0) { // Your code here } }

Actualizaciones para la Sección múltiple:

Puede consultar este enlace para detectar el clic del botón en la vista de tabla para varias filas y secciones.


CustomTableCell.h es una UITableViewCell:

@property (weak, nonatomic) IBOutlet UIButton *action1Button; @property (weak, nonatomic) IBOutlet UIButton *action2Button;

MyVC.m después de las importaciones:

@interface MYTapGestureRecognizer : UITapGestureRecognizer @property (nonatomic) NSInteger dataint; @end

Dentro de "cellForRowAtIndexPath" en MyVC.m:

//CustomTableCell CustomTableCell *cell = (CustomTableCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath]; //Set title buttons [cell.action1Button setTitle:[NSString stringWithString:NSLocalizedString(@"action1", nil)] forState:UIControlStateNormal]; [cell.action2Button setTitle:[NSString stringWithString:NSLocalizedString(@"action2", nil)] forState:UIControlStateNormal]; //Set visibility buttons [cell.action1Button setHidden:FALSE]; [cell.action2Button setHidden:FALSE]; //Do 1 action [cell.action1Button addTarget:self action:@selector(do1Action :) forControlEvents:UIControlEventTouchUpInside]; //Do 2 action MYTapGestureRecognizer *action2Tap = [[MYTapGestureRecognizer alloc] initWithTarget:self action:@selector(do2Action :)]; cancelTap.numberOfTapsRequired = 1; cancelTap.dataint = indexPath.row; [cell.action2Button setUserInteractionEnabled:YES]; [cell.action2Button addGestureRecognizer:action2Tap];

MyVC.m:

-(void)do1Action :(id)sender{ //do some action that is not necessary fr data } -(void)do2Action :(UITapGestureRecognizer *)tapRecognizer{ MYTapGestureRecognizer *tap = (MYTapGestureRecognizer *)tapRecognizer; numberTag = tap.dataint; FriendRequest *fr = [_list objectAtIndex:numberTag]; //connect with a WS o do some action with fr data //actualize list in tableView [self.myTableView reloadData]; }


El código de Tarun no funciona en iOS7, ya que la estructura UITableViewCell cambió y ahora obtendría "UITableViewCellScrollView" en su lugar.

Esta publicación Obtener UITableViewCell con supervista en iOS 7 tiene una buena solución para crear un bucle para encontrar la vista principal correcta, independientemente de cualquier cambio futuro en la estructura. Todo se reduce a crear un bucle:

UIView *superView = [sender superview]; UIView *foundSuperView = nil; while (nil != superView && nil == foundSuperView) { if ([superView isKindOfClass:[UITableViewCell class]]) { foundSuperView = superView; } else { superView = superView.superview; } }

El enlace tiene código para una solución más reutilizable, pero esto debería funcionar.


El siguiente código puede ayudarte.

He tomado UITableView con una clase de celda de prototipo personalizada llamada UITableViewCell dentro de UIViewController .

Así que tengo ViewController.h , ViewController.m y TableViewCell.h , TableViewCell.m

Aquí está el código para eso:

ViewController.h

@interface ViewController : UIViewController<UITableViewDataSource,UITableViewDelegate> @property (strong, nonatomic) IBOutlet UITableView *tblView; @end

ViewController.m

@interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return (YourNumberOfRows); } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ static NSString *cellIdentifier = @"cell"; __weak TableViewCell *cell = (TableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath]; if (indexPath.row==0) { [cell setDidTapButtonBlock:^(id sender) { // Your code here }]; } return cell; }

Clase de celda personalizada

TableViewCell.h @interface TableViewCell : UITableViewCell @property (copy, nonatomic) void (^didTapButtonBlock)(id sender); @property (strong, nonatomic) IBOutlet UILabel *lblTitle; @property (strong, nonatomic) IBOutlet UIButton *btnAction; - (void)setDidTapButtonBlock:(void (^)(id sender))didTapButtonBlock; @end

y

UITableViewCell.m @implementation TableViewCell - (void)awakeFromNib { // Initialization code [self.btnAction addTarget:self action:@selector(didTapButton:) forControlEvents:UIControlEventTouchUpInside]; } - (void)setSelected:(BOOL)selected animated:(BOOL)animated { [super setSelected:selected animated:animated]; // Configure the view for the selected state } - (void)didTapButton:(id)sender { if (self.didTapButtonBlock) { self.didTapButtonBlock(sender); } }

Nota : Aquí he tomado todos los UIControls usando Storyboard.

Espero que pueda ayudarte ... !!!


En lugar de jugar con las etiquetas, tomé un enfoque diferente. Made delegado para mi subclase de UITableViewCell (OptionButtonsCell) y agregué una var de indexPath. Desde mi botón en el guión gráfico conecté @IBAction con OptionButtonsCell y allí envío el método delegate con el indexPath correcto a cualquier persona interesada. En la celda para la ruta del índice, establezco el indexPath actual y funciona :)

Deje que el código hable por sí mismo:

Swift 3 Xcode 8

OptionButtonsTableViewCell.swift

import UIKit protocol OptionButtonsDelegate{ func closeFriendsTapped(at index:IndexPath) } class OptionButtonsTableViewCell: UITableViewCell { var delegate:OptionButtonsDelegate! @IBOutlet weak var closeFriendsBtn: UIButton! var indexPath:IndexPath! @IBAction func closeFriendsAction(_ sender: UIButton) { self.delegate?.closeFriendsTapped(at: indexPath) } }

MyTableViewController.swift

class MyTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, OptionButtonsDelegate {... func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "optionCell") as! OptionButtonsTableViewCell cell.delegate = self cell.indexPath = indexPath return cell } func closeFriendsTapped(at index: IndexPath) { print("button tapped at index:/(index)") }


Encuentro más simple subclasificar el botón dentro de su celda (Swift 3):

class MyCellInfoButton: UIButton { var indexPath: IndexPath? }

En tu clase celular:

class MyCell: UICollectionViewCell { @IBOutlet weak var infoButton: MyCellInfoButton! ... }

En la fuente de datos de la vista de tabla o de la vista de colección, al quitar la secuencia de la celda, otorgue al botón su ruta de índice:

cell.infoButton.indexPath = indexPath

Entonces puede poner estos códigos en su controlador de vista de tabla:

@IBAction func handleTapOnCellInfoButton(_ sender: MyCellInfoButton) { print(sender.indexPath!) // Do whatever you want with the index path! }

Y no olvides configurar la clase del botón en tu Interface Builder y vincularlo a la función handleTapOnCellInfoButton .

editado:

Usando inyección de dependencia. Para configurar una llamada a un cierre:

class MyCell: UICollectionViewCell { var someFunction: (() -> Void)? ... @IBAction func didTapInfoButton() { someFunction?() } }

e inyecte el cierre en el método willDisplay del delegado de la vista de colección:

func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { (cell as? MyCell)?.someFunction = { print(indexPath) // Do something with the indexPath. } }


Esto debería ayudar:

UITableViewCell* cell = (UITableViewCell*)[sender superview]; NSIndexPath* indexPath = [myTableView indexPathForCell:cell];

Aquí el remitente es la instancia de UIButton que está enviando el evento. myTableView es la instancia de UITableView con la que está tratando.

Simplemente obtenga la referencia de la celda correcta y todo el trabajo está hecho.

Es posible que necesite quitar los botones del contenido de la celda y agregarlos directamente a la instancia de UITableViewCell como subvista.

O

Puede formular un esquema de denominación de etiquetas para diferentes UIButtons en cell.contentView. Con esta etiqueta, más adelante puede conocer la información de la fila y la sección según sea necesario.


La razón por la que me gusta la técnica de abajo porque también me ayuda a identificar la sección de la tabla.

Botón Agregar en cell cellForRowAtIndexPath:

UIButton *selectTaskBtn = [UIButton buttonWithType:UIButtonTypeCustom]; [selectTaskBtn setFrame:CGRectMake(15, 5, 30, 30.0)]; [selectTaskBtn setTag:indexPath.section]; //Not required but may find useful if you need only section or row (indexpath.row) as suggested by MR.Tarun [selectTaskBtn addTarget:self action:@selector(addTask:) forControlEvents:UIControlEventTouchDown]; [cell addsubview: selectTaskBtn];

Evento addTask:

-(void)addTask:(UIButton*)btn { CGPoint buttonPosition = [btn convertPoint:CGPointZero toView:self.tableView]; NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonPosition]; if (indexPath != nil) { int currentIndex = indexPath.row; int tableSection = indexPath.section; } }

Espera esta ayuda.


La respuesta de @Mani es buena, sin embargo, las etiquetas de vistas dentro del contenido de la celda a menudo se usan para otros fines. Puede usar la etiqueta de la celda en su lugar (o la etiqueta contentView de la celda):

1) En su método cellForRowAtIndexPath: asigne la etiqueta de la celda como índice:

cell.tag = indexPath.row; // or cell.contentView.tag...

2) Agregue el objetivo y la acción para su botón de la siguiente manera:

[cell.yourbutton addTarget:self action:@selector(yourButtonClicked:) forControlEvents:UIControlEventTouchUpInside];

3) Crear método que devuelva la fila del remitente (gracias @Stenio Ferreira):

- (NSInteger)rowOfSender:(id)sender { UIView *superView = sender.superview; while (superView) { if ([superView isKindOfClass:[UITableViewCell class]]) break; else superView = superView.superview; } return superView.tag; }

4) Acciones de código basadas en el índice:

-(void)yourButtonClicked:(UIButton*)sender { NSInteger index = [self rowOfSender:sender]; // Your code here }


Los delegados son el camino a seguir.

Como se ve con otras respuestas que usan vistas, pueden quedar obsoletas. Quién sabe mañana podría haber otra envoltura y puede necesitar usar cell superview]superview]superview]superview] . Y si usa etiquetas, terminaría con n número de condiciones if else para identificar la celda. Para evitar todos los delegados configurados. (Al hacerlo, creará una clase de celda reutilizable. Puede usar la misma clase de celda que una clase base y todo lo que tiene que hacer es implementar los métodos de delegado).

Primero, necesitamos una interfaz (protocolo) que será utilizada por la célula para comunicar (delegar) los clics del botón. ( Puede crear un archivo .h separado para el protocolo e incluirlo tanto en el controlador de vista de tabla como en las clases de celda personalizadas o simplemente agregarlo en una clase de celda personalizada que de todos modos se incluirá en el controlador de vista de tabla )

@protocol CellDelegate <NSObject> - (void)didClickOnCellAtIndex:(NSInteger)cellIndex withData:(id)data; @end

Incluya este protocolo en la celda personalizada y el controlador de vista de tabla. Y asegúrese de que el controlador de vista de tabla confirme a este protocolo.

En la celda personalizada crea dos propiedades:

@property (weak, nonatomic) id<CellDelegate>delegate; @property (assign, nonatomic) NSInteger cellIndex;

En UIButton IBAction delegado haga clic en: ( Lo mismo se puede hacer para cualquier acción en la clase de celda personalizada que necesita ser delegada de nuevo para ver el controlador )

- (IBAction)buttonClicked:(UIButton *)sender { if (self.delegate && [self.delegate respondsToSelector:@selector(didClickOnCellAtIndex:withData:)]) { [self.delegate didClickOnCellAtIndex:_cellIndex withData:@"any other cell data/property"]; } }

En el controlador de vista de tabla cellForRowAtIndexPath después de dequeing the cell, configure las propiedades anteriores.

cell.delegate = self; cell.cellIndex = indexPath.row; // Set indexpath if its a grouped table.

E implemente el delegado en el controlador de vista de tabla:

- (void)didClickOnCellAtIndex:(NSInteger)cellIndex withData:(id)data { // Do additional actions as required. NSLog(@"Cell at Index: %d clicked./n Data received : %@", cellIndex, data); }

Este sería el enfoque ideal para obtener acciones de botón de celda personalizadas en el controlador de vista de tabla.


Swift 3 con cierre

Una buena solución es usar un cierre en una UITableViewCell personalizada para devolver una llamada al viewController para una acción.

En la celda:

final class YourCustomCell: UITableViewCell { var callbackClosure: (() -> Void)? // Configure the cell here func configure(object: Object, callbackClosure: (() -> Void)?) { self.callbackClosure = callbackClosure } // MARK: - IBAction extension YourCustomCell { @IBAction fileprivate func actionPressed(_ sender: Any) { guard let closure = callbackClosure else { return } closure() } }

En View Controller: Tableview Delegate

extension YourViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { guard let cell: YourCustomCell = cell as? YourCustomCell else { return } cell.configure(object: object, callbackClosure: { [weak self] in self?.buttonAction() }) } } fileprivate extension YourViewController { func buttonAction() { // do your actions here } }


// Add action in cell for row at index path -tableView cell.buttonName.addTarget(self, action: #selector(ViewController.btnAction(_:)), for: .touchUpInside) // Button Action @objc func btnAction(_ sender: AnyObject) { var position: CGPoint = sender.convert(.zero, to: self.tableView) let indexPath = self.tableView.indexPathForRow(at: position) let cell: UITableViewCell = tableView.cellForRow(at: indexPath!)! as UITableViewCell }


cell.show.tag=indexPath.row; [cell.show addTarget:self action:@selector(showdata:) forControlEvents:UIControlEventTouchUpInside]; -(IBAction)showdata:(id)sender { UIButton *button = (UIButton *)sender; UIStoryboard *storyBoard; storyBoard = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; SecondViewController *detailView = [storyBoard instantiateViewControllerWithIdentifier:@"SecondViewController"]; detailView.string=[NSString stringWithFormat:@"%@",[_array objectAtIndex:button.tag]]; [self presentViewController:detailView animated:YES completion:nil]; }