get indexPath of UITableViewCell on click of Button from Cell
Asked Answered
N

10

16

Please Look at this image

I have a button (red color cross) in the UITableViewCell and on click of that button I want to get indexPath of the UITableViewCell.

Right now I am assigning tag to each of the button like this cell.closeButton.tag = indexPath.section and the on click of the button I get the indexPath.section value like this:

@IBAction func closeImageButtonPressed(sender: AnyObject) {
  data.removeAtIndex(sender.tag)
  tableView.reloadData()
}

Is this the right way of implementation or is there any other clean way to do this?

Newbill answered 20/9, 2016 at 4:23 Comment(5)
By the way, why are you reloading the entire table after you delete a section? Just call tableView.deleteSections(NSIndexSet(index: sender.tag), withRowAnimation: .None) instead.Cowbird
Ya I can do that.Newbill
perhaps you can give a look at the following thread: https://mcmap.net/q/247116/-swift-i-want-to-know-what-is-the-index-path-row-of-the-button-that-i-clickedKelsey
were you able to resolve the issue?Trellis
@Mr.Bista yes I did.Newbill
T
55

Use Delegates:

MyCell.swift:

import UIKit

//1. delegate method
protocol MyCellDelegate: AnyObject {
    func btnCloseTapped(cell: MyCell)
}

class MyCell: UICollectionViewCell {
    @IBOutlet var btnClose: UIButton!

    //2. create delegate variable
    weak var delegate: MyCellDelegate?

    //3. assign this action to close button
    @IBAction func btnCloseTapped(sender: AnyObject) {
        //4. call delegate method
        //check delegate is not nil with `?`
        delegate?.btnCloseTapped(cell: self)
    }
}

MyViewController.swift:

//5. Conform to delegate method
class MyViewController: UIViewController, MyCellDelegate, UITableViewDataSource,UITableViewDelegate {

    //6. Implement Delegate Method
    func btnCloseTapped(cell: MyCell) {
        //Get the indexpath of cell where button was tapped
        let indexPath = self.collectionView.indexPathForCell(cell)
        print(indexPath!.row)
    }

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

        let cell = tableView.dequeueReusableCellWithIdentifier("MyCell") as! MyCell
        //7. delegate view controller instance to the cell
        cell.delegate = self

        return cell
    }
}
Trellis answered 20/9, 2016 at 4:34 Comment(0)
D
6

How to get cell indexPath for tapping button in Swift 4 with button selector

@objc func buttonClicked(_sender:UIButton){

 let buttonPosition = sender.convert(CGPoint.zero, to: self.tableView)
 let indexPath = self.tableView.indexPathForRow(at:buttonPosition)
 let cell = self.tableView.cellForRow(at: indexPath) as! UITableViewCell
 print(cell.itemLabel.text)//print or get item
}
Dogfish answered 15/11, 2017 at 8:8 Comment(0)
A
4

Try with the best use of swift closures : Simple, Quick & Easy.

In cellForRowAtIndexPath method:

let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCellIdentifier", for: indexPath) as! CustomCell

cell.btnTick.mk_addTapHandler { (btn) in
     print("You can use here also directly : \(indexPath.row)")
     self.btnTapped(btn: btn, indexPath: indexPath)
}

Selector Method for external use out of cellForRowAtIndexPath method:

func btnTapped(btn:UIButton, indexPath:IndexPath) {
    print("IndexPath : \(indexPath.row)")
}

Extension for UIButton :

extension UIButton {

    private class Action {
        var action: (UIButton) -> Void

        init(action: @escaping (UIButton) -> Void) {
            self.action = action
        }
    }

    private struct AssociatedKeys {
        static var ActionTapped = "actionTapped"
    }

    private var tapAction: Action? {
        set { objc_setAssociatedObject(self, &AssociatedKeys.ActionTapped, newValue, .OBJC_ASSOCIATION_RETAIN) }
        get { return objc_getAssociatedObject(self, &AssociatedKeys.ActionTapped) as? Action }
    }


    @objc dynamic private func handleAction(_ recognizer: UIButton) {
        tapAction?.action(recognizer)
    }


    func mk_addTapHandler(action: @escaping (UIButton) -> Void) {
        self.addTarget(self, action: #selector(handleAction(_:)), for: .touchUpInside)
        tapAction = Action(action: action)

    }
}
Appalachia answered 14/3, 2019 at 7:4 Comment(0)
T
3

In Swift 4 , just use this:

func buttonTapped(_ sender: UIButton) {

    let buttonPostion = sender.convert(sender.bounds.origin, to: tableView)

    if let indexPath = tableView.indexPathForRow(at: buttonPostion) {
        let rowIndex =  indexPath.row
    }
}
Tortoni answered 13/6, 2018 at 12:25 Comment(0)
F
0

try this:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    var cell = (tableView.dequeueReusableCell(withIdentifier: "MainViewCell", forIndexPath: indexPath) as! MainTableViewCell)
    cell.myButton().addTarget(self, action: Selector("myClickEvent:event:"), forControlEvents: .touchUpInside)
    return cell
}

