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

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
}
}

Related

Detecting textfieldshouldreturn from Custom TableViewCell in TableViewController to Add New Row

I want to add a new row in my TableView when the user presses the return key inside the Custom TableViewCell, which includes a TextField. However, I cannot find a way to do so... how do I view the events of the TextField in my TableView so I can add the row?
My TableViewController
class TableViewController: UITableViewController, CustomCellDelegate,
UITextFieldDelegate {
var rowCount = 1
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
// MARK: - Table view data source
...
// Doesn't Do Anything
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
let indexPath = IndexPath(row: rowCount-1, section: 1)
tableView.insertRows(at: [indexPath], with: .automatic)
view.endEditing(true)
return true
}
// Also does nothing
func didReturn(cell: AddActivityTableViewCell, string: String?) {
let indexPath = IndexPath(row: rowCount-1, section: 1)
tableView.insertRows(at: [indexPath], with: .automatic)
view.endEditing(true)
rowCount += 1
}
My CustomTableViewCell
protocol CustomCellDelegate: class {
func didReturn(cell: CustomTableViewCell, string: String?)
}
class CustomTableViewCell: UITableViewCell, UITextFieldDelegate {
#IBOutlet weak var textField: UITextField!
weak var delegate: CustomCellDelegate?
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
textField.delegate = self
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
public func configureTextField(text: String?, placeholder: String) {
textField.text = text
textField.placeholder = placeholder
textField.accessibilityValue = text
textField.accessibilityLabel = placeholder
}
public func editableTextField(editable: Bool) {
if editable == true {
textField.isEnabled = true
} else {
textField.isEnabled = false
}
}
// This works
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
delegate?.didReturn(cell: self, string: textField.text)
return true
}
}
Thanks!
I think you missed the set delegate in the cell . Please find the code below which works fine for me
ViewController
class TableViewController: UITableViewController, CustomCellDelegate, UITextFieldDelegate {
var rowCount = 1
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return rowCount
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : CustomTableViewCell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomTableViewCell
cell.textField.placeholder = "Row \(indexPath.row)"
cell.delegate = self
return cell
}
func didReturn(cell: CustomTableViewCell, string: String?) {
rowCount += 1
let indexPath = IndexPath(row: rowCount-1, section:0)
tableView.beginUpdates()
tableView.insertRows(at: [indexPath], with: .automatic)
tableView.endUpdates()
view.endEditing(true)
}
}
Custom Cell
protocol CustomCellDelegate: class {
func didReturn(cell: CustomTableViewCell, string: String?)
}
class CustomTableViewCell: UITableViewCell, UITextFieldDelegate {
#IBOutlet weak var textField: UITextField!
weak var delegate: CustomCellDelegate?
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
textField.delegate = self
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
public func configureTextField(text: String?, placeholder: String) {
textField.text = text
textField.placeholder = placeholder
textField.accessibilityValue = text
textField.accessibilityLabel = placeholder
}
public func editableTextField(editable: Bool) {
if editable == true {
textField.isEnabled = true
} else {
textField.isEnabled = false
}
}
// This works
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
delegate?.didReturn(cell: self, string: textField.text)
return true
}
}

Closure block not reloading table on second time swift3

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)
}
}

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]

Why my Tableview is reusing some cells?

I have a Todo list, i have a label and a button in the same cell, when i click the button, change the image button for that cell, but when i scrolled the table view the same button appears on the others cells, it was not to appear in cells that the button were not pressed.
Here is my cellForRowAtIndexPath code
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! TaskTableViewCell
cell.label.text = "Task Number: \(indexPath.row + 1)"
cell.btnFavorite.setImage(UIImage(named: "star"), forState: .Normal)
cell.btnFavorite.setImage(UIImage(named: "star-filled"), forState: .Selected)
cell.btnFavorite.addTarget(self, action: #selector(ListOfTasksViewController.addRemoveFavoriteList), forControlEvents: .TouchUpInside)
return cell
}
func addRemoveFavoriteList(sender : UIButton) {
sender.selected = !sender.selected
}
Custom TableViewCell Class:
import UIKit
class TaskTableViewCell: UITableViewCell {
#IBOutlet weak var label: UILabel!
#IBOutlet weak var btnFavorite: FavoriteButton!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
override func prepareForReuse() {
super.prepareForReuse()
label.text = nil
btnFavorite.selected = false
}
}
View Controller:
import UIKit
class ListOfTasksViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! TaskTableViewCell
cell.label.text = "Task Number: \(indexPath.row + 1)"
cell.btnFavorite.indexPath = indexPath.row
cell.btnFavorite.addTarget(self, action: #selector(ListOfTasksViewController.addRemoveFavoriteList), forControlEvents: .TouchUpInside)
return cell
}
func addRemoveFavoriteList(sender : FavoriteButton) {
if sender.selected {
sender.selected = false
} else {
sender.selected = true
let index = NSIndexPath(forRow: sender.indexPath, inSection: 0)
let cell = tableView.cellForRowAtIndexPath(index) as! TaskTableViewCell
}
}
}
The cells in your table view are reused so as you scroll down, the cells going off screen are being put at the start of the queue before going back onto the screen at a different indexPath. This can cause some issues so you need to override the prepareForReuse method in your custom cell class.
override func prepareForReuse() {
super.prepareForReuse()
label.text = nil
btnFavorite.selected = false
}
you need to add condition in the cellforaRowAtIndexPath.
you need to add flag in Array which track your selection.
then its check in cellforRowAtIndexPath.
for example
button.selected= No
if arrselectedIndexpath containObject:indexPath{
button.selected =yes
}

