Closure block not reloading table on second time swift3 - ios

I have a table with button and label .When I tap on button it gets highlighted .So I have 5 rows each with button and label and when I tap on every button they are highlighted.Now on remaining view apart from table I have cancel button when I tap on it I want all the selected rows to reload again.My code works fine for the first execution .Like I selected all 5 button then tap on cancel button all rows are reloaded.But when I select button in table row again and tap on cancel nothing happens.Call is going inside my closure function I can see the correct index printed for reloading but nothing happens.My code is this-:
Cell Custom class-:
import UIKit
class TestingControllerCellTableViewCell: UITableViewCell {
#IBOutlet weak var TableButton: UIButton!
#IBOutlet weak var TableMenu: UILabel!
var TableButtonCallBack : (()->())?
override func awakeFromNib() {
super.awakeFromNib()
ButtonLayout()
// Initialization code
}
func ButtonLayout()
{
TableButton.layer.cornerRadius = 12.5
TableButton.layer.borderWidth = 1.0
TableButton.layer.borderColor = UIColor.gray.cgColor
self.selectionStyle = UITableViewCellSelectionStyle.none
}
#IBAction func filterTableRadioButtonAction(_ sender: UIButton) {
TableButtonCallBack?()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
controller class-:
import UIKit
class filterControllerViewController: UIViewController {
#IBOutlet weak var TableViewController: UITableView!
fileprivate var ButtonSelectedIndex = [[Int]]()
fileprivate var cancelDataItemSelectedCallBack : ((Int)->())? = nil
override func viewDidLoad() {
super.viewDidLoad()
filterTableViewSetUp()
// Do any additional setup after loading the view.
}
// CANCEL ACTION
#IBAction func cancelDataItemSelected(_ sender: UIButton) {
for sectionIndex in 0..<filterRadioButtonSelectedIndex.count
{
for valueIndex in 0..<ButtonSelectedIndex[sectionIndex].count
{
cancelDataItemSelectedCallBack!(ButtonSelectedIndex[sectionIndex][valueIndex])
}
}
ButtonSelectedIndex.removeAll()
}
func TableViewSetUp()
{
TableViewController.delegate = self
TableViewController.dataSource = self
TableViewController.backgroundColor = UIColor.green
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
}
extension filterControllerViewController:UITableViewDataSource,UITableViewDelegate
{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let filterCell = tableView.dequeueReusableCell(withIdentifier: "filterCell", for: indexPath) as! FilterControllerCellTableViewCell
filterCell.filterTableRadioButtonCallBack = {
filterCell.TableButton.backgroundColor = UIColor.blue
self.ButtonSelectedIndex.append([indexPath.row])
}
// THIS cancelDataItemSelectedCallBack CALLED FIRST TIME AND RELOAD TABLE EVEN GETS CALLED SECOND TIME SHOWS CORRECT INDEX BUT TABLE BUTTONS STLL REMAIN HIGHLIGHTED
self.cancelDataItemSelectedCallBack = { data in
let indexPath = IndexPath(item: data, section: indexPath.section)
print(indexPath)
self.TableViewController.reloadRows(at: [indexPath], with: UITableViewRowAnimation.none)
}
return filterCell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
return 40.0
}
}
I know I am missing something but not getting it.Please help
print indexPath within self.cancelDataItemSelectedCallBack gives me this output which is correct.But it works only one time.
[0, 2]
[0, 3]

You have to reload the UI on the main thread like this:
self.cancelDataItemSelectedCallBack = { data in
OperationQueue.main.addOperation {
let indexPath = IndexPath(item: data, section: indexPath.section)
self.TableViewController.reloadRows(at: [indexPath], with: UITableViewRowAnimation.none)
}
}

Related

Table view cell elements not able to click and get data

