swift:如何在单元格中的按钮被点击时获取indexpath.row?

时间:2015-02-22 15:52:30

标签: swift button touch nsindexpath

我有一个带有按钮的tableview,我想在使用其中一个时使用indexpath.row。 这就是我现在拥有的,但总是0

var point = Int()
func buttonPressed(sender: AnyObject) {
    let pointInTable: CGPoint =         sender.convertPoint(sender.bounds.origin, toView: self.tableView)
    let cellIndexPath = self.tableView.indexPathForRowAtPoint(pointInTable)
    println(cellIndexPath)
    point = cellIndexPath!.row
    println(point)
}

20 个答案:

答案 0 :(得分:132)

giorashc几乎已经接受了他的答案,但他忽略了细胞有额外jmeter层的事实。因此,我们必须深入一层:

contentView

这是因为在视图层次结构中,tableView将单元格作为子视图,随后它们拥有自己的内容视图'这就是为什么你必须得到这个内容视图的超级视图来获取单元格本身。因此,如果您的按钮包含在子视图中而不是直接包含在单元格的内容视图中,那么您必须更深层次地访问它。

以上是一种这样的方法,但不一定是最好的方法。虽然它是功能性的,但它假定了Apple从未记录过的guard let cell = sender.superview?.superview as? YourCellClassHere else { return // or fatalError() or whatever } let indexPath = itemTable.indexPath(for: cell) 的详细信息,例如它的视图层次结构。这可以在将来进行更改,因此上述代码可能会因此而出现不可预测的行为。

由于上述原因,出于长寿和可靠性的原因,我建议采用另一种方法。本主题中列出了许多替代方案,我建议您阅读,但我个人最喜欢的内容如下:

在你的单元类上保存一个闭包属性,让按钮的动作方法调用它。

UITableViewCell

然后,当您在class MyCell: UITableViewCell { var button: UIButton! var buttonAction: ((Any) -> Void)? @objc func buttonPressed(sender: Any) { self.buttonAction?(sender) } } 中创建单元格时,可以为闭包指定值。

cellForRowAtIndexPath

通过在此处移动处理程序代码,您可以利用已存在的func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! MyCell cell.buttonAction = { sender in // Do whatever you want from your button here. } // OR cell.buttonAction = buttonPressed(closure: buttonAction, indexPath: indexPath) // <- Method on the view controller to handle button presses. } 参数。这是一种比上面列出的方法更安全的方法,因为它不依赖于未记录的特征。

答案 1 :(得分:46)

我遇到此类问题的方法是在单元格和tableview之间使用委托协议。这允许您将按钮处理程序保留在单元子类中,这使您可以将接触操作处理程序分配给Interface Builder中的原型单元格,同时仍将按钮处理程序逻辑保留在视图控制器中。

它还避免了导航视图层次结构或使用tag属性的潜在脆弱方法,当单元格索引发生更改(由于插入,删除或重新排序)时会出现问题

<强> CellSubclass.swift

protocol CellSubclassDelegate: class {
    func buttonTapped(cell: CellSubclass)
}

class CellSubclass: UITableViewCell {

@IBOutlet var someButton: UIButton!

weak var delegate: CellSubclassDelegate?

override func prepareForReuse() {
    super.prepareForReuse()
    self.delegate = nil
}

@IBAction func someButtonTapped(sender: UIButton) {
    self.delegate?.buttonTapped(self)
}

<强> ViewController.swift

class MyViewController: UIViewController, CellSubclassDelegate {

    @IBOutlet var tableview: UITableView!

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! CellSubclass

        cell.delegate = self

        // Other cell setup

    } 

    //  MARK: CellSubclassDelegate

    func buttonTapped(cell: CellSubclass) {
        guard let indexPath = self.tableView.indexPathForCell(cell) else {
            // Note, this shouldn't happen - how did the user tap on a button that wasn't on screen?
            return
        }

        //  Do whatever you need to do with the indexPath

        print("Button tapped on row \(indexPath.row)")
    }
} 

答案 2 :(得分:44)

更新:获取包含按钮(包括部分和行)的单元格的indexPath:

使用按钮位置

buttonTapped方法的内部,您可以抓住按钮的位置,将其转​​换为tableView中的坐标,然后在该坐标处获取行的indexPath。

func buttonTapped(_ sender:AnyObject) {
    let buttonPosition:CGPoint = sender.convert(CGPoint.zero, to:self.tableView)
    let indexPath = self.tableView.indexPathForRow(at: buttonPosition)
}

注意:有时候使用函数view.convert(CGPointZero, to:self.tableView)会导致查找nil某一行的行时遇到边缘情况,即使有一个tableView细胞在那里。要解决此问题,请尝试传递与原点稍微偏移的实际坐标,例如:

let buttonPosition:CGPoint = sender.convert(CGPoint.init(x: 5.0, y: 5.0), to:self.tableView)

上一个答案:使用标记属性(仅返回行)

而不是爬进superview树来抓住指向包含UIButton的单元格的指针,有一种更安全,更可重复的技术,利用上面提到的Antonio上面提到的button.tag属性,在this answer中描述,如下所示:

cellForRowAtIndexPath:中设置标记属性:

button.tag = indexPath.row
button.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)

然后,在buttonClicked:函数中,引用该标记来获取按钮所在的indexPath行:

func buttonClicked(sender:UIButton) {
    let buttonRow = sender.tag
}

我更喜欢这种方法,因为我发现在superview树中摆动可能是设计应用程序的一种危险方式。此外,对于Objective-C,我过去曾使用过this technique,并对结果感到满意。

答案 3 :(得分:12)

使用UITableView的扩展来获取任何视图的单元格:

@ Paulw11的答案是设置一个带有委托属性的自定义单元格类型,它将消息发送到表格视图是一个很好的方法,但它需要一定的工作量来设置。

我认为走桌子视图单元格的视图层次结构寻找单元格是一个坏主意。它很脆弱 - 如果您稍后将按钮放在视图中以进行布局,则该代码可能会中断。

使用视图标签也很脆弱。您必须记住在创建单元格时设置标记,并且如果在视图控制器中使用该方法将视图标记用于其他目的,则可能会出现重复的标记编号,并且您的代码可能无法按预期工作。

我创建了一个UITableView的扩展,它允许您获取表视图单元格中包含的任何视图的indexPath。如果传入的视图实际上不属于表视图单元格,则返回Optional,该值为nil。以下是其中的扩展源文件。您只需将此文件放在项目中,然后使用包含的indexPathForView(_:)方法查找包含任何视图的indexPath。

//
//  UITableView+indexPathForView.swift
//  TableViewExtension
//
//  Created by Duncan Champney on 12/23/16.
//  Copyright © 2016-2017 Duncan Champney.
//  May be used freely in for any purpose as long as this 
//  copyright notice is included.

import UIKit

public extension UITableView {

  /**
  This method returns the indexPath of the cell that contains the specified view

   - Parameter view: The view to find.

   - Returns: The indexPath of the cell containing the view, or nil if it can't be found

  */

    func indexPathForView(_ view: UIView) -> IndexPath? {
        let center = view.center
        let viewCenter = self.convert(center, from: view.superview)
        let indexPath = self.indexPathForRow(at: viewCenter)
        return indexPath
    }
}

要使用它,您只需在IBAction中调用方法,以获取包含在单元格中的按钮:

func buttonTapped(_ button: UIButton) {
  if let indexPath = self.tableView.indexPathForView(button) {
    print("Button tapped at indexPath \(indexPath)")
  }
  else {
    print("Button indexPath not found")
  }
}

(请注意,indexPathForView(_:)功能仅在其传递的视图对象被当前在屏幕上的单元格包含时才有效。这是合理的,因为不在屏幕上的视图实际上并不属于特定的indexPath;当它的包含单元格被回收时,它可能被分配给不同的indexPath。)

编辑:

您可以从Github下载使用上述扩展程序的工作演示项目:TableViewExtension.git

答案 4 :(得分:9)

Thread 1: status = VgTs_Runnable (lwpid 2567) ==30388== at 0x103BE5C3D: _dispatch_alloc_continuation_from_heap_slow (in /usr/lib/system/libdispatch.dylib) ==30388== by 0x103BE5C0E: _dispatch_alloc_continuation_alloc (in /usr/lib/system/libdispatch.dylib) ==30388== by 0x103BE59D6: dispatch_source_set_event_handler (in /usr/lib/system/libdispatch.dylib) ==30388== by 0x103F16D05: _notify_lib_init (in /usr/lib/system/libsystem_notify.dylib) ==30388== by 0x103F176C2: notify_register_dispatch (in /usr/lib/system/libsystem_notify.dylib) ==30388== by 0x1021D0096: __71+[CFPrefsSource withSourceForIdentifier:user:byHost:container:perform:]_block_invoke_2 (in /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation) ==30388== by 0x103BE333E: _dispatch_client_callout (in /usr/lib/system/libdispatch.dylib) ==30388== by 0x103BE3236: dispatch_once_f (in /usr/lib/system/libdispatch.dylib) ==30388== by 0x1020C6A7A: +[CFPrefsSource withSourceForIdentifier:user:byHost:container:perform:] (in /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation) ==30388== by 0x10221D1AF: -[CFPrefsSearchListSource addSourceForIdentifier:user:byHost:container:] (in /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation) ==30388== by 0x10221C9E9: __73+[CFPrefsSearchListSource withSearchListForIdentifier:container:perform:]_block_invoke (in /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation) ==30388== by 0x10221C732: +[CFPrefsSearchListSource withSearchListForIdentifier:container:perform:] (in /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation) ==30388== by 0x10224F5C6: _CFPreferencesCopyAppValueWithContainer (in /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation) ==30388== by 0x10480B9C8: -[NSUserDefaults(NSUserDefaults) init] (in /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation) ==30388== by 0x10480B3B6: +[NSUserDefaults(NSUserDefaults) standardUserDefaults] (in /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation) ==30388== by 0x100BBE5C7: +[NSApplication initialize] (in /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit) ==30388== by 0x1003553C7: call_load_methods (in /usr/lib/libobjc.A.dylib) ==30388== by 0x100355155: class_createInstance (in /usr/lib/libobjc.A.dylib) ==30388== by 0x100354D07: NXMapRemove (in /usr/lib/libobjc.A.dylib) ==30388== by 0x10034F590: objc_msgSend (in /usr/lib/libobjc.A.dylib) ==30388== by 0x1000BDC8F: Cocoa_RegisterApp (in /usr/local/lib/libSDL2-2.0.0.dylib) ==30388== by 0x1000C229B: Cocoa_CreateDevice (in /usr/local/lib/libSDL2-2.0.0.dylib) ==30388== by 0x1000B655B: SDL_VideoInit_REAL (in /usr/local/lib/libSDL2-2.0.0.dylib) ==30388== by 0x100020C69: SDL_InitSubSystem_REAL (in /usr/local/lib/libSDL2-2.0.0.dylib) ==30388== by 0x100002E80: main (main.cpp:14)

我找到了一种方法,希望它会有所帮助。

Swift2.1

答案 5 :(得分:5)

在Swift 4中,只需使用它:

func buttonTapped(_ sender: UIButton) {
        let buttonPostion = sender.convert(sender.bounds.origin, to: tableView)

        if let indexPath = tableView.indexPathForRow(at: buttonPostion) {
            let rowIndex =  indexPath.row
        }
}

答案 6 :(得分:4)

  

Swift 4解决方案:

您有一个按钮(myButton)或单元格中的任何其他视图。在cellForRowAt中像这样分配标签

cell.myButton.tag = indexPath.row

现在你在tapFunction或任何其他。像这样取出它并将其保存在局部变量中。

currentCellNumber = (sender.view?.tag)!

在此之后,您可以使用此currentCellNumber的任何位置来获取所选按钮的indexPath.row。

享受!

答案 7 :(得分:4)

非常简单地获取索引路径迅速4、5

REGEXP_REPLACE(REGEXP_EXTRACT(Field, "&extension=([^\\s&]*)"), "-", " ")

如何在Btn中获取IndexPath单击:

let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! Cell
cell.btn.tag = indexPath.row
cell.btn.addTarget(self, action: "buttonTapped:", forControlEvents: 
UIControlEvents.TouchUpInside)

答案 8 :(得分:3)

由于事件处理程序的发送者是按钮本身,我使用按钮的tag属性来存储索引,初始化为cellForRowAtIndexPath

但是我会以一种完全不同的方式做更多的工作。如果您使用自定义单元格,这就是我解决问题的方法:

  • 将“indexPath”属性添加到自定义表格单元格
  • cellForRowAtIndexPath
  • 中对其进行初始化
  • 将点击处理程序从视图控制器移动到单元格实现
  • 使用委托模式通知视图控制器有关tap事件,传递索引路径

答案 9 :(得分:2)

在看到Paulw11建议使用委托回调之后,我想稍微详细说明/提出另一个类似的建议。如果您不想使用委托模式,可以使用swift中的闭包,如下所示:

你的细胞类:

class Cell: UITableViewCell {
    @IBOutlet var button: UIButton!

    var buttonAction: ((sender: AnyObject) -> Void)?

    @IBAction func buttonPressed(sender: AnyObject) {
        self.buttonAction?(sender)
    }
}

您的cellForRowAtIndexPath方法:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! Cell
    cell.buttonAction = { (sender) in
        // Do whatever you want from your button here.
    }
    // OR
    cell.buttonAction = buttonPressed // <- Method on the view controller to handle button presses.
}