Table View Cell with a Textfield

I have a subclass, CustomCell, which inherits from my parent class, CreateEvent. The subclass describes the individual cells for the table view cell, which is on the CreateEvent View controller. In one specific cell, I have a textfield, that is linked to the CustomCell file, but I am having trouble getting the value from that textfield when a user enters into the textfield. I am also having trouble dismissing the keyboard with outside touches and pressing the return key, but I am primarily focused on getting the text from the textfield. I am familiar with doing these functionalities on a normal swift file but because this is a subclass, I'm not sure what to do. What I've tried is to use:
class CustomCell: UITableViewCell, UITextFieldDelegate {
#IBOutlet weak var entranceFeeTextField: UITextField!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
And:
class CreateEventVC: UIViewController, UITableViewDelegate, UITableViewDataSource, CustomCellDelegate, UITextFieldDelegate {
override func viewDidLoad() {
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let currentCellDescriptor = getCellDescriptorForIndexPath(indexPath)
let cell = tableView.dequeueReusableCell(withIdentifier: currentCellDescriptor["cellIdentifier"] as! String, for: indexPath) as! CustomCell
cell.entranceFeeTextField.delegate = self
entranceFeeAmount = cell.entranceFeeTextField.text!
}
This code doesn't run and I'm not exactly sure which textfield delegates I need to run in order to be able to get the Text value from the textfield.
You could use the UITextFieldDelegate methods textFieldShouldEndEditing(:) or textFieldShouldReturn(:) to get the results of the textfield.
for example:
func textFieldShouldEndEditing(textField: UITextField) -> Bool {
print("TextField should end editing method called")
let textFromCell = textField.text!
//do whatever you want with the text!
return true;
}
In this code snippet, textField will actually be your instance of entranceFeeTextField. Because somewhere, when that textfield stops editing, it calls self.delegate?.textFieldShouldEndEditing(entranceFeeTextField) and that method's implementation is inside your CreateEventVC.
Returning true will allow the textfield to end editing. This method will only get called when the user wants to stop editing. So you should remove entranceFeeAmount = cell.entranceFeeTextField.text! from your cellForRowAtIndexPath method because that's where you create your cell. At that point a user will not have typed into your textfield, so no use in getting the text from it as soon as it has been made.
All you have to do is implement one of those methods in CreateEventVC.
Here is the full code: (Xcode 8 swift 3)
(View Controller Class)
class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate,UITextFieldDelegate
{
#IBOutlet weak var tbl: UITableView!
var cell = TableViewCell()
override func viewDidLoad()
{
super.viewDidLoad()
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
cell = tbl.dequeueReusableCell(withIdentifier: "CELL") as! TableViewCell
cell.configure(text: "", placeholder: "EnterText")
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return 1
}
func numberOfSections(in tableView: UITableView) -> Int
{
return 1
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool
{
print( cell.returnTextOfTextField() )
print(cell.txtField.text)
cell.txtField .resignFirstResponder()
return true
}
}
TableViewCell class (Custom cell):
class TableViewCell: UITableViewCell,UITextFieldDelegate
{
#IBOutlet weak var txtField: UITextField!
override func awakeFromNib()
{
super.awakeFromNib()
// Initialization code
}
public func configure(text: String?, placeholder: String) {
txtField.text = text
txtField.placeholder = placeholder
txtField.accessibilityValue = text
txtField.accessibilityLabel = placeholder
}
func returnTextOfTextField() -> String
{
print(txtField.text)
return txtField.text!
}
override func setSelected(_ selected: Bool, animated: Bool)
{
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
"CELL" is the identifier given to cell in Nib .
This is working code , I get the value from text field and even keyboard is resigned.
var cell = TableViewCell() // customCell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
cell = tbl.dequeueReusableCell(withIdentifier: "CELL") as! TableViewCell
cell.configure(text: "", placeholder: "EnterText")
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return 1
}
func numberOfSections(in tableView: UITableView) -> Int
{
return 1
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool
{
//cell = tbl.dequeueReusableCell(withIdentifier: "CELL") as! TableViewCell
print( cell.returnTextOfTextField() )
print(cell.txtField.text)
cell.txtField .resignFirstResponder()
return true
}
/// Custom cell class
class TableViewCell: UITableViewCell,UITextFieldDelegate
{
#IBOutlet weak var txtField: UITextField!
override func awakeFromNib()
{
super.awakeFromNib()
// Initialization code
}
public func configure(text: String?, placeholder: String) {
txtField.text = text
txtField.placeholder = placeholder
txtField.accessibilityValue = text
txtField.accessibilityLabel = placeholder
}
func returnTextOfTextField() -> String
{
print(txtField.text)
return txtField.text!
}
override func setSelected(_ selected: Bool, animated: Bool)
{
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}

Resources