ios - Ottieni clic con il pulsante all'interno di UITableViewCell




objective-c uibutton (13)

I delegati sono la strada da percorrere.

Come visto con altre risposte usando le viste potrebbe diventare obsoleto. Chi lo sa che domani potrebbe esserci un altro involucro e potrebbe essere necessario usare cell superview]superview]superview]superview] . E se si utilizzano i tag si finirebbe con n numero di condizioni if ​​else per identificare la cella. Per evitare tutti i delegati impostati. (In questo modo creerai una classe di celle riutilizzabile. Puoi utilizzare la stessa classe di celle di una classe base e tutto ciò che devi fare è implementare i metodi delegati).

Per prima cosa abbiamo bisogno di un'interfaccia (protocollo) che verrà utilizzata dalla cella per comunicare i clic del pulsante (delegato). ( È possibile creare un file .h separato per il protocollo e includerlo nel controller della vista tabella e nelle classi di celle personalizzate OPPURE aggiungerlo in una classe di celle personalizzata che verrà comunque inclusa nel controller di visualizzazione tabella )

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

Includi questo protocollo in un controller di visualizzazione di celle e tabelle personalizzato. E assicurarsi che il controller della vista tabella confermi questo protocollo.

Nella cella personalizzata crea due proprietà:

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

Nel clic del delegato UIButton IBAction: ( Lo stesso può essere fatto per qualsiasi azione nella classe di cella personalizzata che deve essere delegata indietro per visualizzare il controller )

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

Nella vista tabella controller cellForRowAtIndexPath dopo aver desquamato la cella, impostare le proprietà sopra.

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

E implementare il delegato nel controller di visualizzazione tabella:

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

Questo sarebbe l'approccio ideale per ottenere azioni personalizzate dei pulsanti di cella nel controller di visualizzazione tabella.

Ho un controller di visualizzazione con una vista tabella e un pennino separato per il modello di cella di tabella. Il modello di cella ha alcuni pulsanti. Voglio accedere al clic del pulsante insieme all'indice della cella cliccata all'interno del controller della vista dove ho definito la vista Tabella.

Quindi ho TableTemplate.m e TableTemplate.xib dove ho UITableView e TableTemplate.h , TableTemplate.m e TableTemplate.xib dove ho definito il pennino. Voglio l'evento click del pulsante con l'indice delle celle in ViewController.m .

Qualsiasi aiuto su come posso farlo?


Questo dovrebbe aiutare:

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

Qui il mittente è l'istanza UIButton che sta inviando l'evento. myTableView è l'istanza di UITableView con cui hai a che fare.

Ottieni il riferimento alla cella e tutto il lavoro è fatto.

Potrebbe essere necessario rimuovere i pulsanti dal contenuto della cellaViewView e aggiungerli direttamente all'istanza di UITableViewCell come nella sottoview.

O

È possibile formulare uno schema di denominazione dei tag per diversi UIButtons in cell.contentView. Usando questo tag, in seguito puoi conoscere le informazioni su riga e sezione secondo necessità.


Invece di giocare con i tag, ho adottato un approccio diverso. Reso delegato per la mia sottoclasse di UITableViewCell (OptionButtonsCell) e aggiunto una variabile indexPath. Dal mio pulsante nello storyboard ho collegato @IBAction all'OptionButtonsCell e lì mando il metodo delegate con il giusto indexPath a chiunque sia interessato. Nella cella per il percorso dell'indice ho impostato indexPath corrente e funziona :)

Lascia che il codice parli da solo:

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)")
}

// 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




}

La risposta @Mani è buona, tuttavia i tag di visualizzazione all'interno del contenuto della cella spesso vengono utilizzati per altri scopi. Puoi utilizzare il tag della cella (o il tag contentView della cella):

1) Nel tuo cellForRowAtIndexPath: metodo, assegna il tag della cella come indice:

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

2) Aggiungi target e azione per il tuo pulsante come di seguito:

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

3) Crea un metodo che restituisca una riga del mittente (grazie a @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) Azioni di codice basate su indice:

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

Il seguente codice potrebbe aiutarti.

Ho preso UITableView con una classe di prototipo personalizzata chiamata UITableViewCell all'interno di UIViewController .

Quindi ho TableViewCell.h , TableViewCell.m e TableViewCell.h , TableViewCell.m

Ecco il codice per questo:

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;
}

Classe di celle personalizzate:

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

e

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 : qui ho preso tutti gli UIControls usando Storyboard.

Spero che possa aiutarti ... !!!


Il codice di Tarun non funziona su iOS7, poiché la struttura di UITableViewCell è cambiata e ora avrebbe ottenuto "UITableViewCellScrollView".

Questo post Ottenere UITableViewCell con superview in iOS 7 ha una buona soluzione per creare un loop per trovare la corretta visualizzazione genitore, indipendentemente da eventuali futuri cambiamenti nella struttura. Si riduce alla creazione di un ciclo:

    UIView *superView = [sender superview];
    UIView *foundSuperView = nil;

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

Il collegamento ha il codice per una soluzione più riutilizzabile, ma dovrebbe funzionare.


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];

}

CustomTableCell.h è un UITableViewCell:

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

MyVC.m dopo le importazioni:

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

All'interno di "cellForRowAtIndexPath" in 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];
}

Trovo più semplice creare una sottoclasse del pulsante all'interno della cella (Swift 3):

class MyCellInfoButton: UIButton {
    var indexPath: IndexPath?
}

Nella tua classe di cellule:

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

Nell'origine dati della vista tabella o della raccolta, quando si rimuove la cella, dare al pulsante il suo percorso dell'indice:

cell.infoButton.indexPath = indexPath

Quindi puoi semplicemente inserire questi codici nel tuo controller di visualizzazione tabella:

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

E non dimenticare di impostare la classe del pulsante nel tuo Interface Builder e collegarlo alla funzione handleTapOnCellInfoButton !

modificato:

Utilizzando l'iniezione di dipendenza. Per impostare la chiusura di una chiamata:

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

e iniettare la chiusura nel metodo willDisplay del delegato della vista dell'insieme:

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

Swift 2.2

Devi aggiungere un obiettivo per quel pulsante.

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

FunctionName: connesso // ad esempio

E ovviamente devi impostare il tag di quel pulsante da quando lo stai usando.

myButton.tag = indexPath.row

È possibile ottenere questo sottoclasse UITableViewCell. Usalo nel generatore di interfaccia, rilascia un pulsante su quella cella, collegalo via presa e via.

Per ottenere il tag nella funzione connessa:

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

Swift 3 con una chiusura

Una buona soluzione consiste nell'usare una chiusura in un UITableViewCell personalizzato per richiamare il viewController per un'azione.

Nella cella:

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()
    }
}

In View Controller: Delegato Tableview

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 
    }
}

UITableView ha un metodo per trovare il indexPath di una cella:

- (NSIndexPath *)indexPathForCell:(UITableViewCell *)cell

Basta scorrere l'array di celle visibili e passare ogni cella per ottenere il percorso dell'indice.

for (UITableViewCell *cell in arrayOfVisibleTVC) {
  NSIndexPath *path = [[BNUtilitiesQuick ListController].tableViewA indexPathForCell:cell];
  NSLog(@"%@", path);
}




ios objective-c uitableview uibutton