Swift - Custom TableView Not Executing Click on UIButton - ios

I am trying to do what I believed was a simple task using Swift. I have created a Custom TableView Cell and added a button to it. I want to be able to just see when you click on the button some action take place. Unfortunately, when I click on the button there is nothing happening. Can someone shed some light on this? I have placed the code below:
Custom TableView Cell:
import UIKit
class TestTableViewCell: UITableViewCell {
#IBOutlet weak var testBtn: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func buttonTappedOnCell()
{
println("buttonTapped!")
}
}
Below is the code in the View Controller which the call is being made:
func tableView(tableView: UITableView,
cellForRowAtIndexPath
indexPath: NSIndexPath) -> UITableViewCell {
tableView.registerNib(UINib(nibName:"TestTableViewCell", bundle:nil), forCellReuseIdentifier:"TestButtonCell")
let cell =
tableView.dequeueReusableCellWithIdentifier("TestButtonCell", forIndexPath: indexPath) as TestTableViewCell
cell.testBtn.addTarget(cell, action: "buttonTappedOnCell", forControlEvents: UIControlEvents.TouchDown)
return cell
}
I also tried changing the call to include the ':' -> cell.testBtn.addTarget(cell, action: "buttonTappedOnCell:", forControlEvents: UIControlEvents.TouchDown) but this did not work. Another thing I tried is moving the call function into the view controller and having the target action point to self. This unfortunately did not work either. A quick example of this working would be great. At the end of day would like to be able to have a custom table view cell that contains 6 radio buttons allowing the user to select just one. But baby steps first at this point. Thanks for any help.

I think the issue is caused by the event you specified in the code.
cell.testBtn.addTarget(cell, action: "buttonTappedOnCell", forControlEvents: UIControlEvents.TouchDown)
Change that ToouchDown to TouchUpInside
cell.testBtn.addTarget(cell, action: "buttonTappedOnCell", forControlEvents: UIControlEvents.TouchUpInside)
Also why are you setting it programmaticaly ? From your code I think you have the button on your storyboard. So why should you add the IBAction programmaticaly ? (Since the action is also invoked on the same class).
Declare your buttonTappedOnCell as an IBAction and connect it directly to your button on storyboard/xib.

Related

How do I pass button action from a nested collectionView cell?

I have a MainCollectionView used for scrolling between items, inside of one of these cells I have another collectionView with cells. In that collection view, I have a button for each cell. My question is how do I pass action from my button to my MainCollectionView when it is tapped? I did create protocol for that button in the cell but I don't know how to let MainCollectionView know when my button is tapped. I can call action from my cell class but I think it is better to run it in Model which is my MainCollectionView. Below is my button protocol.
protocol ThanhCaHotTracksCellDelegate: class {
func handleSeeAllPressed()}
weak var delegate: ThanhCaHotTracksCellDelegate?
#objc func handleSeeAllButton(){
delegate?.handleSeeAllPressed()
}
LIke NSAdi said, you're on the right track, but the delegate pattern is a bit much overhead for just a single task like notifying about a button press.
I prefer using closures, because they're lightweight and helps to keep related code together.
Using Closures
This is what I'm always doing in UITableView. So this will work in UICollectionView too.
class MyTableViewCell: UITableViewCell {
var myButtonTapAction: ((MyTableViewCell) -> Void)?
#IBAction func myButtonTapped(_ sender: Any) {
myButtonTapAction?(self)
}
}
So when I dequeue my cell and cast it to MyTableViewCell I can set a custom action like this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "myCellReuseIdentifier", for: indexPath) as! MyTableViewCell
cell.myButtonTapAction = { cell in
// Put your button action here
// With cell you have a strong reference to your cell, in case you need it
}
}
Using direct reference
When you're dequeueing your UICollectionView cell you can obtain a reference to your button by casting the cell to your cell's custom subclass.
Then just do the following
cell.button.addTarget(self, action: #selector(didTapButton(_:)), forControlEvents: .TouchUpInside)
And outside have a function:
#objc func didTapButton(_ sender: UIButton) {
// Handle button tap
}
Downside of this is that you have no direct access to your cell. You could use button.superview? but it's not a good idea since your view hierarchy could change...
You're on the right track.
Make sure MainCollectionView (or the class that contains) it implements ThanhCaHotTracksCellDelegate protocol.
Then assign the delegate as self.
Something like...
class ViewController: ThanhCaHotTracksCellDelegate {
override func viewDidLoad() {
super.viewDidLoad()
subCollectionView.delegate = self
}
}

Swift 3 - button in .xib custom tableviewcell is not performing action