I have one table view and inside that i placed one main view. And inside that main view i placed one button.And when ever use click on my cell button. I need to get the cell title label.This is what i need. But i tried following below code. Not sure what i am missing out. It not at all calling my cell.add target line.
Code in cell for row at index:
cell.cellBtn.tag = indexPath.row
cell.cellBtn.addTarget(self, action:#selector(self.buttonPressed(_:)), for:.touchUpInside)
#objc func buttonPressed(_ sender: AnyObject) {
print("cell tap")
let button = sender as? UIButton
let cell = button?.superview?.superview as? UITableViewCell
let indexPath = tableView.indexPath(for: cell!)
let currentCell = tableView.cellForRow(at: indexPath!)! as! KMTrainingTableViewCell
print(indexPath?.row)
print(currentCell.cellTitleLabel.text)
}
I even added a breakpoint, still it not at calling my cell.addTarget line
Tried with closure too. In cell for row at index:
cell.tapCallback = {
print(indexPath.row)
}
In my table view cell:
var tapCallback: (() -> Void)?
#IBAction func CellBtndidTap(_ sender: Any) {
print("Right button is tapped")
tapCallback?()
}
Here that print statement is getting print in console.
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var list = [String]()
#IBOutlet weak var tableView: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return list.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MyTableViewCell
cell.saveButton.tag = indexPath.row
//cell.saveButton.accessibilityIdentifier = "some unique identifier"
cell.tapCallback = { tag in
print(tag)
}
return cell
}
}
class MyTableViewCell: UITableViewCell {
// MARK: - IBOutlets
#IBOutlet weak var saveButton: UIButton!
// MARK: - IBActions
#IBAction func saveTapped(_ sender: UIButton) {
tapCallback?(sender.tag)
}
// MARK: - Actions
var tapCallback: ((Int) -> Void)?
}
Actually this is not a good programming practice to add the button (which contains in table view cell) target action in view controller. We should follow the protocol oriented approach for it. Please try to under stand the concept.
/*This is my cell Delegate*/
protocol InfoCellDelegate {
func showItem(item:String)
}
/*This is my cell class*/
class InfoCell: UITableViewCell {
//make weak reference to avoid the Retain Cycle
fileprivate weak var delegate: InfoCellDelegate?
//Outlet for views
#IBOutlet var showButton: UIButton?
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
//This is the public binding function which will bind the data & delegate to cell
func bind(with: DataModel?, delegate: InfoCellDelegate?, indexPath: IndexPath) {
//Now the bind the cell with data here
//.....
//Assign the delegate
self.delegate = delegate
}
//Button action
#IBAction func rowSelected(sender: UIButton) {
self.delegate?.showItem(item: "This is coming from cell")
}
}
/*Now in your ViewController you need to just confirm the InfoCellDelegate & call the bind function*/
class ListViewController: UIViewController {
//Views initialisation & other initial process
}
//Table view Delegate & Data source
extension ListViewController: UITableViewDataSource, UITableViewDelegate {
/**
Configure the table views
*/
func configureTable() {
//for item table
self.listTable.register(UINib.init(nibName: "\(InfoCell.classForCoder())", bundle: nil), forCellReuseIdentifier: "\(InfoCell.classForCoder())")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "InfoCell") as! InfoCell
cell.bind(with: DataModel, delegate: self, indexPath: indexPath)
return cell
}
}
extension ListViewController: InfoCellDelegate {
func showItem(item) {
print(item)
}
}

When I go back to the page, changing number and cell datas of the TableView

