Frage

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

- (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: in der buttonPressedAction: Methode, wie kann ich wissen, welche Taste gedrückt wurde. Ich habe mit Hilfe von Tags in Betracht gezogen, aber ich bin nicht sicher, ob dies der beste Weg ist. Ich möchte in der Lage sein, um irgendwie die indexPath auf die Steuer zu markieren.

- (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 der normale Weg, dies zu tun?

Edit:

Ich habe irgendwie gelöst durch die folgenden tun. Ich möchte noch eine Meinung haben, ob dies der normale Weg ist, es zu tun, oder gibt es einen besseren Weg?

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

Was ist wichtig zu beachten ist, dass ich nicht den Tag in der Schaffung der Zelle festlegen kann, da könnte die Zelle stattdessen aus der Warteschlange entfernt werden. Es fühlt sich sehr schmutzig. Es muss ein besserer Weg geben.

War es hilfreich?

Lösung

In Apples Accessory die folgende Methode probieren verwendet wird:

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

Dann in Kontakt Touch-Handler Koordinaten abgerufen und Indexpfad berechnet sich aus dieser Koordinate:

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

Andere Tipps

Ich fand die Methode der Super des Superview mit einem Verweis auf die Zelle indexPath zu erhalten perfekt gearbeitet. Dank iphonedevbook.com (macnsmith) für die Spitze Link-Text

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

}

Hier ist, wie ich es tun. Einfach und prägnant:

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

Gefunden eine schöne Lösung für dieses Problem an anderer Stelle, nicht Herumspielen mit Tags auf die 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...
}

Wie wäre es, die Informationen wie NSIndexPath im UIButton mit Runtime-Injektion zu senden.

1) Sie benötigen Laufzeit auf den Import

2) fügen Sie statische Konstante

3) in NSIndexPath auf Ihre Schaltfläche auf Laufzeit mit:

(void) setMetadata: (id) Ziel withobject: (id) NEWOBJ

4) auf Tastendruck erhalten Metadaten:

(id) metaData: (id) Ziel

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
    }

Aktivitäten (@Vladimir) 's Antwort ist Swift:

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

Obwohl für indexPath != nil Überprüfung gibt mir die Finger ... "NSIndexPath ist kein Subtyp von NSString"

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

würde ich den Tag-Eigenschaft verwenden, wie Sie gesagt haben, das Setzen der Tag wie folgt:

[button setTag:indexPath.row];

dann immer den Tag innerhalb des buttonPressedAction etwa so:

((UIButton *)sender).tag

oder

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

Obwohl ich den Tag gefällt, wie ..., wenn Sie nicht wollen, um Tags zu verwenden, für welchen Gründen auch immer, Sie könnten ein Mitglied NSArray von vorgefertigten Schaltflächen erstellen:

NSArray* buttons ;

dann diese Tasten erstellen, bevor die Tableview Rendering und sie in das Array drücken.

Dann innerhalb der tableView:cellForRowAtIndexPath: Funktion, die Sie tun können:

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

Dann in der buttonPressedAction: Funktion, die Sie tun können

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

PROFILE Handhabung - ich NSIndexPath in einem benutzerdefinierten UITableViewCell gespeichert

IN CLKIndexPricesHEADERTableViewCell.xib

IN IB hinzufügen UIButton zu XIB - DONT Aktion hinzufügen

In Ausgang @property (retain, nonatomic) IBOutlet UIButton * buttonIndexSectionClose;

DO + NICHT CTRL DRAG eine Aktion in IB (in Code unten getan)

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

In viewForHeaderInSection (sollte auch für cellForRow arbeiten .... etc, wenn Sie Tabelle nur 1 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];

... den Abschnitt verwenden, um Daten für Ihr Handy zu bekommen

... füllen Sie es in

   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ücken ENTF-Taste auf einem Abschnitt Header und dies ruft

- (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 sollte so zeigen UIAlertView es zu bestätigen

Ich speichere den Abschnitt und Schlüssel in das Wörterbuch zu speichern Informationen über den Abschnitt in einer Ivar in der 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);
    }
}
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; //:)
}

Mit Swift 4.2 und iOS 12, können Sie eine der 5 nach vollständigen Beispielen , um Ihr Problem zu lösen.


# 1. Mit UIView des convert(_:to:) und UITableView der 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. Mit UIView des convert(_:to:) und UITableView der indexPathForRow(at:) (alternative)