this function get the position of row click

@IBAction func myClickEvent(_ sender: Any, event: Any) {
    var touches = event.allTouches()!
    var touch = touches.first!
    var currentTouchPosition = touch.location(inView: feedsList)
    var indexPath = feedsList.indexPathForRow(atPoint: currentTouchPosition)!
    print("position:\(indexPath.row)")
}
Facture answered 20/9, 2016 at 4:28 Comment(0)
T
0

You can also get NSIndexPath from CGPoint this way:

@IBAction func closeImageButtonPressed(sender: AnyObject) {
    var buttonPosition = sender.convertPoint(CGPointZero, to: self.tableView)
    var indexPath = self.tableView.indexPathForRow(atPoint: buttonPosition)!
}
Tees answered 20/9, 2016 at 4:28 Comment(1)
CGPointZero is a point constant with location (0,0). The zero point is equivalent to CGPointMake(0,0). And it will convert your buttonPosition to indexpath.Tees
R
0

Create a custom class of UIButton and declare a stored property like this and use it to retrieve assigned indexPath from callFroRowAtIndexPath.

class VUIButton: UIButton {
    var indexPath: NSIndexPath = NSIndexPath()
}

This is the full proof solution that your indexPath will never be wrong in any condition. Try once.

Rochelrochell answered 20/9, 2016 at 5:1 Comment(0)
O
0

In your cellForRow:

#import <objc/runtime.h>

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    setAssociatedObject(object: YOURBUTTON, key: KEYSTRING, value: indexPath)
}

@IBAction func closeImageButtonPressed(sender: AnyObject) {
    let val = getAssociatedObject(object: sender, key: KEYSTROKING)
}

Here val is your indexPath object, your can pass any object like you can assign pass cell object and get it in button action.

Orthostichy answered 20/9, 2016 at 5:15 Comment(0)
E
0
//
//  ViewController.swift
//  Table
//
//  Created by Ngugi Nduung'u on 24/08/2017.
//  Copyright © 2017 Ngugi Ndung'u. All rights reserved.
//

import UIKit

class ViewController: UITableViewController{

    let identifier = "cellId"
    var items = ["item1", "2", "3"]
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        self.title = "Table"
        tableView.register(MyClass.self, forCellReuseIdentifier: "cellId")
    }

    //Return number of cells you need
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
        return items.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath) as! MyClass
        cell.controller = self
        cell.label.text  = items[indexPath.row]
        return cell

    }

    // Delete a cell when delete button on cell is clicked 
    func delete(cell: UITableViewCell){
        print("delete")
        if let deletePath = tableView.indexPath(for: cell){
            items.remove(at: deletePath.row)
            tableView.deleteRows(at: [deletePath], with: .automatic)
        }

    }

}

class MyClass : UITableViewCell{
    var controller : ViewController?
    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
            super.init(style: style, reuseIdentifier: reuseIdentifier)
            setUpViews()
    }

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

    let label : UILabel = {
        let label = UILabel()
        label.text = "My very first cell"
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    let btn : UIButton = {
       let bt = UIButton(type: .system)
        bt.translatesAutoresizingMaskIntoConstraints = false
        bt.setTitle("Delete", for: .normal)


        bt.setTitleColor(.red, for: .normal)
        return bt
    }()

    func handleDelete(){
       controller?.delete(cell: self)
    }
    func setUpViews(){
        addSubview(label)
        addSubview(btn)
        btn.addTarget(self, action: #selector(MyClass.handleDelete), for: .touchUpInside)
        btn.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
        label.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 16).isActive = true
        label.widthAnchor.constraint(equalTo: self.widthAnchor , multiplier: 0.8).isActive = true
        label.rightAnchor.constraint(equalTo: btn.leftAnchor).isActive = true

    }
}

Here is a full example that will answer your question.

Endeavor answered 22/11, 2017 at 8:39 Comment(0)
M
0
class MyCell: UICollectionViewCell {

   @IBOutlet weak var btnPlus: UIButton!

}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> 
 UITableViewCell {


cell.btnPlus.addTarget(self, action: #selector(increment_Action(sender:)), 
 for: .touchUpInside)
cell.btnPlus.tag = indexPath.row
cell.btnPlus.superview?.tag = indexPath.section
}

@objc func increment_Action(sender: UIButton) {
        
let btn = sender as! UIButton
let section = btn.superview?.tag ?? 0

let row = sender.tag
}
Mauritius answered 21/10, 2020 at 15:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.