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.
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)
{
...
}
}
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];
...
}
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];
...
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...
}
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
}
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")
}
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 ...
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;
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
}
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);
}
}
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 eines der folgenden vollständigen Beispiele auswählen, um Ihr Problem zu lösen.
UIView
s convert(_:to:)
und UITableView
s 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)
}
}
UIView
s 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)
}
}
UITableView
s indexPath(for:)
und delegieren Sie das MusterIn 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)
}
}
UITableView
s indexPath(for:)
und einer Schließung für die DelegierungDies 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
}
}
UITableViewCell
s accessoryType
und UITableViewDelegate
s 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 UITableViewDelegate
s 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)
}
}
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];
...
}
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)
}
// 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.
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)
}
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);
}
Ich verwende immer Tags.
Sie müssen die UITableviewCell
subclassieren und von dort aus den Tastendruck ausführen.
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];
}
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)
}
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
}
}
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)
}
}
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.
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.
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 UIButton
s 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 UIButton
s 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.