答案 10 :(得分:1)

尝试使用#selector来调用IBaction。在cellforrowatindexpath

            cell.editButton.tag = indexPath.row
        cell.editButton.addTarget(self, action: #selector(editButtonPressed), for: .touchUpInside)

这样您就可以访问方法editButtonPressed

中的索引路径
func editButtonPressed(_ sender: UIButton) {

print(sender.tag)//this value will be same as indexpath.row

}

答案 11 :(得分:1)

快速4和5

使用协议委托的方法1

例如,您有一个UITableViewCell,名称为MyCell

class MyCell: UITableViewCell {
    
    var delegate:MyCellDelegate!
    
    @IBAction private func myAction(_ sender: UIButton){
        delegate.didPressButton(cell: self)
    }
}

现在创建一个protocol

protocol MyCellDelegate {
    func didPressButton(cell: UITableViewCell)
}

下一步,创建UITableView的扩展名

extension UITableView {
    func returnIndexPath(cell: UITableViewCell) -> IndexPath?{
        guard let indexPath = self.indexPath(for: cell) else {
            return nil
        }
        return indexPath
    }
}

在您的UIViewController中实施协议MyCellDelegate

class ViewController: UIViewController, MyCellDelegate {
     
    func didPressButton(cell: UITableViewCell) {
        if let indexpath = self.myTableView.returnIndexPath(cell: cell) {
              print(indexpath)
        }
    }
}

使用闭包的方法2

UIViewController

override func viewDidLoad() {
        super.viewDidLoad()
       //using the same `UITableView extension` get the IndexPath here
        didPressButton = { cell in
            if let indexpath = self.myTableView.returnIndexPath(cell: cell) {
                  print(indexpath)
            }
        }
    }
 var didPressButton: ((UITableViewCell) -> Void)

class MyCell: UITableViewCell {

    @IBAction private func myAction(_ sender: UIButton){
        didPressButton(self)
    }
}

注意:-如果要获取UICollectionView indexPath,可以使用此UICollectionView extension并重复上述步骤

extension UICollectionView {
    func returnIndexPath(cell: UICollectionViewCell) -> IndexPath?{
        guard let indexPath = self.indexPath(for: cell) else {
            return nil
        }
        return indexPath
    }
}

答案 12 :(得分:0)

在Swift 3.中也使用了保护语句,避免使用长链。

func buttonTapped(sender: UIButton) {
    guard let cellInAction = sender.superview as? UITableViewCell else { return }
    guard let indexPath = tableView?.indexPath(for: cellInAction) else { return }

    print(indexPath)
}

答案 13 :(得分:0)

有时按钮可能位于UITableViewCell的另一个视图中。在那种情况下,superview.superview可能不会给出单元格对象,因此indexPath将为nil。

在这种情况下,我们应该继续找到超视图,直到我们得到单元格对象。

通过superview获取单元格对象的函数

func getCellForView(view:UIView) -> UITableViewCell?
{
    var superView = view.superview

    while superView != nil
    {
        if superView is UITableViewCell
        {
            return superView as? UITableViewCell
        }
        else
        {
            superView = superView?.superview
        }
    }

    return nil
}

现在我们可以在按钮上点击indexPath,如下所示

@IBAction func tapButton(_ sender: UIButton)
{
    let cell = getCellForView(view: sender)
    let indexPath = myTabelView.indexPath(for: cell)
}

答案 14 :(得分:0)

我发现通过使用Model类,可以非常简单方便地在tableView和collectionView中管理任何单元格,这是一项完美的工作。

现在确实有更好的方法来处理此问题。这将适用于管理单元格和价值

here is my output(screenshote) so see this

这是我的代码

  1. 创建模型分类非常简单,请按照以下步骤操作。 创建名称为“ RNCheckedModel”的swift类,编写如下代码。

RNCheckedModel类:NSObject {

var is_check = false
var user_name = ""

}
  1. 创建您的单元格类

InviteCell类:UITableViewCell {

@IBOutlet var imgProfileImage: UIImageView!
@IBOutlet var btnCheck: UIButton!
@IBOutlet var lblName: UILabel!
@IBOutlet var lblEmail: UILabel!
}
    当您使用 UITableView 时,
  1. 并最终在 UIViewController 中使用模型类。

RNInviteVC类:UIViewController,UITableViewDelegate,UITableViewDataSource {

@IBOutlet var inviteTableView: UITableView!
@IBOutlet var btnInvite: UIButton!

var checkArray : NSMutableArray = NSMutableArray()
var userName : NSMutableArray = NSMutableArray()

override func viewDidLoad() {
    super.viewDidLoad()
    btnInvite.layer.borderWidth = 1.5
    btnInvite.layer.cornerRadius = btnInvite.frame.height / 2
    btnInvite.layer.borderColor =  hexColor(hex: "#512DA8").cgColor

    var userName1 =["Olivia","Amelia","Emily","Isla","Ava","Lily","Sophia","Ella","Jessica","Mia","Grace","Evie","Sophie","Poppy","Isabella","Charlotte","Freya","Ruby","Daisy","Alice"]


    self.userName.removeAllObjects()
    for items in userName1 {
       print(items)


        let model = RNCheckedModel()
        model.user_name = items
        model.is_check = false
        self.userName.add(model)
    }
  }
 @IBAction func btnInviteClick(_ sender: Any) {

}
   func tableView(_ tableView: UITableView, numberOfRowsInSection 
   section: Int) -> Int {
    return userName.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell: InviteCell = inviteTableView.dequeueReusableCell(withIdentifier: "InviteCell", for: indexPath) as! InviteCell

    let image = UIImage(named: "ic_unchecked")
    cell.imgProfileImage.layer.borderWidth = 1.0
    cell.imgProfileImage.layer.masksToBounds = false
    cell.imgProfileImage.layer.borderColor = UIColor.white.cgColor
    cell.imgProfileImage.layer.cornerRadius =  cell.imgProfileImage.frame.size.width / 2
    cell.imgProfileImage.clipsToBounds = true

    let model = self.userName[indexPath.row] as! RNCheckedModel
    cell.lblName.text = model.user_name

    if (model.is_check) {
        cell.btnCheck.setImage(UIImage(named: "ic_checked"), for: UIControlState.normal)
    }
    else {
        cell.btnCheck.setImage(UIImage(named: "ic_unchecked"), for: UIControlState.normal)
    }

    cell.btnCheck.tag = indexPath.row
    cell.btnCheck.addTarget(self, action: #selector(self.btnCheck(_:)), for: .touchUpInside)

    cell.btnCheck.isUserInteractionEnabled = true

return cell

}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return 80

}

@objc func btnCheck(_ sender: UIButton) {

    let tag = sender.tag
    let indexPath = IndexPath(row: tag, section: 0)
    let cell: InviteCell = inviteTableView.dequeueReusableCell(withIdentifier: "InviteCell", for: indexPath) as! InviteCell

    let model = self.userName[indexPath.row] as! RNCheckedModel

    if (model.is_check) {

        model.is_check = false
        cell.btnCheck.setImage(UIImage(named: "ic_unchecked"), for: UIControlState.normal)

        checkArray.remove(model.user_name)
        if checkArray.count > 0 {
            btnInvite.setTitle("Invite (\(checkArray.count))", for: .normal)
            print(checkArray.count)
            UIView.performWithoutAnimation {
                self.view.layoutIfNeeded()
            }
        } else {
            btnInvite.setTitle("Invite", for: .normal)
            UIView.performWithoutAnimation {
                self.view.layoutIfNeeded()
            }
        }

    }else {

        model.is_check = true
        cell.btnCheck.setImage(UIImage(named: "ic_checked"), for: UIControlState.normal)

        checkArray.add(model.user_name)
        if checkArray.count > 0 {
            btnInvite.setTitle("Invite (\(checkArray.count))", for: .normal)
            UIView.performWithoutAnimation {
            self.view.layoutIfNeeded()
            }
        } else {
             btnInvite.setTitle("Invite", for: .normal)
        }
    }

    self.inviteTableView.reloadData()
}

func hexColor(hex:String) -> UIColor {
    var cString:String = hex.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()

    if (cString.hasPrefix("#")) {
        cString.remove(at: cString.startIndex)
    }

    if ((cString.count) != 6) {
        return UIColor.gray
    }

    var rgbValue:UInt32 = 0
    Scanner(string: cString).scanHexInt32(&rgbValue)

    return UIColor(
        red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0,
        green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0,
        blue: CGFloat(rgbValue & 0x0000FF) / 255.0,
        alpha: CGFloat(1.0)
    )
}
override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()

}

 }