I am using nested tableview. The main tableview lists the file categories. Child tableview listing the files. I open the files with safari. The child tableview is listed incorrectly when I go back to the page after opening the file. How can i solve this problem? Android sdk have "onActivityResult" method. Does iOS have a similar function? Thanks.
ViewController
import UIKit
class ProductDetailViewController: UIViewController, UITableViewDataSource, UITableViewDelegate{
var bundleProductModel:ProductModel? = ProductModel.init()
var lastFileCatIndex:Int = 0
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// If tableview is file category table.
if (tableView.tag == 100){
return bundleProductModel!.fileCategoryModels.count
} else /* Table view is file tableview. */ {
//self.lastFileIndex = self.lastFileIndex + 1
return (bundleProductModel?.fileCategoryModels[self.lastFileCatIndex].files.count)!
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if (tableView.tag == 100){
// Define cell for file category.
let cell = tableView.dequeueReusableCell(withIdentifier: "FileCategoryTableViewCell") as! FileCategoryTableViewCell
// Set file category cell height.
cell.frame.size.height = CGFloat(((bundleProductModel?.fileCategoryModels[indexPath.row].files.count)! * 44) + 42)
// cell row height
tableView.rowHeight = CGFloat(((bundleProductModel?.fileCategoryModels[indexPath.row].files.count)! * 44) + 42)
// Control bound
if (self.lastFileCatIndex <= indexPath.row){
// Index.
self.lastFileCatIndex = indexPath.row
// File category name.
cell.lblFileCatNme.text = " \(bundleProductModel?.fileCategoryModels[indexPath.row].file_category_name ?? "Unknow") "
}
return cell
} else {
// Define cell for files.
let cell = tableView.dequeueReusableCell(withIdentifier: "FileTableViewCell") as! FileTableViewCell
if ((bundleProductModel?.fileCategoryModels[self.lastFileCatIndex].files.count)! > indexPath.row){
// Set file model to file cell.
cell.setFile(fileItem: (self.bundleProductModel?.fileCategoryModels[self.lastFileCatIndex].files[indexPath.row])!)
// file cell delegate
cell.delegate = self
} else {
cell.lblFileName.text = "unknow"
}
return cell
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
extension ProductDetailViewController:FileCellDelegate{
func didClickDownload(downloadLink: String, button: UIButton) {
if let url = URL(string: downloadLink) {
UIApplication.shared.open(url)
}
}
}
A very easy workaround on iOS would be to override viewWillAppear and call reloadData() like so:
override func viewWillAppear() {
super.viewWillAppear()
tableView.reloadData()
}
This will update your table everytime your view reappears.
SOLVED
Problem is lastFileCategoryIndex variable. Ex: final value is four. When I come back to the page; listing relative to fourth index. I define child tableview in main tableview cell and solved.
FileCategoryTableViewCell
class FileCategoryTableViewCell: UITableViewCell, UITableViewDelegate, UITableViewDataSource {
// General Objects
var fileCategoryModel:FileCategoryModel = FileCategoryModel.init()
// Cell Ui Objects
#IBOutlet weak var lblFileCatNme: UILabel!
#IBOutlet weak var fileTableView: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fileCategoryModel.files.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = fileTableView.dequeueReusableCell(withIdentifier: "FileTableViewCell") as! FileTableViewCell
cell.lblFileName.text = "Ex File..."
return cell
}
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
// Set category model.
func setFileCategory(fileCategoryModel:FileCategoryModel){
self.fileCategoryModel = fileCategoryModel
self.fileTableView.dataSource = self
self.fileTableView.delegate = self
}
}

How to make textField in TableViewCell editable when edit button of NavigationBar is pressed?

Developing an iOS application with Xcode ver 9.2, Swift.
When the edit button on the top right of the NavigationBar is pressed, how to change the textField in the TableViewCell to make it editable?
To prevent the TextField from being edited in the initial display, I set textField.isEnabled = false with awakeFromNib() in the TableViewCell.swift.
When the edit button is pressed, I want to set it to true so that I can edit the TextField.
Could you tell me how?
Relationship between object placement and code (in parentheses) is below.
NavigationController - TableViewController (TableViewController.swift) - TableViewCell (TableViewCell.swift) - TextField
Here is the code.
TableViewController.swift
import UIKit
class TableViewController: UITableViewController, TableViewCellDelegate {
#IBOutlet var ttableView: UITableView!
var array:[String] = ["aaa", "bbb", "ccc", "ddd", "eee"]
override func viewDidLoad() {
super.viewDidLoad()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
self.navigationItem.rightBarButtonItem = self.editButtonItem
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func setEditing(_ editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return array.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "inputCell", for: indexPath) as! TableViewCell
cell.textField.text = array[indexPath.row]
cell.delegate = self
return cell
}
func textFieldDidEndEditing(cell: TableViewCell, value: String) -> () {
let path = tableView.indexPathForRow(at: cell.convert(cell.bounds.origin, to: tableView))
array[(path?.row)!] = value
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if (editingStyle == UITableViewCellEditingStyle.delete) {
array.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
}
}
override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
let cell = tableView.cellForRow(at: sourceIndexPath) as! TableViewCell
let moveData = cell.textField.text
array.remove(at: sourceIndexPath.row)
array.insert(moveData!, at: destinationIndexPath.row)
}
}
TableViewCell.swift
import UIKit
protocol TableViewCellDelegate {
func textFieldDidEndEditing(cell: TableViewCell, value: String) -> ()
}
class TableViewCell: UITableViewCell, UITextFieldDelegate {
var delegate: TableViewCellDelegate! = nil
#IBOutlet weak var textField: UITextField!
override func awakeFromNib() {
super.awakeFromNib()
textField.delegate = self
textField.returnKeyType = .done
// To prevent the TextField from being edited in the initial display
textField.isEnabled = false
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func textFieldDidEndEditing(_ textField: UITextField) {
self.delegate.textFieldDidEndEditing(cell: self, value: textField.text!)
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}
I added the following from the first time question and answers.
Editing screen shot: after edit button is pressed
If there are many elements of the array, the cells will be outside the screen, but I want to make all textField editable as well.
var array:[String] = ["aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk", "lll", "mmm", "nnn", "ooo", "ppp", "qqq", "rrr", "sss", "ttt"]
Editing screen shot for many elements
Finally resolved code
TableViewController.swift
import UIKit
class TableViewController: UITableViewController, TableViewCellDelegate {
#IBOutlet var ttableView: UITableView!
// var array:[String] = ["aaa", "bbb", "ccc", "ddd", "eee"]
var array:[String] = ["aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk", "lll", "mmm", "nnn", "ooo", "ppp", "qqq", "rrr", "sss", "ttt"]
override func viewDidLoad() {
super.viewDidLoad()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Edit", style: .plain, target: self, action: #selector(rightBarButtonItemTapped))
}
// handle tap by button...
#objc func rightBarButtonItemTapped(_ sender: UIBarButtonItem) {
ttableView.setEditing(!ttableView.isEditing, animated: true)
navigationItem.rightBarButtonItem?.title = ttableView.isEditing ? "Done" : "Edit"
navigationItem.rightBarButtonItem?.style = ttableView.isEditing ? .done : .plain
ttableView.visibleCells.forEach { cell in
guard let cell = cell as? TableViewCell else { return }
cell.textField.isEnabled = ttableView.isEditing
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return array.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "inputCell", for: indexPath) as! TableViewCell
cell.textField.text = array[indexPath.row]
cell.textField.isEnabled = tableView.isEditing
cell.delegate = self
return cell
}
func textFieldDidEndEditing(cell: TableViewCell, value: String) -> () {
let path = tableView.indexPathForRow(at: cell.convert(cell.bounds.origin, to: tableView))
array[(path?.row)!] = value
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if (editingStyle == UITableViewCellEditingStyle.delete) {
array.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
}
}
override func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
if tableView.isEditing {
return UITableViewCellEditingStyle.delete
} else {
return UITableViewCellEditingStyle.none
}
}
override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
let cell = tableView.cellForRow(at: sourceIndexPath) as! TableViewCell
let moveData = cell.textField.text
array.remove(at: sourceIndexPath.row)
array.insert(moveData!, at: destinationIndexPath.row)
}
}
TableViewCell.swift
import UIKit
protocol TableViewCellDelegate {
func textFieldDidEndEditing(cell: TableViewCell, value: String) -> ()
}
class TableViewCell: UITableViewCell, UITextFieldDelegate {
var delegate: TableViewCellDelegate! = nil
#IBOutlet weak var textField: UITextField!
override func awakeFromNib() {
super.awakeFromNib()
textField.delegate = self
textField.returnKeyType = .done
//textField.isEnabled = false
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func textFieldDidEndEditing(_ textField: UITextField) {
self.delegate.textFieldDidEndEditing(cell: self, value: textField.text!)
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}
First, you should handle navigation button tap, find cell(s) with textField and then set textField.isEnabled = true.
You can do something like this:
override func viewDidLoad() {
super.viewDidLoad()
// in your code `self.editButtonItem` is the `UIBarButtonItem`, so make sure that it configured properly
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .edit, target: self, action: #selector(rightBarButtonItemTapped))
}
// handle tap by button...
#objc func rightBarButtonItemTapped(_ sender: UIBarButtonItem) {
// and set `textField.isEnabled` to all `visibleCells`
ttableView.visibleCells.forEach { cell in
guard let cell = cell as? TableViewCell { else return }
cell.textField.isEnabled = true
}
// or set `isEnabled` to specific `textField` at index 0
if let cell = ttableView.cellForRow(at: IndexPath(row: 0, section: 0)) {
cell.textField.isEnabled = true
}
}
UPD.
Base on your screenshot you:
doesn't need to set textField.isEnabled = false
you just need setEditing for tableView and show appropriate title for button in navigation bar.
Example:
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Edit", style: .plain, target: self, action: #selector(rightBarButtonItemTapped))
}
#objc func rightBarButtonItemTapped(_ sender: UIBarButtonItem) {
ttableView.setEditing(!ttableView.isEditing, animated: true)
navigationItem.rightBarButtonItem?.title = ttableView.isEditing ? "Done" : "Edit"
navigationItem.rightBarButtonItem?.style = ttableView.isEditing ? .done : .plain
}
LAST UPD
Ok, now only steps you should do:
remove from awakeFromNib code that disable textField
in cellForRowAtIndexPath method in your viewController write cell.textField.isEnabled = tableView.isEditing
to set tableView in editing mode use my UPD code
to enable all textFields in cells you should use approach from original answer with visibleCells (i updated this part, now you shouldn't have any error). note, that this code apply only for currently visible cells. for others it also works, but set textField enabled part goes in cellForRowAtIndexPath method because these cells will appear on the screen.
you can do so by creating an action of your navigation barbutton item , and in that action you can simply do the textField enabled, as shown below:
#IBAction func editTapped(_ sender: Any) {
print("editTapped")
for i in 0..< ttableView.visibleCells.count{
let cell = ttableView.cellForRow(at: IndexPath(row: i, section: 0)) as! TableViewCell
cell.textField.isEnabled = true
}
}

