wake-up-neo.net

Ermitteln, welches UIButton in einer UITableView gedrückt wurde

Ich habe eine UITableView mit 5 UITableViewCells. Jede Zelle enthält eine UIButton, die wie folgt eingerichtet ist:

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

Meine Frage ist folgende: Woher weiß ich in der buttonPressedAction:-Methode, welche Taste gedrückt wurde. Ich habe überlegt, Tags zu verwenden, bin aber nicht sicher, ob dies die beste Route ist. Ich möchte die Variable indexPath irgendwie auf dem Steuerelement markieren können.

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

Was ist die Standardmethode dafür?

Bearbeiten:

Ich habe es irgendwie gelöst, indem ich folgendes getan habe. Ich möchte immer noch eine Meinung haben, ob dies die Standardmethode ist oder gibt es eine bessere Möglichkeit?

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

Wichtig ist zu beachten, dass ich das Tag bei der Erstellung der Zelle nicht setzen kann, da die Zelle stattdessen aus der Warteschlange genommen werden könnte. Es fühlt sich sehr schmutzig an. Es muss einen besseren Weg geben.

204
rein

In Apples Accessory sample wird die folgende Methode verwendet:

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

Dann werden im Touchhandler die abgerufenen Berührungskoordinaten und der Indexpfad aus dieser Koordinate berechnet: 

- (void)checkButtonTapped:(id)sender
{
    CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.tableView];
    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonPosition];
    if (indexPath != nil)
    {
     ...
    }
}
393
Vladimir

Ich fand die Methode der Verwendung des Superview-Überblicks, um eine Referenz auf den indexPath der Zelle zu erhalten, perfekt. Danke an iphonedevbook.com (macnsmith) für den Tipp Linktext

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

}
48
Cocoanut

So mache ich es. Einfach und prägnant:

- (IBAction)buttonTappedAction:(id)sender
{
    CGPoint buttonPosition = [sender convertPoint:CGPointZero
                                           toView:self.tableView];
    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonPosition];
    ...
43
Chris Schwerdt

Ich habe an anderer Stelle eine nette Lösung für dieses Problem gefunden, kein Durcheinander mit Tags auf der Schaltfläche:

- (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
Alpinista

Wie wäre es, wenn Sie Informationen wie NSIndexPath in der UIButton mit Hilfe der Laufzeitinjektion senden.

1) Sie benötigen eine Laufzeit für den Import

2) addiere die statische Konstante

3) Fügen Sie Ihrer Schaltfläche NSIndexPath zur Laufzeit hinzu.

(void) setMetaData: (id) Ziel mitObjekt: (id) newObj

4) Drücken Sie beim Drücken der Taste Metadaten abrufen mit:

(id) metaData: (id) target

Genießen

    #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
magno cardona
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
Ankit Bansal

Um (@Vladimir) zu antworten, ist Swift:

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

Obwohl nach indexPath != nil gesucht wird, gibt mir der Finger den Finger ...

5
dennis

Ich würde die Tag-Eigenschaft verwenden, wie Sie es sagten, und das Tag so setzen:

[button setTag:indexPath.row];

dann bekommen Sie das Tag wie folgt in der buttonPressedAction:

((UIButton *)sender).tag

Oder

UIButton *button = (UIButton *)sender; 
button.tag;
3
ACBurk

Obwohl ich die Tag-Methode mag ... Wenn Sie Tags aus irgendeinem Grund nicht verwenden möchten, können Sie mit Ein Member NSArray von vorgefertigten Buttons erstellen:

NSArray* buttons ;

erstellen Sie dann diese Schaltflächen, bevor Sie die tableView rendern, und verschieben Sie sie in das Array.

In der tableView:cellForRowAtIndexPath:-Funktion können Sie dann Folgendes tun:

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

Dann können Sie in der buttonPressedAction:-Funktion tun

- (void)buttonPressedAction:(id)sender {
   UIButton* button = (UIButton*)sender ;
   int row = [buttons indexOfObject:button] ;
   // Do magic
}
3
Eld

HANDHABUNG VON SEKTIONEN - Ich habe den NSIndexPath in einer benutzerdefinierten UITableViewCell gespeichert

IN CLKIndexPricesHEADERTableViewCell.xib

IN IB Füge UIButton zu XIB hinzu - Füge keine Aktion hinzu!

Auslass hinzufügen @ property (keep, nonatomic) IBOutlet UIButton * buttonIndexSectionClose;

NICHT STRG + DRAG eine Aktion in IB durchführen (erfolgt im Code unten)

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

In viewForHeaderInSection (sollte auch für cellForRow .... funktionieren, wenn Ihre Tabelle nur einen Abschnitt hat)

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

