Festzustellen, welche UIButton in einem UITableView gedrückt wurde
-
05-07-2019 - |
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.
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
destag
incellForRowAtIndexPath:
Methoderow
Wert des Indexpfads. Dies ist keine gute Lösung, da es erforderttag
kontinuierlich aktualisiert und es funktioniert nicht mit Tabellenansichten mit mehr als einem Abschnitt. -
eine
NSIndexPath
Eigenschaft, um benutzerdefinierte Zelle hinzufügen und es stattUIButton
destag
incellForRowAtIndexPath:
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 VerwendungindexPathForCell:
Methode des Indexpfads zu erhalten. Scheint ein bisschen besser, aktualisieren Sie keine Notwendigkeit, etwas incellForRowAtIndexPath:
Methode, erfordert aber immer noch eine schwache Referenz eingestellt wird, wenn die benutzerdefinierte Zelle erstellt wird. -
Mit Zelle
superView
Eigenschaft einen Verweis auf übergeordnetenUITableView
zu erhalten. Keine Notwendigkeit, alle Eigenschaften der benutzerdefinierten Zelle hinzuzufügen, und keine Notwendigkeit zu setzen / aktualisieren, alles auf Schöpfung / später. Aber ZellesuperView
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)
}
}