How to reload tableView from custom cell? Cell has two buttons inside if the button is clicked table should reload.
I was trying to add protocol inside UITableViewCell File and reload it once the button is clicked but the protocol function inside UITableViewController is not being called.
Here the code inside UITableViewCell:
protocol reloadTableDelegate {
func reloadTableonClick()
}
class TableViewCell: UITableViewCell {
var delegate : reloadTableDelegate?
#IBOutlet weak var button2: UIButton!
#IBOutlet weak var button1: UIButton!
var button1Clicked = false
var button2clicked = false
#IBAction func button1Action(_ sender: Any) {
button2clicked = true
delegate?.reloadTableonClick()
}
#IBAction func button2Action(_ sender: Any) {
delegate?.reloadTableonClick()
}
}
This is what I am doing inside UITableView to reload table:
extension TableViewController : reloadTableDelegate {
func reloadTableonClick() {
tableView.reloadData()
}
}
First you need to add an action to the button. You can do it like this:
if myButton.target(forAction: #selector(self.myButtonTapped()), withSender: nil) == nil { //Check that we don't add it multiple times
myButton.addTarget(self, action: #selector(self.myButtonTapped()), for: .touchUpInside)
}
This line has to be inside the cellForRowAtIndexPath.
Then in your view controller make a function like this:
func myButtonTapped() {
self.tableView.reloadData()
}
From the example you provided in your code you should also be setting the delegate to the cell. Meaning in cellForRowAtIndexPath you should set:
myCell.delegate = self
And in your view controller implement those methods like you're already doing.
try adding tableView.reloadData() anytime it needs to update.
Related
I've a custom UITableViewCell, in that I've two UILabels & one UIButton. I'm able to load data...and display it as per requirement.
Problem Statement-1: Now problem exist in my UIButton, which is in my UICustomTableViewCell. Due to this I'm unable to handle click event on that UIButton.
Problem Statement-2: On button Click I have to identify the index of that Button click and pass data to next ViewController using segue.
Now have a look on...what did I've tried for this...
Yes, first-of-all I have thought that Binding IBOutlet action in my CustomCell will resolve my problem...but actually it doesn't solved my problem.
After that I've accessed button using .tag and initialised index path.row to it.
But it won't helped me.
So now I'm using Protocol oriented concept using delegate to handle click event on my UIButton which is available in CustomCell.
What did I tried:
SwiftyTableViewCellDelegate:
protocol SwiftyTableViewCellDelegate : class {
func btnAuditTrailDidTapButton(_ sender: LeadCustomTableViewCell)
}
CustomTableViewCell with delegate:
class LeadCustomTableViewCell: UITableViewCell {
#IBOutlet weak var lblMeetingPersonName: UILabel!
#IBOutlet weak var lblPolicyNo: UILabel!
#IBOutlet weak var btnLeadAuditTrail: UIButton!
weak var delegate: SwiftyTableViewCellDelegate?
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
#IBAction func btnAuditTrailTapped(_ sender: UIButton) {
delegate?.btnAuditTrailDidTapButton(self)
}
}
ViewController implementing delegate:
class LeadViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, SwiftyTableViewCellDelegate {
//IBOutlet Connections - for UITableView
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
//setting dataSource & delegates of UITableView with this ViewController
self.tableView.dataSource = self
self.tableView.delegate = self
//Reloading tableview with updated data
self.tableView.reloadData()
//Removing extra empty cells from UITableView
self.tableView.tableFooterView = UIView()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:LeadCustomTableViewCell = self.tableView.dequeueReusableCell(withIdentifier: "cell") as! LeadCustomTableViewCell
//Assigning respective array to its associated label
cell.lblMeetingPersonName.text = (meetingPersonNameArray[indexPath.section] )
cell.lblPolicyNo.text = (String(policyNoArray[indexPath.section]))
cell.btnLeadAuditTrail.tag = indexPath.section
cell.delegate = self
return cell
}
//This is delegate function to handle buttonClick event
func btnAuditTrailDidTapButton(_ sender: LeadCustomTableViewCell) {
guard let tappedIndexPath = tableView.indexPath(for: sender) else { return }
print("AuditTrailButtonClick", sender, tappedIndexPath)
}
Don't know why this is not working.
Link the touch up inside event in cellForRow by adding the following code:
cell.btnLeadAuditTrail.addTarget(self, action:#selector(btnAuditTrailDidTapButton(_:)), for: .touchUpInside)
I have used the same nib file to populated a UITableView. There are 2 different functionalities I have built out for these cells. If you anywhere on the cell other than a small button it runs a function and segues to another page. However if you click the small button, I want to update the UITableView and input a cell below the clicked cell, as a sort of dropdown. I have the below to successfully run a separate functionality:
import UIKit
class ContactCell: UITableViewCell {
//below are the outlets for the conact cells
#IBOutlet weak var msgStatus: UIView!
#IBOutlet weak var contactName: UILabel!
#IBOutlet weak var dropDown: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
msgStatus.layer.cornerRadius = msgStatus.frame.size.width/2
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
#IBAction func dropDown(_ sender: Any) {
print("selected drop down")
}
}
Moving forward I need to be able to get the index of the current cell and perform a UITableView update from the UITableViewCell's class. How would I be able to do this?
You could do this with delegation. Create a delegate protocol for your ContactCell:
protocol ContactCellDelegate {
func pleaseAddDropdown(to: ContactCell)
}
Then set up a delegate parameter for the cell:
var delegate: ContactCellDelegate?
Then subscribe your table view to the ContactCellDelegate protocol (you will have to subclass if you are using a standard UITableView). This means you will need to write an implementation of pleaseAddDropdown() for your table view class. When you dequeue a cell make sure the delegate parameter is assigned to your table view.
Now in your implementation of dropdown() you just need to do something like:
guard let _ = delegate else { return }
delegate!.pleaseAddDropdown(to: self)
Which will send that message up to the table view which can take the appropriate action.
Hope that helps.
I am trying to implement the Delegate way to do some action on a button tap from my UITableViewCell to a ViewController. The following is what I have so far -
TableViewCell:
protocol UserCellDelegate : class {
func disableUser(cell: UserCell, button: UIButton)
}
class UserCell : UITableViewCell {
#IBOutlet weak var userLabel: UILabel!
#IBOutlet weak var userDescription: UILabel!
#IBOutlet weak var writeOutUser: UIButton!
weak var delegate: UserCellDelegate?
override func awakeFromNib() {
super.awakeFromNib()
writeOutUser.layer.cornerRadius = 5.0
}
#IBAction func disableUserButtonAction(sender: UIButton) {
delegate?.disableUser(self, button: writeOutUser) //self here I believe to be the cell
}
}
ViewController:
class UserDetailTableViewController : UIViewController, UserCellDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let userCell = UserCell()
userCell.delegate = self
}
func disableUser(cell: UserCell, button: UIButton) {
print("VC: User Disabled")
}
}
The problem here is, the disableUser function in my ViewController never gets called. What am I doing wrong?
What is the best way to do it?
I had referred to the SO Approved Answer Here which is what I am following the same, but with no luck.
Any help will be appreciated. Thanks!!
You should set the delegate of your cell in the cellForRowAtIndexPath method.As #vadian said,In the viewDidLoad you should not initialize your cell using default initializer, and the delegate is nil for your cell by this way in viewDidLoad.
Either initialise your cell using the init(style: reuseIdentifier) or set the delegate in the cell for row method as you will initialize the cell in that method anyway.
When you're doing this:
let userCell = UserCell()
userCell.delegate = self
You are setting the delegate of userCell, and only the delegate of userCell. I'm sure that the table view cells displayed in your table view is not userCell.
So instead of setting the delegate of userCell, you should set the delegate of the cells that you actually want to show in the table view. The most probable place to create new cells that you want to show in table view is in the tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) method.
In the method, you must have something like this:
let cell = ...
// setting properties of cell using the model
return cell
You just need to add this line before the return:
cell.delegate = self
In your code UserCell acts like a UIView. You forgot adding userCell to current controller's view. If you want to use UITableViewCell, the better way is using it with UITableView.
I have a dynamically generated UITableView with many dynamic UITableViewCells and one static UITableViewCell.
The static one has a button and I want to refresh the whole table view when user presses it.
My code attached to the cell is simple:
class MyStaticCell: UITableViewCell {
#IBOutlet weak var sendCommentButton: UIButton!
#IBAction func sendCommentButtonAction(sender: AnyObject) {
//from here I want to refresh the table
}
}
How can I refresh the parent table from that button? In the class MyStaticCell I don't have any instance of the table, so that's my problem for now :|
The cleanest way to do this is through delegation. This ensures that the cell class doesn't need to know what should happen when the button is pressed; that logic can remain in your view controller where it belongs.
protocol CommentButtonProtocol {
func commentButtonTapped(sender: MyStaticCell)
}
class MyStaticCell: UITableViewCell {
#IBOutlet weak var sendCommentButton: UIButton!
var delegate: CommentButtonProtocol?
#IBAction func sendCommentButtonAction(sender: AnyObject) {
self.delegate?.commentButtonTapped(self)
}
}
Then in your view controller you can set it as the delegate in cellForRowAtIndexPath and comply with the protocol in order to handle the event:
class ViewController: UIViewController, CommentButtonProtocol {
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("staticCell", forIndexPath: indexPath) as! MyStaticCell
cell.delegate = self
return cell
}
func commentButtonTapped(sender: MyStaticCell) {
// Do whatever you need to do when the button is tapped
}
}
You could access the tableView using superview.
class MyStaticCell: UITableViewCell {
#IBOutlet weak var sendCommentButton: UIButton!
#IBAction func sendCommentButtonAction(sender: AnyObject) {
(superview as? UITableView)?.reloadData()
}
}
This isn't as stable as it could be so maybe consider this extension:
extension UIResponder {
func nextResponder<T: UIResponder>(ofType type: T.Type) -> T? {
switch nextResponder() {
case let responder as T:
return responder
case let .Some(responder):
return responder.nextResponder(ofType: type)
default:
return nil
}
}
}
It allows you to find the next parent of a particular type, in the cells case, a UITableView.
class MyStaticCell: UITableViewCell {
#IBOutlet weak var sendCommentButton: UIButton!
#IBAction func sendCommentButtonAction(sender: AnyObject) {
nextResponder(ofType: UITableView.self)?.reloadData()
}
}
I am developing app which users will choose one of the two pictures in one cell. My prototype cell looks like :
and I have
cell.rightVoteButton.addTarget(self, action: #selector(voteRightButtonPressed), forControlEvents: .TouchUpInside)
cell.leftVoteButton.addTarget(self, action: #selector(voteLeftButtonPressed), forControlEvents: .TouchUpInside)
in the tableView function.
func voteRightButtonPressed(sender:UIButton){
print("Right Vote clicked is \(sender.tag)")
print(self.polls[sender.tag].poll_id)
}
in this way I am printing the polls id and cells index.
I want to hide the Vote button after clicking specific cell.
For example if I click the vote in first cell and the left picture, I want to hide the two buttons on the first cell. I now the cell's index but how can hide the buttons in specific cell.
My Custom TableViewCell:
class CustomTableViewCell: UITableViewCell {
#IBOutlet weak var leftImage: UIImageView!
#IBOutlet weak var rightImage: UIImageView!
#IBOutlet weak var userPicture: UIImageView!
#IBOutlet weak var userName: UILabel!
#IBOutlet weak var leftButton: UIButton!
#IBOutlet weak var rightButton: UIButton!
#IBOutlet weak var pollDescription: UILabel!
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
}
}
Rather than using tags, which have no intrinsic meaning and are easy to confuse, you can say something like:
func voteRightButtonPressed(sender:UIButton){
let location = self.tableView.convertPoint(sender.bounds.origin, fromView:sender)
let indexPath = self.tableView.indexPathForRowAtPoint(location)
if let cell = self.tableView.cellForRowAtIndexPath(indexPath) as? CustomUITableViewCell {
//hide views in cell and update your model to reflect vote.
}
print("Right Vote clicked is \(indexPath.row)")
print(self.polls[indexPath.row].poll_id)
}
Once you have the cell you can hide the views you want and you can update your model to reflect the vote just cast.
I suppose you have a tableview with several cells of this type, if this is the case you need a custonTableViewCell where you put this code. the buttons respond to a #IBAction that hide the buttons and call a delegate in his UITableViewController.
understand your custonTableViewCell like a viewController for each cell
add this in your custon cell and point the button
// IBAction for buttons
#IBAction func buttonPress(sender: UIButton){
leftButton.hidden = true
rightImage.hidden = true
self.delegate?.buttonPress(sender.tag)
}
add this before your custon cell class definition
protocol CustomTableViewCellDelegate {
func buttonPress(tag: Int)
}
and this after:
var delegate : CustomTableViewCellDelegate?
and in your tableviewcontroller
class TableViewController: UITableViewController, CustomTableViewCellDelegate
and your new func in some place
func buttonPress(tag: Int){
print(tag)
}