... nutzen Sie den Abschnitt, um Daten für Ihre Zelle abzurufen

...Füll es aus 

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

USER drückt die DELETE-Taste in einem Section-Header und ruft dies auf

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

In diesem Beispiel habe ich eine Schaltfläche "Löschen" hinzugefügt, sodass UIAlertView zur Bestätigung angezeigt werden sollte

Ich speichere den Abschnitt und den Schlüssel im Wörterbuch, in dem Informationen über den Abschnitt in einer IVAR im VC gespeichert werden

- (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
brian.clear
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
mmmanishs

Mit Swift 4.2 und iOS 12 können Sie eines der folgenden vollständigen Beispiele auswählen, um Ihr Problem zu lösen.


# 1. Verwenden von UIViews convert(_:to:) und UITableViews indexPathForRow(at:)

import UIKit

private class CustomCell: UITableViewCell {

    let button = UIButton(type: .system)

    override init(style: UITableViewCell.CellStyle, 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.constraint(equalToSystemSpacingBelow: contentView.topAnchor, multiplier: 1).isActive = true
        button.leadingAnchor.constraint(greaterThanOrEqualToSystemSpacingAfter: 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: "CustomCell")
    }

    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: "CustomCell", for: indexPath) as! CustomCell
        cell.button.addTarget(self, action: #selector(customCellButtonTapped), for: .touchUpInside)
        return cell
    }

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

}

# 2. Verwenden von UIViews convert(_:to:) und UITableView_s indexPathForRow(at:) (alternativ)

Dies ist eine Alternative zum vorherigen Beispiel, in dem wir nil an den target-Parameter in addTarget(_:action:for:) übergeben. Wenn der erste Responder die Aktion nicht implementiert, wird er auf diese Weise an den nächsten Responder in der Responder-Kette gesendet, bis eine ordnungsgemäße Implementierung gefunden wird.

import UIKit

private class CustomCell: UITableViewCell {

    let button = UIButton(type: .system)

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

        button.setTitle("Tap", for: .normal)
        button.addTarget(nil, action: #selector(TableViewController.customCellButtonTapped), for: .touchUpInside)
        contentView.addSubview(button)

        button.translatesAutoresizingMaskIntoConstraints = false
        button.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
        button.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
        button.topAnchor.constraint(equalToSystemSpacingBelow: contentView.topAnchor, multiplier: 1).isActive = true
        button.leadingAnchor.constraint(greaterThanOrEqualToSystemSpacingAfter: 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: "CustomCell")
    }

    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: "CustomCell", for: indexPath) as! CustomCell
        return cell
    }

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

}

#3. Verwenden Sie UITableViews indexPath(for:) und delegieren Sie das Muster

In diesem Beispiel setzen wir den View-Controller als Delegat der Zelle. Wenn Sie auf die Schaltfläche der Zelle tippen, wird die entsprechende Methode des Delegaten aufgerufen.

import UIKit

protocol CustomCellDelegate: AnyObject {
    func customCellButtonTapped(_ customCell: CustomCell)
}

class CustomCell: UITableViewCell {

    let button = UIButton(type: .system)
    weak var delegate: CustomCellDelegate?

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

        button.setTitle("Tap", for: .normal)
        button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
        contentView.addSubview(button)

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

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

    @objc func buttonTapped(sender: UIButton) {
        delegate?.customCellButtonTapped(self)
    }

}
import UIKit

class TableViewController: UITableViewController, CustomCellDelegate {

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

    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: "CustomCell", for: indexPath) as! CustomCell
        cell.delegate = self
        return cell
    }

    // MARK: - CustomCellDelegate

    func customCellButtonTapped(_ customCell: CustomCell) {
        guard let indexPath = tableView.indexPath(for: customCell) else { return }
        print(indexPath)
    }

}

# 4. Verwendung von UITableViews indexPath(for:) und einer Schließung für die Delegierung

Dies ist eine Alternative zum vorherigen Beispiel, bei dem anstelle der Protokolldelegationsdeklaration eine Schließung verwendet wird, um das Tastenfeld zu behandeln.

import UIKit

class CustomCell: UITableViewCell {

    let button = UIButton(type: .system)
    var buttontappedClosure: ((CustomCell) -> Void)?

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

        button.setTitle("Tap", for: .normal)
        button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
        contentView.addSubview(button)

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

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

    @objc func buttonTapped(sender: UIButton) {
        buttontappedClosure?(self)
    }

}
import UIKit

class TableViewController: UITableViewController {

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

    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: "CustomCell", for: indexPath) as! CustomCell
        cell.buttontappedClosure = { [weak tableView] cell in
            guard let indexPath = tableView?.indexPath(for: cell) else { return }
            print(indexPath)
        }
        return cell
    }

}

