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.
Related
I have a tableview with two buttons and a label and I want to save the text in the label in two different arrays based on the button I select.
| _Add Button_______Label______________Favourites Button___|
| _Add Button_______Label______________Favourites Button___|
When I select the add button I want the label to be saved in Add Button Array and when I select the Favorites Button I want to save the text in favorites.
The code I did below works fine for the Add Button but always stores the first cell for the favorite button. What am I missing here?
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! SegmentControlCell
cell.addPointsLabel.text? = SegmentNetworkCallObj.AFResponse[indexPath.row]["Description"] as? String ?? ""
cell.addTaskButton.tag = indexPath.row
cell.addTaskButton.addTarget(self, action: #selector(addButtontapped(_:)), for: .touchUpInside)
cell.addTaskButton.addTarget(self, action: #selector(favouriteButtonTapped(_:)), for: .touchUpInside)
return cell
}
//Button Selection
#IBAction func addButtontapped(_ sender: Any) {
let selectedTask = SegmentNetworkCallObj.AFResponse[(sender as AnyObject).tag]["Description"]
dailyDeedsArray.append(selectedTask as! String)
print("addbutton",dailyDeedsArray)
}
#IBAction func favouriteButtonTapped(_ sender: Any) {
let selectedTask = SegmentNetworkCallObj.AFResponse[(sender as AnyObject).tag]["Description"]
favouritesArray.append(selectedTask as! String)
print("favourites",favouritesArray)
}
It seems that you have 2 buttons in each cell, one called addTaskButton and another presumably called addFavoriteButton or something similar, but you only assign & update the tag value for addTaskButton in the tableView delegate method, which is a problem for your favorites button because you access (sender as AnyObject).tag in both IBAction methods. Also, you assign 2 different targets for addTaskButton, which I guess is a mistake.
I think the code should look something like this:
cell.addTaskButton.tag = indexPath.row
cell.addTaskButton.addTarget(self, action: #selector(addButtontapped(_:)), for: .touchUpInside)
cell.addFavoriteButton.tag = indexPath.row
cell.addFavoriteButton.addTarget(self, action: #selector(favouriteButtonTapped(_:)), for: .touchUpInside)
My question:
I wanna perform segue to two different destinations in a table view cell. One is directing destination "A" by clicking the cell which handled by didSelectRowAt, Another one is directing to destination "B" by clicking the button inside the cell, for example, the labelName.
For destiation "B", I have try to use (btn.addTarget), but it cannot add parameters, so the destinatin view controller do not know the which cell was being clicked.
Any suggestion?
You can Get the indexPath of your selected TableviewCell in your btnClick function by using this.
let index = self.tableview.indexPathForSelectedRow
Now by doing this you can solve this problem you mentioned.
the destinatin view controller do not know the which cell was being clicked
you can use button.tag and assign the tag of every button with your indexpath.row
button.tag = indexPath.row
button.addTarget(self, action: "btnClick:", forControlEvents: UIControlEvents.TouchUpInside)
func btnClick(sender:UIButton) {
let buttonRow = sender.tag
}
for swift 4 :
button.addTarget(self, action: #selector(händlerButtonTapped), for: .touchUpInside)
#objc func händlerButtonTapped(sender:UIButton) {
let buttonRow = sender.tag
}
Here is my cellForRowAt:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! contentTableViewCell
let content: contentModel
content = contentList[indexPath.row]
contentViewController().getUserProfilePic(userID:content.userID!)
cell.detailLabelName.text = content.name
cell.detailLabelTime.text = content.time
cell.detailTextViewContent.text = content.content
if UserDefaults.standard.data(forKey:content.userID!) != nil {
cell.detailImageSelfie.image = UIImage(data:UserDefaults.standard.data(forKey:content.userID!)!)
} else {
cell.detailImageSelfie.image = #imageLiteral(resourceName: "defaultIcon")
}
return cell
}
I have 2 VCs, one of them is called HomeVC the other is DetailVC. I have a table view on HomeVC which displays cells with a label and a button. DetailVC just has a label. I am displaying an array of strings on the table view and when the button on the cell is clicked i want to carry the text in the label to the DetailVC's label.
Now i can easily do this with either didSelectRowAt method or using indexPathForSelectedRow in prepare segue method. But both cases requires me to tap on the cell itself but not the button.
I am just a beginner in swift. But to explain this there shouldn't be need for much code. So if you can, please explain with detail.
Thanks in advance.
In cellForRowAt add target to button i.e
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellID", for: indexPath)
cell.button.tag = indexPath.row
cell.button.addTarget(self, action: Selector("buttonAction:"), for: .touchUpInside)
// other cell element setup
return cell
}
And at button action get the item from array using button tag i.e
func buttonAction(sender: UIButton) {
let data = tableArray[sender.tag]
// logic to pass present detailVC
}
Hope this will work!!
If you are using collection view you can use the following
// Set The Click Action On Button
cell.bProfileImage.addTarget(self, action: #selector(connected(sender:)), for:
.touchUpInside)
cell.bProfileImage.tag = indexPath.row
Then in your function
// Function For TouchUpInside For Cell
#objc func connected(sender: UIButton) {
let data = individualChatsListArray[sender.tag]
print(data.name)
}
I have a tableView in which i post users feeds and i added a heart button for like in the cell view. I created a class for the cell view and declared my #IBOutlet of the button there. Then in the cellForRowAtIndexPath in the tableview i called the button and made the indexpath.row the tag number of the button itself. Then i added a target with an action to be done and created my #IBAction. Now I'm trying to change the image look of the heart button to red but nothing happens. Is there a problem passing the an UIImage to the button via the sender. I have no errors. And the if like = statement is working correctly. Here is my code:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! PostsCellTableViewCell
cell.heartButton.tag = indexPath.row
cell.heartButton.addTarget(self, action: "liked:", forControlEvents: .TouchUpInside)
return cell
}
#IBAction func liked (sender: UIButton){
if like == false{
sender.imageView?.image = UIImage(contentsOfFile: "red-heart.png")
like = true
}
else{
sender.imageView?.image = UIImage(contentsOfFile: "white-heart-hi.png")
like = false
}
// self.tableView.reloadData()
}
Try this instead.
if like == false{
sender.setImage(UIImage(named: "red-heart.png"), forState: .Normal)
like = true
} else {
sender.setImage.setImage(UIImage(named: "white-heart-hi.png"), forState: .Normal)
like = false
}
This is a really simple error. You declared your target function as "liked:", but your function is declared as "liked". Notice the lack of a colon the second time. This is critical, and should fix the problem. If this does not fix the problem, make sure you have declared
var like = false
If this still doesn't work, comment and I will continue helping. If it does work, don't forget to check my answer.
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")
}