iOS swift UIButton in TableView Cell

I have a tableView with custom cell. in my custom cell I have a like button. for like Button I wrote a function to change state from .normal to .selected like this:
FeedViewCell
class FeedViewCell: UITableViewCell {
#IBOutlet weak var likeButton: UIButton!
var likes : Bool {
get {
return UserDefaults.standard.bool(forKey: "likes")
}
set {
UserDefaults.standard.set(newValue, forKey: "likes")
}
}
override func awakeFromNib() {
super.awakeFromNib()
self.likeButton.setImage(UIImage(named: "like-btn-active"), for: .selected)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
#IBAction func likeBtnTouch(_ sender: AnyObject) {
print("press")
// toggle the likes state
self.likes = !self.likeButton.isSelected
// set the likes button accordingly
self.likeButton.isSelected = self.likes
}
}
FeedViewController :
class FeedViewController: UIViewController {
#IBOutlet var feedTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Register Cell Identifier
let feedNib = UINib(nibName: "FeedViewCell", bundle: nil)
self.feedTableView.register(feedNib, forCellReuseIdentifier: "FeedCell")
}
func numberOfSectionsInTableView(_ tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.feeds.count
}
func tableView(_ tableView: UITableView, heightForRowAtIndexPath indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, cellForRowAtIndexPath indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "FeedCell", for: indexPath) as! FeedViewCell
return cell
}
}
But my problem is when I tap like button in cell with indexPath.row 0 the state of button in cell with indexPath.row 3 change state too.
where is my mistake?
thanks
You didn't post all your code, but I can tell you that for this to work the #IBAction func likeBtnTouch(_ sender: AnyObject) { } definition must be inside the FeedViewCell class definition to make it unique to a particular instance of the cell.
As a rule of thumb, I normally ensure that all the UI elements inside my cell are populated in cellForRowAtIndexPath when using dequeued cells. Also it should be set from an external source. I.o.w not from a property inside the cell. Dequeuing cells reuse them, and if not setup properly, it might have some leftovers from another cell.
For example, inside cellForRowAtIndexPath:
self.likeButton.isSelected = likeData[indexPath.row]