I have a tableviewcontroller, where i have created custom tableviewcell in a .xib files.
The button (myButton) is used on myCustomTableViewCell.xib has an outlet to myCustomTableViewCell.swift
I have set an action for the button in the TableViewController.swift file
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = Bundle.main.loadNibNamed("myCustomTableViewCell", owner: self, options: nil)?.first as! myCustomTableViewCell
cell.myButton.setTitle(arrayOfMyData[indexPath.row].myText, for:.normal )
//other code to set some other cell.attribute values like above (all works)
cell.myButton.actions(forTarget: "myAction", forControlEvent: .touchUpInside)
}
and elsewhere in the TableViewController.swift I have the action:
func myAction(sender: UIButton){
print("pressed myButton")
}
but myAction is never called / "pressed myButton" is never printed. What am I missing?
You need to use addTarget(_:action:for:) method to add the action for your button not the actions(forTarget:forControlEvent:).
The function actions(forTarget:forControlEvent:) returns the actions that have been added to a control. It doesn't add a target/action.
cell.myButton.addTarget(self,action: #selector(myAction(sender:)), for: .touchUpInside)

Implementing accessoryButtonTappedForRowWithIndexPath: in Swift 2

I'm attempting to implement accessoryButtonTappedForRowWithIndexPath: in Swift 2 on a UITableViewController.
As I explain below, I think I'm missing something in when I create the disclosureIndicator, but I don't know what. It gets drawn from code, but my target action doesn't get called. UGH!
To do this programmatically, my understanding is I need to add the detailDisclosure indicator in cellForRowAtIndexPath before my cell is returned. I'm doing that as follows:
// Create disclosure indicator button in the cell
let disclosureIndicatorButton = UIButton(type: UIButtonType.DetailDisclosure)
disclosureIndicatorButton.addTarget(self, action: "disclosureIndicatorPressed:event:", forControlEvents: UIControlEvents.TouchUpInside)
customCell.accessoryType = .DisclosureIndicator
In my code, the detailDisclosure chevron gets drawn, but the target action method I assigned to it doesn't get called.
Then I need to create a handler for the button when it's pressed:
func disclosureIndicatorPressed(sender: UIButton, event: UIControlEvents) {
print("disclosure button pressed")
// convert touches to CGPoint, then determine indexPath
// if indexPath != nil, then call accessoryButtonTappedForRowWithIndexPath
}
Finally accessoryButtonTappedForRowWithIndexPath contains code to perform the segue, which I can do. What am I missing?
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableViewDelegate_Protocol/#//apple_ref/occ/intfm/UITableViewDelegate/tableView:accessoryButtonTappedForRowWithIndexPath:
Not sure why you are adding disclosure button indicator like that in code.
What you are looking for is simply 2 step process -
Step 1 : Add correct accessoryType on cell:
cell.accessoryType = .DetailDisclosureButton
Step 2 : Take action when the button is tapped by creating the accessoryButtonTappedForRowWithIndexPath function:
override func tableView(tableView: UITableView, accessoryButtonTappedForRowWithIndexPath indexPath: NSIndexPath) {
doSomethingWithItem(indexPath.row)
}

How to know in which cell the button is being tapped using Delegate method. Swift

So i have userListTableViewController and userListTableViewCell in which i am connecting the followButton .. this is the code of my userListTableViewCell
import UIKit
class userListTableViewCell: UITableViewCell {
// IBOutlets..
#IBOutlet var followButton: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func createButton(delegate:AnyObject){
followButton.addTarget(delegate, action: "followButtonTapped:", forControlEvents: UIControlEvents.TouchUpInside)
}
}
and this is my cellForRowAtIndexPath code:
myCell.createButton(self)
and this is the func of followButtonTapped in userListTableViewController
func followButtonTapped(object:AnyObject) {
println("button clicked") // ******************** here i want to know in which cell or indexPath the button is being pressed. or maybe when button is being tapped, change the title of that button.
}
I need some nice explanation where i've marked "******************". Thanks for your time.
I'm holding at any cell the NSIndexPath and assigning it at the cellForRow.
At the delegate method I'm returning the cell itself,
(see the UITableView delegate functions - they deliver the UITableView), So at the delegate function you have the relevant cell, and it has the relevant NSIndexPath.
Pay attention - if you assigning the NSIndexPath - any change of the cells like adding row or removing one will make the old NSIndexPath of the other cells to be not true...
Set the button tag to the indexPath.row in your cellForRowAtIndexPath code, and set your followButtonTapped method as an #IBAction with a UIButton parameter, rather than AnyObject
So in your cellForRowAtIndexPath add this:
myCell.followButton.tag = indexPath.row
and change your followButtonTapped method to be:
#IBAction func followButtonTapped (sender: UIButton!) {
println("\(sender.tag) button pressed")
}
You will have to connect followButtonTapped to your follow button in IB, but then should be good to go.
TableView didSelectRowAtIndexPath function is called on click of cell.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)

UIButton in custom cell not working

I have a button in a custom cell
class CardTableViewCell: UITableViewCell {
#IBOutlet weak var detailsButton: UIButton!
}
in my view controller then I do this
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//.....more code....
openDealCell.detailsButton.addTarget(self, action: "push:", forControlEvents: UIControlEvents.TouchUpInside)
}
and then:
func push(sender:AnyObject) {
println("tap")
}
But when I clicked the button nothing happens.
What I am doing wrong?
Fix it! The problem was not in the code but in my cell in the storyboard:
where user interaction for the cell wasn't enabled and all the other view didn't allow the user interaction.
Right now I created demo project with exactly the same code as your and it works. Please check here at GitHub. The issue definitely in the other stuff that you didn't show us, that code does not have any problems

Resources