答案 15 :(得分:0)

在我的情况下,我有多个节,并且节和行索引都至关重要,因此在这种情况下,我只是在UIButton上创建了一个属性,该属性设置像这样的单元格indexPath:

fileprivate struct AssociatedKeys {
    static var index = 0
}

extension UIButton {

    var indexPath: IndexPath? {
        get {
            return objc_getAssociatedObject(self, &AssociatedKeys.index) as? IndexPath
        }
        set {
            objc_setAssociatedObject(self, &AssociatedKeys.index, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
}

然后像下面这样在cellForRowAt中设置属性:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! Cell
    cell.button.indexPath = indexPath
}

然后在handleTapAction中,您可以像这样获得indexPath:

@objc func handleTapAction(_ sender: UIButton) {
    self.selectedIndex = sender.indexPath

}

答案 16 :(得分:0)

我使用convertPoint方法从tableview获取点并将此点传递给indexPathForRowAtPoint方法以获取indexPath

 @IBAction func newsButtonAction(sender: UIButton) {
        let buttonPosition = sender.convertPoint(CGPointZero, toView: self.newsTableView)
        let indexPath = self.newsTableView.indexPathForRowAtPoint(buttonPosition)
        if indexPath != nil {
            if indexPath?.row == 1{
                self.performSegueWithIdentifier("alertViewController", sender: self);
            }   
        }
    }

答案 17 :(得分:0)

// CustomCell.swift

protocol CustomCellDelegate {
    func tapDeleteButton(at cell: CustomCell)
}

class CustomCell: UICollectionViewCell {
    
    var delegate: CustomCellDelegate?
    
    fileprivate let deleteButton: UIButton = {
        let button = UIButton(frame: .zero)
        button.setImage(UIImage(named: "delete"), for: .normal)
        button.addTarget(self, action: #selector(deleteButtonTapped(_:)), for: .touchUpInside)
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()
    
    @objc fileprivate func deleteButtonTapped(_sender: UIButton) {
        delegate?.tapDeleteButton(at: self)
    }
    
}

//  ViewController.swift

extension ViewController: UICollectionViewDataSource {

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: customCellIdentifier, for: indexPath) as? CustomCell else {
            fatalError("Unexpected cell instead of CustomCell")
        }
        cell.delegate = self
        return cell
    }

}

extension ViewController: CustomCellDelegate {

    func tapDeleteButton(at cell: CustomCell) {
        // Here we get the indexPath of the cell what we tapped on.
        let indexPath = collectionView.indexPath(for: cell)
    }

}

答案 18 :(得分:0)

为行和节使用单个标签

有一种简单的方法可以使用标签同时传输行/项和TableView / CollectionView的部分。

cellForRowAtIndexPath 中为您的UIView.tag

编码 IndexPath :< / p>

buttonForCell.tag = convertIndexPathToTag(with: indexPath)

解码 发件人在目标选择器中的 IndexPath

    @IBAction func touchUpInsideButton(sender: UIButton, forEvent event: UIEvent) {

        var indexPathForButton = convertTagToIndexPath(from: sender)

    }

编码器 解码器:

func convertIndexPathToTag(indexPath: IndexPath) -> Int {
    var tag: Int = indexPath.row + (1_000_000 * indexPath.section)
    
    return tag
}

func convertTagToIndexPath(from sender: UIButton) -> IndexPath {
    var section: Int = Int((Float(sender.tag) / 1_000_000).rounded(.down))
    var row: Int = sender.tag - (1_000_000 * section)

    return IndexPath(row: row, section: section)
}

假设您在32位设备上不需要多于4294967296行/项目;-)例如

  • 42949个节,每行100_000个项目
  • 4294个部分,每行有1_000_000个项目-(就像上面的示例一样
  • 429个节,每行10_000_000个项目

-

警告: 请记住,在TableView / CollectionView中删除或插入行/项目时,必须在插入/删除点之后重新加载所有行/项目,以使按钮的标记号与模型保持同步。

-

答案 19 :(得分:0)

扩展 UITableView 以创建获取视图索引路径的函数:

extension UITableView {
    func indexPath(for view: UIView) -> IndexPath? {
        self.indexPathForRow(at: view.convert(.zero, to: self))
    }
}

使用方法:

let row = tableView.indexPath(for: sender)?.row