how to handle button click for each button in each row of UITableView

I have a UITableView (with a Custom class called CellModelAllNames for each row). Each Row has a Label and a button.
My question is: When btn_addRecording (i.e. the '+' button is clicked on any/each of the rows, how do I get the lbl_name.text, the label name shown, and show a pop up in the ViewController itself. I want to get additional information in the pop up and then save all the info (including the lbl_name to a database).
CellModelAllNames for each row layout:
import UIKit
class CellModelAllNames: UITableViewCell {
#IBOutlet weak var lbl_name: UILabel!
#IBOutlet weak var btn_addRecording: UIButton!
#IBAction func btnAction_addRecording(sender: AnyObject) {
println("clicked on button in UITableViewCell")
}
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
func setCell(setBabyName: String) {
self.lbl_name.text = setBabyName
}
}
Here's the code of my ViewController:
import UIKit
class SecondViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tbl_allNames: UITableView!
var arrayOfNames: [Name] = [Name]()
override func viewDidLoad() {
super.viewDidLoad()
self.tbl_allNames.delegate = self
self.tbl_allNames.dataSource = self
self.tbl_allNames.scrollEnabled = true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:CellModelAllNames = self.tbl_allNames.dequeueReusableCellWithIdentifier("CellModelAllNames") as! CellModelAllNames
let name = arrayOfNames[indexPath.row]
cell.setCell(name.name)
println("in tableView, cellforRowatIndex, returning new cells")
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayOfNames.count
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
}
}
You can use standard UIKit methods to get the cell and its data:
func tappedButton(sender : UIButton) {
let point = sender.convertPoint(CGPointZero, toView: self.tableView)
let indexPath = self.tableView.indexPathForRowAtPoint(point)!
let name = arrayOfNames[indexPath.row]
// do something with name
}
You can add button action in your ViewController
1) In your function cellForRowAtIndexPath assign button's tag as index (ie. indexPath.row)
cell.btn_addRecording.tag = indexPath.row
2) Add target and action for your button :
cell.btn_addRecording.addTarget(self, action: "buttonPressed:", forControlEvents: .TouchUpInside)
3) Add action in ViewControler (ie. save info in database)
func buttonPressed(button: UIButton!)
{
// Add your code here
let name = arrayOfNames[button.tag]
}

Resources