In my UITableView I've many cells created like this:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell")! as UITableViewCell
let btn = cell.viewWithTag(1001) as! UIButton
btn.tag = indexPath.row
btn.addTarget(cell, action: Selector(myFunc(btn)), forControlEvents: .TouchUpInside)
...
}
I can't understand why myFunc() is called automatically when the UITableView is populated. (without touching any buttons)
Change your addTarget method something like this
btn.addTarget(self, action:#selector(myFunc(_:)), forControlEvents: .TouchUpInside)
Because you given the target of the function in the cell, so target call automatically in the cellRowAtIndexPath without touching any button. First you remove cell from the target and write self. It says the function declare the same class. If you access function from any other class then write the class name.
btn.addTarget(self, action: Selector(myFunc(btn)), forControlEvents: .TouchUpInside)
Related
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)
I'm trying to add the download button for some items in my tableView. I've created the custom cell class and added the label and the button outlets, everything is working in displaying the info and even the buttons are showing where it should be.
I'm trying to add the target, but it does nothing. I need to pass the row index to the buttonClicked function or should I create this function in the custom cell class and then do the action some how? I would like to know the best practise of this.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "PlaylistCell", for: indexPath) as! PlaylistTableViewCell
let playlist = self.playlists?[indexPath.row]
cell.titleLabel.text = playlist?.getTitle()
if (playlist?.isOfflineAvailable())! {
cell.downloadButton.isHidden = false
} else {
cell.downloadButton.isHidden = true
cell.downloadButton.tag = indexPath.row
cell.downloadButton.addTarget(self, action: #selector(buttonClicked(sender:)), for: .touchUpInside)
}
return cell
}
func buttonClicked(sender: UIButton) {
let buttonRow = sender.tag
print(buttonRow)
}
I've also tried removing the (sender:) from #selector, but it does not change a functionality.
In order to handle button callback in your view controller, you have two choices:
Target-action:
Add target-action in cellForRow method just as you did. Your code is probably not working because you are hiding the button when it should be visible, aren't you?
I guess you need to replace this
if (playlist?.isOfflineAvailable())! {
cell.downloadButton.isHidden = false
} else {
cell.downloadButton.isHidden = true
cell.downloadButton.tag = indexPath.row
cell.downloadButton.addTarget(self, action: #selector(buttonClicked(sender:)), for: .touchUpInside)
}
With this:
cell.downloadButton.isHidden = playlist?.isOfflineAvailable()
cell.downloadButton.tag = indexPath.row
cell.downloadButton.addTarget(self, action: #selector(buttonClicked(sender:)), for: .touchUpInside)
You should update tag every time because cell are reused in tableView and if don't do it every time when cellForRow is called, you may easilly get a case when a callback is called but it's tag belongs to indexPath from the previous cell usage. Also I've changed isHidden logics to the opposite. I guess you should hide the button when isOfflineAvailable returns true, right?
Delegate pattern
It is described a million of times here on SO and on many other sites as well. Basically you define a cell protocol, implement it in your controller and send callbacks from cell to it's delegate whenever a button is pressed. You can find more details in my answer for a similar question.
I am very puzzled.
In my cellForRowAtIndexPath method, I am trying to set a UIButton title:
Not working:
cell?.react?.setTitle("\(currentObject.likes)", forState: UIControlState.Normal)
where react is a UIButton, that is a subview of my UITableViewCell subclass.
I can't seem to update the title of my UIButton at all. The only way I have found to modify it is through the UITapGestureRecognizer in my UITableViewCell subclass,
Working:
func reaction(button : UIButton) {
if button.imageView?.image == UIImage(named: "ic_favorite.png") {
button.setImage(UIImage(named: "ic_favorite_border.png"), forState: UIControlState.Normal)
} else {
button.setImage(UIImage(named: "ic_favorite.png"), forState: UIControlState.Normal)
}
}
Create a custom cell (say myCell), add the button as an #IBOutlet, then type this let cell = tableView.dequeueReusableCellWithIdentifier("yourIdentifier", forIndexPath: indexPath) as! myCell.
Your problem I think is that you haven't linked the button to the cell & XCode doesn't know which button you are talking about.
You should first get a reference to your cell with cellForRowAtIndexPath passed to your method.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("MyCellIdentifier", forIndexPath: indexPath) as! UIButton
// do anything with cell
return cell
}
Remember to set an identifier for your Table View Cell (UITableViewCell).
// try like this, first give tag for that button in your table cell
(cell?.contentView.viewWithTag(tag) as? UIButton)?.setTitle("\(currentObject.likes)", forState: UIControlState.Normal)
I'm using a custom TableViewCell in my iOS app. I use the method tableViewDidSelectRowAtIndexPath to open a new ViewController. What I need to do is to add a button or an image somewhere in the custom cell so if I tap the button or whatever element don't open the ViewController, but execute a function without opening the cell.
set [cell.button setTag:indexPath.row] in cellForRowAtIndexPath method.
and than addTarget to cell.button like
[cell.button addTarget:self action:#selector(yourAction:) forControlEvents:UIControlEventTouchUpInside]];
and than do Whatever you want to do in yourAction
with getting tag from sender.
Or you want code for that than please add your code what you had done so we can help more if you are new in iOS.
This code may helps you
here i have used custom buttom in table and add target to that buton
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell: AnyObject = tableView.dequeueReusableCellWithIdentifier("CellIdentifier", forIndexPath: indexPath)
// use your custom cell here
//cell = UIColor.redColor()
//cell.textLabel?!.text = String(data[indexPath.row])
//nameTextField.text = ""
let custom_btn : UIButton? = UIButton.init(type: .System)
//declaring custom button
custom_btn?.setTitle("custom button", forState: .Normal)
custom_btn!.tag = indexPath.row
custom_btn!.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)
cell .addSubview(custom_btn!);
return cell as! UITableViewCell
}
func buttonClicked(sender:UIButton)
{
if(sender.tag == 5){
//Do something for tag
}
print("hello")
}
I have taken UIbutton on TableViewCell, but when I click on a row, only the row get clicked, but I want to click only the button on that row.
How is this possible?
In the CellForRowatindexPath define tag for button and also set target to handler the event
button.tag=indexPath.row;
button.addTarget(self, action: "buttonHandler:", forControlEvents: UIControlEvents.TouchUpInside)
*************
func buttonHandler(sender:UIButton!)
{
if(sender.tag==0){
println("Button at row 0")
}
else if(sender.tag==1){
println("Button at row 1")
}
}
you set click event for cell Button try this way
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
cell.yourButton.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)
}
func buttonClicked(sender:UIButton!)
{
println("Button tapped")
}
First do one thing
cell.selectionStyle = UITableViewCellSelectionStyleNone;
// This will disable the selection highlighting.
Then create IBOutlet of your button in Cell class (Don't create the IBAction yet!!!)
Then in your CellForRowatindexPath create the action of button like this
button.addTarget(self, action: "buttonAction:", forControlEvents: UIControlEvents.TouchUpInside)
then create the button action Function
func buttonAction(sender:UIButton!)
{
println("Button tapped")
}
Check it. Hope it helps!!!!