# 5. UITableViewCells accessoryType und UITableViewDelegates verwenden tableView(_:accessoryButtonTappedForRowWith:)

Wenn es sich bei Ihrer Taste um die standardmäßige Zubehörsteuerung von UITableViewCell handelt, wird durch Antippen darauf ein Aufruf von UITableViewDelegates tableView(_:accessoryButtonTappedForRowWith:) ausgelöst, wodurch Sie den zugehörigen Indexpfad aufrufen können.

import UIKit

private class CustomCell: UITableViewCell {

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        accessoryType = .detailButton
    }

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

    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: "CustomCell", for: indexPath) as! CustomCell
        return cell
    }

    override func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
        print(indexPath)
    }

}
1
Imanou Petit

Es funktioniert auch für mich, Danke @Cocoanut

Ich fand die Methode der Verwendung des Superview-Überblicks, um eine Referenz auf den indexPath der Zelle zu erhalten, perfekt. Vielen Dank an iphonedevbook.com (macnsmith) für den Link-Link-Tipp

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

}
1
user366584

Swift 2 UPDATE

Hier erfahren Sie, wie Sie herausfinden, welche Taste gedrückt wurde + Daten von indexPath.row an einen anderen ViewController senden, da ich davon ausgehe, dass dies für die meisten der Punkt ist! 

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

    }

Für diejenigen, die eine ViewController-Klasse verwenden und eine tableView hinzugefügt haben, verwende ich einen ViewController anstelle eines TableViewControllers. Daher habe ich manuell das tableView hinzugefügt, um darauf zuzugreifen.

Hier ist der Code für die Weitergabe von Daten an einen anderen VC, wenn Sie auf diese Schaltfläche tippen und die ZelleindexPath.row übergeben. 

@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
Lukesivi
// how do I know which button sent this message?
// processing button press for this row requires an indexPath.

Eigentlich ziemlich unkompliziert:

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

Gut für mich: p

wenn Sie Ihre Zielaktionskonfiguration anpassen möchten, können Sie den Ereignisparameter in die Methode einschließen und dann die Berührungen dieses Ereignisses verwenden, um die Koordinaten der Berührung aufzulösen. Die Koordinaten müssen noch in den Grenzen der Berührungsansicht aufgelöst werden, aber für manche Menschen scheint das einfacher.

0
ohhorob

Chris Schwerdts Lösung aber dann in Swift arbeitete für mich: 

@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

Beachten Sie, dass ich hier ein benutzerdefiniertes Feld verwende

 @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
Gaurav

Ich verwende immer Tags.

Sie müssen die UITableviewCell subclassieren und von dort aus den Tastendruck ausführen.

0
Chris