Dies ist eine Alternative zu dem vorherigen Beispiel, wo wir nil zum target Parameter in addTarget(_:action:for:) passieren. Auf diese Weise, wenn der Ersthelfer nicht die Aktion implementieren, wird es auf das nächste Responder in der Responder-Kette senden, bis, bis eine ordnungsgemäße Durchführung 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. Mit UITableView des indexPath(for:) und delegieren Muster

In diesem Beispiel setzen wir den View-Controller als Delegierter der Zelle. Wenn die Taste der Zelle entnommen wird, löst es einen Aufruf an die entsprechende Methode des Delegierten.

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. Mit UITableView des indexPath(for:) und einen Verschluss für eine Delegation

Dies ist eine Alternative zu dem vorherigen Beispiel, in dem wir einen Verschluss anstelle einem protokoll Delegatendeklaration verwenden Sie die Taste tippen 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. Mit UITableViewCell des accessoryType und UITableViewDelegate der tableView(_:accessoryButtonTappedForRowWith:)

Wenn Sie Ihre Schaltfläche ein UITableViewCell Standardzubehör Kontrolle, jeder Hahn an wird es einen Aufruf an UITableViewDelegate der tableView(_:accessoryButtonTappedForRowWith:) auslösen, so dass Sie die damit verbundenen Indexpfad erhalten.

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

}

Es funktioniert für mich als gut, Dank @Cocoanut

Ich fand die Methode der Super des Superview mit einem Verweis auf die Zelle indexPath zu erhalten perfekt gearbeitet. Dank iphonedevbook.com (macnsmith) für die Spitze Linktext

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

}

können Sie 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)
}

Bin ich etwas fehlt? Sie können nicht nur Sender mit der Taste zu identifizieren. Sender gibt Ihnen Informationen wie folgt aus:

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

Dann, wenn Sie die Eigenschaften der Taste ändern möchten, sagen das Hintergrundbild Sie Absender nur sagen:

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

Wenn Sie den Tag dann ACBurk Methode brauchen, ist in Ordnung.

// how do I know which button sent this message?
// processing button press for this row requires an indexPath.

Ziemlich einfach wirklich:

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

Arbeiten gut für mich: P

Wenn Sie Ihr Ziel-Aktion Setup anpassen möchten, können Sie die Ereignisparameter in dem Verfahren umfassen, und verwenden Sie dann die Berührungen dieses Ereignisses die Koordinaten der Berührung zu lösen. Die Koordinaten noch in den direkt Kontakt Grenzen gelöst werden müssen, aber das kann für manche Menschen leichter erscheinen.

ein NSMutable Array erstellen und setzen alle Schaltfläche in diesem Array USINT [Array addObject: yourButton];

in der Taste drückt Methode

-

 (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

}
}

Eine leichte Abwandlung Cocoanuts Antwort (die ich dazu beigetragen, zu lösen), wenn die Schaltfläche in der Fußzeile einer Tabelle war (die Sie von der Suche nach der "geklickt Zelle verhindert:

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

Ich verwende Tags immer.

Sie müssen die UITableviewCell Unterklasse und drücken Sie die Taste von dort zu behandeln.

Es ist ganz einfach; machen Sie eine benutzerdefinierte Zelle und nehmen Sie einen Ausgang Taste

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

    cell.yourButton.tag = indexPath.Row;

- (void)buttonPressedAction:(id)sender

Änderung id in obigen Verfahren (UIButton *)

Sie können den Wert erhalten, dass die Taste, indem Sie sender.tag angezapft wird.

Unterklasse die Taste, um den gewünschten Wert zu speichern, erstellen Sie vielleicht ein Protokoll (ControlWithData oder etwas). Setzen Sie den Wert, wenn Sie die Taste, um die Tabellenansicht Zelle hinzuzufügen. In Ihrem Touch-up-Ereignis finden, wenn der Absender das Protokoll gehorcht und die Daten extrahieren. Ich speichere normalerweise einen Verweis auf das eigentliche Objekt, das auf dem Tisch Sichtzelle wiedergegeben wird.

SWIFT 2 UPDATE

Hier ist, wie um herauszufinden, welche Taste + wurde angezapft Daten von dieser Schaltfläche indexPath.row an einem anderen Viewcontroller senden, wie ich gehe davon aus, dass der Punkt für die meisten!

@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 hat eine Tableview, ich bin ein Viewcontroller anstelle eines Tableviewcontroller mit so habe ich manuell die Tableview, um darauf zuzugreifen.

Hier ist der Code für die Daten an einem anderen VC geben, wenn diese Taste tippen und vorbei die Zelle 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)

}

