Identify in which table view Cell button was pressed?

Multi tool use
Multi tool use


Identify in which table view Cell button was pressed?



I have table view cells like quiz. And in each cell I have a buttons And how can I identify in which cell button was pressed. Maybe by IndexPath???
This is how I connected button to


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "QuestionCell")!
variant1 = cell.contentView.viewWithTag(1) as! UIButton
variant2 = cell.contentView.viewWithTag(2) as! UIButton
variant3 = cell.contentView.viewWithTag(3) as! UIButton
variant4 = cell.contentView.viewWithTag(4) as! UIButton

variant1.addTarget(self, action: #selector(self.variant1ButtonPressed), for: .touchUpInside)
variant2.addTarget(self, action: #selector(self.variant2ButtonPressed), for: .touchUpInside)
variant3.addTarget(self, action: #selector(self.variant3ButtonPressed), for: .touchUpInside)
variant4.addTarget(self, action: #selector(self.variant4ButtonPressed), for: .touchUpInside)

return cell
}

func variant1ButtonPressed() {
print("Variant1")
variant1.backgroundColor = UIColor.green


}
func variant2ButtonPressed() {
print("Variant2")
variant2.backgroundColor = UIColor.green


}
func variant3ButtonPressed() {
print("Variant3")
variant3.backgroundColor = UIColor.green

}
func variant4ButtonPressed() {
print("Variant4")
variant4.backgroundColor = UIColor.green

}



This is how it looks like in Storyboard: enter image description here




5 Answers
5



Use this line to get indexPath, Where you have to pass UIButton on target selector


UIButton


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





exchange CGPointZero to CGPoint.zero It has helped me ! Thanx
– Азамат Булегенов
Jul 13 '17 at 10:36





Thank you , It is very important to work with rect rather than setting tag as per indexpath , In case of row deletion or adding may cause problem in that case , so it is very safe idea to go with rect
– Prashant Tukadiya
Jul 13 '17 at 12:22




You should use delegate pattern, basic example:


protocol MyCellDelegate {
func didTapButtonInside(cell: MyCell)
}

class MyCell: UITableViewCell {

weak var delegate: MyCellDelegate?

func buttonTapAction() {
delegate?.didTapButtonInside(cell: self)
}
}

class ViewController: MyCellDelegate {

let tableView: UITableView

func didTapButtonInside(cell: MyCell) {
if let indexPath = tableView.indexPath(for: cell) {
print("User did tap cell with index: (indexPath.row)")
}
}
}



Since actions need to be inside the view controller, ctrl + drag from your button to the view controller - this will use the responder chain.



Basically you need to convert the view (button) to the coordinate system of the table view in order to tell what is the IndexPath and if you have the IndexPath you have the object that corresponds to the button inside the cell that was tapped:


@IBAction func buttonTapped(_ sender: Any)
{
if let indexPath = getIndexPath(of: sender)
{
// Your implementation...
}
}

private func getIndexPath(of element:Any) -> IndexPath?
{
if let view = element as? UIView
{
// Converting to table view coordinate system
let pos = view.convert(CGPoint.zero, to: self.tableView)
// Getting the index path according to the converted position
return tableView.indexPathForRow(at: pos) as? IndexPath
}
return nil
}



It is important to mention that there many solutions for your question. But you should know that in Apple's sample projects they also use this technic.





I'd recommend against force casting in any code base. Don't use ! when you can avoid it, be wary of crashes.
– cloudcal
Jul 13 '17 at 7:45





@cloudcal Correct, code snip updated
– OhadM
Jul 13 '17 at 9:09





It looks like you're still force casting. Why cast at all? just return tableView.indexPathForRow(at: pos)
– cloudcal
Jul 14 '17 at 18:48


tableView.indexPathForRow(at: pos)





@cloudcal, Of course I am force casting, I'v validated that the return object isn't nil. But you are correct again since I am already returning optional type. Code updated :)
– OhadM
Jul 15 '17 at 12:13





Right. But according to OP, buttons are attached inside the UITableViewCells. It's better to send a delegate call with the UITableViewCell, i.e., func tableViewCellDidTapButton(_ cell: UITableViewCell) back to the controller, and then call tableView.indexPath(for: UITableViewCell) if you need to know which row, or just operate on the cell itself since a pointer to it is sent back with the delegate.
– cloudcal
Jul 16 '17 at 5:52


UITableViewCell


func tableViewCellDidTapButton(_ cell: UITableViewCell)


tableView.indexPath(for: UITableViewCell)



This is how you add tag to a UIButton inside UITableView, add below lines of code in


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

cell.yourButton.tag = indexPath.row
cell.yourButton.addTarget(self, action:#selector(btnPressed(sender:)), for: .touchUpInside)



Add this function in your ViewController


func btnPressed(sender: UIButton)
{
print("Button tag (sender.tag)")
}



Hope this helps...



Simple Subclass button just like JSIndexButton


class JSIndexButton : UIButton {

var indexPath : IndexPath!

}



Now at cellForRowAt


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

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

let itemCategory = dataList[button.indexPath.section];
let item = itemCategory.items[button.indexPath.row];

cell.imgView.setImageWithURL(item.photoUrl);
cell.btnBuy.indexPath = indexPath;
cell.btnBuy.addTarget(self, action: #selector(JSCollapsableTableView.btnBuyPressed(_:)), for: UIControlEvents.touchUpInside)

return cell;

}



Check Button Action


@IBAction func btnBuyPressed(_ button: JSIndexButton) {

let itemCategory = dataList[button.indexPath.section];
let item = itemCategory.items[button.indexPath.row];

}






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

rq3TjPp7Rd,3Rfl A NKvL l80ok
QK64dgwCsM LH0 Od baDKSAYZCW h 01fg,oEI88wvGr8KHc

Popular posts from this blog

PySpark - SparkContext: Error initializing SparkContext File does not exist

django NoReverseMatch Exception

List of Kim Possible characters