Eine kleine Variation der Antwort von Cocoanuts (die mir dabei geholfen hat, dieses Problem zu lösen), wenn sich die Schaltfläche in der Fußzeile einer Tabelle befand (was Sie daran hindert, die angeklickte Zelle zu finden:

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

sie können das Tag-Muster verwenden:

- (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
Nir Levy

erstellen Sie ein nsmutable-Array, und fügen Sie alle Schaltflächen in dieses Array ein.

in der Knopfdruckmethode 

-

 (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
rajesh

Klicken Sie auf die Schaltfläche, um den erforderlichen Wert zu speichern. Erstellen Sie möglicherweise ein Protokoll (ControlWithData oder etwas anderes). Legen Sie den Wert fest, wenn Sie die Schaltfläche zur Tabellensichtzelle hinzufügen. Prüfen Sie in Ihrem Touch-Up-Ereignis, ob der Sender das Protokoll einhält, und extrahieren Sie die Daten. Normalerweise speichere ich einen Verweis auf das tatsächliche Objekt, das in der Tabellenzellenzelle dargestellt wird.

Ich benutze eine Lösung dieser Unterklasse UIButton und ich dachte, ich sollte sie hier einfach teilen, Codes in Swift

class ButtonWithIndexPath : UIButton {
    var indexPath:IndexPath?
}

Dann vergessen Sie nicht, den indexPath in cellForRow(at:) zu aktualisieren.

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
}

Wenn Sie also auf das Ereignis der Schaltfläche reagieren, können Sie es wie verwenden

func cellButtonPressed(_ sender:UIButton) {
    if sender is ButtonWithIndexPath {
        let button = sender as! ButtonWithIndexPath
        print(button.indexPath)
    }
}
0
Ben Ong

Es ist einfach; Machen Sie eine benutzerdefinierte Zelle und nehmen Sie den Auslass des Knopfes

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

    cell.yourButton.tag = indexPath.Row;

- (void)buttonPressedAction:(id)sender

Ändern Sie die ID in der obigen Methode in (UIButton *).

Sie können den Wert erhalten, mit dem die Schaltfläche getippt wird, indem Sie sender.tag ausführen.

0
piyush Bageria

Fehlt mir etwas? Können Sie nicht einfach den Sender verwenden, um die Schaltfläche zu identifizieren. Der Absender gibt Ihnen folgende Informationen:

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

Wenn Sie dann die Eigenschaften der Schaltfläche ändern möchten, sagen Sie das Hintergrundbild, das Sie dem Absender sagen:

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

Wenn Sie das Tag benötigen, ist die Methode von ACBurk in Ordnung.

0

Dieses Problem besteht aus zwei Teilen:

1) Abrufen des Indexpfads von UITableViewCell, der gedrückte UIButton enthält

Es gibt einige Vorschläge wie:

  • Aktualisieren von UIButtons tag in cellForRowAtIndexPath:-Methode mit dem row-Wert des Indexpfads. Dies ist keine gute Lösung, da tag kontinuierlich aktualisiert werden muss und nicht mit Tabellensichten mit mehr als einem Abschnitt funktioniert. 

  • Hinzufügen einer NSIndexPath-Eigenschaft zu einer benutzerdefinierten Zelle und Aktualisierung statt UIButtons tag in der cellForRowAtIndexPath:-Methode. Dies löst ein Problem mit mehreren Abschnitten, ist jedoch immer noch nicht gut, da immer eine Aktualisierung erforderlich ist.

  • Beibehaltung eines schwachen Verweises auf das übergeordnete UITableView in der benutzerdefinierten Zelle während der Erstellung und Verwendung der indexPathForCell:-Methode zum Abrufen des Indexpfads. Scheint ein wenig besser zu sein, es ist keine Notwendigkeit, etwas in der cellForRowAtIndexPath:-Methode zu aktualisieren, es muss jedoch immer noch eine schwache Referenz gesetzt werden, wenn die benutzerdefinierte Zelle erstellt wird.

  • Verwenden der superView-Eigenschaft der Zelle, um eine Referenz auf das übergeordnete UITableView zu erhalten. Sie müssen der benutzerdefinierten Zelle keine Eigenschaften hinzufügen und müssen bei der Erstellung/nachträglich keine Änderungen vornehmen oder aktualisieren. superView der Zelle hängt jedoch von den Details der iOS-Implementierung ab. Es kann also nicht direkt verwendet werden.

Dies kann jedoch mit einer einfachen Schleife erreicht werden, da wir uns sicher sind, dass sich die betreffende Zelle in einer UITableView befinden muss:

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

Daher können diese Vorschläge zu einer einfachen und sicheren benutzerdefinierten Zellenmethode zum Abrufen des Indexpfads kombiniert werden:

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

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

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

Von nun an kann mit dieser Methode ermittelt werden, welche UIButton gedrückt wird.

2) Informieren anderer Parteien über Knopfdruckereignis

Nachdem intern bekannt ist, welche UIButton in welcher benutzerdefinierten Zelle mit genauem Indexpfad gedrückt wird, müssen diese Informationen an andere Parteien gesendet werden (höchstwahrscheinlich der View-Controller, der die UITableView verarbeitet). Daher kann dieses Schaltflächenklickereignis auf einer ähnlichen Abstraktions- und Logikebene wie die didSelectRowAtIndexPath:-Methode des UITableView-Delegaten behandelt werden.

Hierfür können zwei Ansätze verwendet werden: 

a) Delegierung: custom cell kann eine delegate -Eigenschaft haben und ein Protokoll definieren. Wenn die Taste gedrückt wird, führt sie nur ihre Delegat-Methoden für ihre delegate-Eigenschaft aus. Diese delegate-Eigenschaft muss jedoch für jede benutzerdefinierte Zelle festgelegt werden, wenn sie erstellt wird. Alternativ kann eine benutzerdefinierte Zelle auch ihre Delegatmethoden für die delegate der übergeordneten Tabellensicht ausführen.

b) Benachrichtigungscenter: Benutzerdefinierte Zellen können einen benutzerdefinierten Benachrichtigungsnamen definieren und diese Benachrichtigung mit dem Indexpfad und den Informationen der übergeordneten Tabellensicht, die im userInfo-Objekt enthalten sind, buchen. Es ist nicht notwendig, für jede Zelle etwas festzulegen. Es reicht aus, nur einen Beobachter für die Benachrichtigung der benutzerdefinierten Zelle hinzuzufügen.

0
erkanyildiz