Hinweis: Hier bin ich mit benutzerdefinierten Zelle dieser Code perfekt für mich arbeitet

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

Chris Schwerdt-Lösung, aber dann in Swift arbeitet 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)
}

Dieses Problem hat zwei Teile:

1) Erhalten des Indexpfads von UITableViewCell die gedrückt UIButton enthält

Es gibt einige Vorschläge, wie:

  • Die Aktualisierung UIButton des tag in cellForRowAtIndexPath: Methode row Wert des Indexpfads. Dies ist keine gute Lösung, da es erfordert tag kontinuierlich aktualisiert und es funktioniert nicht mit Tabellenansichten mit mehr als einem Abschnitt.

  • eine NSIndexPath Eigenschaft, um benutzerdefinierte Zelle hinzufügen und es statt UIButton des tag in cellForRowAtIndexPath: Verfahren zu aktualisieren. Dies löst mehrere Probleme Abschnitt aber immer noch nicht gut, wie es die Aktualisierung erfordert immer.

  • ein schwaches refence Mutter UITableView in der benutzerdefinierten Zelle zu halten, während es die Erstellung und Verwendung indexPathForCell: Methode des Indexpfads zu erhalten. Scheint ein bisschen besser, aktualisieren Sie keine Notwendigkeit, etwas in cellForRowAtIndexPath: Methode, erfordert aber immer noch eine schwache Referenz eingestellt wird, wenn die benutzerdefinierte Zelle erstellt wird.

  • Mit Zelle superView Eigenschaft einen Verweis auf übergeordneten UITableView zu erhalten. Keine Notwendigkeit, alle Eigenschaften der benutzerdefinierten Zelle hinzuzufügen, und keine Notwendigkeit zu setzen / aktualisieren, alles auf Schöpfung / später. Aber Zelle superView hängt von iOS Implementierungsdetails. Es kann also nicht direkt verwendet werden.

Aber dies kann mit einer einfachen Schleife erreicht werden, da wir sicher sind, die betreffende Zelle in einem UITableView sein muss:

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

So können diese Vorschläge für das Erhalten des Indexpfads in ein einfachen und sichere individuellen Zellverfahren 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 diese Methode verwendet werden, um zu ermitteln, welche UIButton gedrückt wird.

2) Information andere Parteien über Tastendruck-Ereignis

Nach intern zu wissen, welche UIButton in der individuellen Zelle mit genauer Indexpfad gedrückt wird, muss diese Informationen an anderen Parteien geschickt werden (höchstwahrscheinlich die View-Controller die UITableView Handling). So kann dieses Schaltfläche Click-Ereignis in einer ähnlichen Abstraktion und logische Ebene behandelt werden, um didSelectRowAtIndexPath: Methode von UITableView delegieren.

Zwei Ansätze können dazu verwendet werden:

a) Delegation: benutzerdefinierte Zelle kann eine delegate Eigenschaft hat, und ein Protokoll definieren. Wenn der Knopf gedrückt wird, führt sie nur Methoden Delegierten auf sie delegate Eigenschaft ist. Aber diese delegate Eigenschaft muss für jede individuelle Zelle gesetzt werden, wenn sie erstellt werden. Als Alternative können benutzerdefinierte Zelle wählen ihre Delegatmethoden auszuführen auf sie delegate geordneten Tabelle Ansicht des ist zu.

b) Notification Center: benutzerdefinierte Zellen können eine benutzerdefinierte Benachrichtigung Namen definieren und veröffentlichen diese Benachrichtigung mit dem Indexpfad und Elterntabellenansicht Informationen in userInfo Objekt zur Verfügung gestellt. Keine Notwendigkeit, etwas für jede Zelle, nur einen Beobachter für die Mitteilung der benutzerdefinierten Zelle hinzugefügt ist genug.

Ich verwende eine Lösung, die Unterklasse UIButton und ich dachte, ich sollte es einfach teilen hier, Codes in Swift:

class ButtonWithIndexPath : UIButton {
    var indexPath:IndexPath?
}

merken Sie dann zu aktualisieren, es ist indexPath in 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
}
So

, wenn auf die Schaltfläche Ereignis reagieren können Sie es verwenden wie

func cellButtonPressed(_ sender:UIButton) {
    if sender is ButtonWithIndexPath {
        let button = sender as! ButtonWithIndexPath
        print(button.indexPath)
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top