How to get Cell Index on TextField Delegate Method in TableViewCell Class - uitableview

Please review the code below. I want to get cell index when textfield should begin editing.
class SingleLineText: UITableViewCell, UITextFieldDelegate {
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
let cell: SingleLineText = textField.superview!.superview as! SingleLineText
let table: UITableView = cell.superview as! UITableView
let textFieldIndexPath = table.indexPath(for: cell)
print(textFieldIndexPath as Any)
return true
}
}

In cellForRowAt method just add:
youCell.textField.tag = indexPath.row
and use it Like:
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
let indexPath: IndexPath = IndexPath(row: textField.tag, section: 0)
//here is your indexPath
return true
}
}

Related

How to find the index of an edited textfield in a tableview

I have a UITableView, in which, each cell has UITextField embedded. I have an array of values that I want to change based on which UITextField gets edited. Currently, I am using the function:
func textFieldDidEndEditing(_ textField: UITextField) {
editedValue = textField.text!
}
But what I want to do is set a generic string, and if a user changes the text in a UITextField, then I can index the string and change that specific value. Is there a way to find the tag of the cell containing the UITextField that was edited?
in your cellForRowAtIndexPath, do this:
cell.yourTextField.tag = indexPath.row // so we are setting the tag of your textfield to indexPath.row, so that we can use this tag property to get the indexpath.
cell.yourTextField.addTarget(self, action: #selector(textChanged(textField:)), for: .editingChanged)
now in your view controller declare this function:
#objc func textChanged(textField: UITextField) {
let index = textField.tag
// this index is equal to the row of the textview
}
You can get parent cell of your textField and then find IndexPath
func textFieldDidEndEditing(_ textField: UITextField) {
if let cell = textField.superview as? UITableViewCell {
let indexpath = tableview.indexPath(for: cell)
// indexpath.row - row index, indexpath.section - section index
}
}
First define a protocol/delegate in your UITableViewCell
protocol CustomCellDelegate: class {
func getTextFeildData(cell: CustomCell, text: String)
}
class CustomCell: UITableViewCell {
weak var delegate: CustomCellDelegate!
func textFieldDidEndEditing(_ textField: UITextField) {
delegate.getTextFeildData(cell: self, text: textField.text ?? "")
}
}
In your cellForRowAtIndexPath function set the delegate of the cell:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.delegate = self
return cell
}
Then confirm the delegate method to ViewController:
extension ViewController: CustomCellDelegate {
func getTextFeildData(cell: CustomCell, text: String) {
guard let tappedIndexPath = self.tableView.indexPathForCell(cell) else {return}
print("Tapped IndexPath: \(tappedIndexPath)")
print("Text Field data: \(text)")
// update your model here
}
}

Multiple textFields in UITableView update the wrong textField when textFieldShouldReturn

I'm doing a form through a UITableView, using custom UITableViewCells which contain a UITextField each.
I'm using textFieldShouldReturn to jump to the next textField but I cannot understand why what I typed in one textField appears randomly (actually, there is weird pattern) into another textField.
Here the custom UITableViewCell
class RPTableViewCell: UITableViewCell {
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var textField: DictionaryTextField!
#IBOutlet weak var errorLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
titleLabel.textColor = Constants.secondaryColor
textField.textColor = Constants.secondaryColor
contentView.isUserInteractionEnabled = false
errorLabel.isHidden = true
}
func setTag(tag: Int) {
textField.tag = 100 + tag
}
}
Then in my FormViewController I do
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let field = formFields?[indexPath.row] else { return UITableViewCell() }
if let cell = tableView.dequeueReusableCell(withIdentifier: "cellID") as? RPTableViewCell {
cell.titleLabel.text = field["displayText"]?.uppercased
cell.textField.text = field["userAnswer"] as? String // This was missing, but is key
cell.textField.placeholder = field["placeholder"] as? String
cell.setTag(tag: indexPath.row)
cell.textField.delegate = self
return cell
} else {
return UITableViewCell()
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let cell = tableView.cellForRow(at: indexPath) as? RPTableViewCell else { return }
tableView.scrollToRow(at: indexPath, at: .middle, animated: true)
cell.textField.becomeFirstResponder()
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if let nextTextField = tableView.viewWithTag(textField.tag + 1) as? UITextField {
tableView.deselectRow(at: IndexPath(row: textField.tag - 100, section: 0), animated: false)
tableView.selectRow(at: IndexPath(row: textField.tag - 99, section: 0),
animated: false, scrollPosition: .middle)
nextTextField.becomeFirstResponder()
} else {
textField.resignFirstResponder()
}
return false
}
EDIT:
In viewDidLoad I load the formFiels like this
// Read from a JSON file
guard let visitorPaths = Constants.configDict()?["visitorPaths"] as? [Dictionary<String, AnyObject>] else {
print("Error: no visitorPaths found in the configuration")
return
}
formFields = visitorPaths.first!["fields"]! as? [[String: AnyObject]]
Your are using the following snippet which does not work:
if let nextTextField = tableView.viewWithTag(textField.tag + 1) as? UITextField
The textfield is not a subview of your tableView. The Textfield is a subview of the TableViewCell.
You can acces the cell in the textFieldShouldReturn(_ textField: UITextField) delegate method like the following:
let nextIndexPath = IndexPath(row: textField.tag + 1, section: 0)
if let cell = tableView.cellForRow(at: nextIndexPath) as? RPTableViewCell {
cell.textField.becomeFirstResponder()
}
Edit for the text jumping:
Add the following textField delegate method to store the new text:
func textFieldDidEndEditing(_ textField: UITextField) {
formFields?[textField.tag - 100]["displayText"] = textField.text
}

how to clear the text from the textfield after entering one data from other cell

Once I have 15 cells in the tableView. In the tableViewCell I have a textfield, I firstly enter the data in textfield of the 1st cell, then click on enter, but while scrolling the entered text is displaying in the other textfield. How to solve it?
In viewController :-
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let identifier = "Cell"
var cell: QuestionListCell! = tableView.dequeueReusableCell(withIdentifier: identifier) as? QuestionListCell
if cell == nil {
tableView.register(UINib(nibName: "QuestionListCell", bundle: nil), forCellReuseIdentifier: identifier)
cell = tableView.dequeueReusableCell(withIdentifier: identifier) as? NH_QuestionListCell
}
cell.contentView.backgroundColor = UIColor.clear
let questionsModel = questionViewModel.titleForHeaderInSection(atsection:indexPath.section)
print(questionsModel.buttontype)
questionViewModel.button = questionsModel.buttontype
let optionModel = questionViewModel.datafordisplay(atindex: indexPath)
cell.setOptions(Options1: optionModel)
print("Section \(indexPath.section), Row : \(indexPath.row)")
if questionViewModel.button == "5"{
self.selected = 1
cell.option5()
cell.setOtherOptions(Options:questionViewModel.datafordisplay(atindex: indexPath))
}
print("text")
cell.textadd = {[weak self] in
if let i = self?.tableview.indexPath(for: $0) {
print("the selected text\(cell.textname ?? "")")
print(i)
print("the Selected button is \(cell.textname ?? "")")
print(i)
cell.setText(Options:(self?.questionViewModel.datafordisplay(atindex: indexPath))!)
let model = self?.questionViewModel.datafordisplay(atindex: indexPath)
print(model?.values ?? "")
print("Section \(indexPath.section), Row : \(indexPath.row)")
let indexPath = IndexPath(row: indexPath.row, section:indexPath.section);
self?.tableview.selectRow(at: indexPath, animated: false, scrollPosition: UITableViewScrollPosition.none)
self?.tableView((self?.tableview)!, didSelectRowAt: indexPath)
}
print(cell.texttype.text ?? "")
self?.u = 1
}
return cell}
This is my tableviewcell:-
#IBOutlet weak var texttype: UITextField!
var textname:String?
func textFieldDidBeginEditing(_ textField: UITextField) {
texttype.text = ""
}
func textFieldShouldClear(_ textField: UITextField) -> Bool
{
return true
}
func textFieldDidEndEditing(_ textField: UITextField) {
self.TextAction(texttype)
}
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
return true;
}
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
return true;
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
print(texttype.text)
texttype.resignFirstResponder()
// self.TextAction(texttype)
return true
}
var textadd : ((NH_QuestionListCell) -> Void)?
#IBAction func TextAction(_ sender: UITextField) {
print(texttype.text)
// self.question.text = texttype.text
self.textname = texttype.text
print(self.textname)
print(texttype.text)
textadd?(self)
}
func setText(Options:NH_OptionsModel)
{
self.displaySmiley.isHidden = true
self.viewdisplay.isHidden = false
self.imagebutton.isHidden = true
self.question.isHidden = true
self.displayRatingView.isHidden = true
print(Options.values)
Options.values = self.textname
print(Options.values)
}
Declare a array which can store table View text .
var arrString = ["","",""] // each empty string for each text field
in you tableview data source set a tag for each textField . and set value from array
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
cell.textField.tag = indexPath.row
cell.textField.text = arrString[indexPath.row]
return cell
}
in textFieldShouldReturn
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
texttype.resignFirstResponder()
let index = textField.tag
arrString[indexPath.row] = textField.text
return true
}

Keyboard not showing when tableView.reloadData() inside textFieldDidBeginEditing

I put UITextField inside UITableViewCell and want to make highlight tableViewCell and unselected tableViewCell goes original color if user key-in inside each UITextField. So, I did like that.
func textFieldDidBeginEditing(_ textField: UITextField) {
defaultIndex = textField.tag
dynamicFormTable.reloadData()
}
But problem is Keyboard is not showing when I've added dynamicFormTable.reloadData(). Please let me know how to resolve it. Thanks.
Following code will give good result, to avoid reloads
var cellBGColr = [Int : UIColor]()
var previouselectedRow = [Int]()
override func viewDidLoad() {
super.viewDidLoad()
for i in 0..<70 // numberOfRows
{
cellBGColr[i] = UIColor.white
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 70
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "table", for: indexPath) as! TblTableViewCell
cell.backgroundColor = cellBGColr[indexPath.row]
cell.selectionStyle = .none
return cell
}
func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
let cellPosition = textView.superview?.convert(CGPoint.zero, to: tblView)
let indPath : IndexPath = tblView.indexPathForRow(at: cellPosition!)!
let cell = tblView.cellForRow(at: indPath) as! TblTableViewCell
var previousSelectedCellRow : Int = -1 // FOR VALIDATION
if previouselectedRow.count == 0 // FIRST EDIT
{
previouselectedRow.append(indPath.row)
}
else
{
previousSelectedCellRow = previouselectedRow[0]
if previousSelectedCellRow == indPath.row // SAME ROW EDITING AGAIN
{
}
else // NEW ROW
{
let previousIndPath : IndexPath = IndexPath(row: previousSelectedCellRow, section: 0)
if (tblView.indexPathsForVisibleRows?.contains(previousIndPath))!
{
let previousCell = tblView.cellForRow(at: previousIndPath) as! TblTableViewCell
previousCell.backgroundColor = UIColor.white
cellBGColr[previousSelectedCellRow] = UIColor.white
}
else
{
cellBGColr[previousSelectedCellRow] = UIColor.white
}
previouselectedRow.remove(at: 0)
previouselectedRow.append(indPath.row)
}
}
cell.backgroundColor = UIColor.red // HERE YOU CAN CHANGE UR CELL COLOR
cellBGColr[indPath.row] = UIColor.red // HERE STORED IN DICT
return true
}
On scrolling your tableview, or somewhere you try to reload, cell background color will not change / reuse.
When reloadData is called it resigns first responder. But you can use beginUpdates/endUpdates methods:
dynamicFormTable.beginUpdates()
dynamicFormTable.reloadRows(at: [IndexPath(row: defaultIndex, section: 0)], with .none)
dynamicFormTable.endUpdates()

How to make UITableview with Textfield in swift?

I want to make a table view with textfields in each cell,
I have a custom class in a swift file:
import UIKit
public class TextInputTableViewCell: UITableViewCell{
#IBOutlet weak var textField: UITextField!
public func configure(#text: String?, placeholder: String) {
textField.text = text
textField.placeholder = placeholder
textField.accessibilityValue = text
textField.accessibilityLabel = placeholder
}
}
Then in my ViewController I have
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCellWithIdentifier("TextInputCell") as! TextInputTableViewCell
cell.configure(text: "", placeholder: "Enter some text!")
text = cell.textField.text
return cell
}
That works well:
But when the user enters text in the textfield and press the button I want to store the strings of each textfield in an array.
I have tried with
text = cell.textField.text
println(text)
But it prints nothing like if it was empty
How can I make it work?
In your view controller become a UITextFieldDelegate
View Controller
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate {
var allCellsText = [String]()
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! CustomTableViewCell
cell.theField.delegate = self // theField is your IBOutlet UITextfield in your custom cell
cell.theField.text = "Test"
return cell
}
func textFieldDidEndEditing(textField: UITextField) {
allCellsText.append(textField.text!)
println(allCellsText)
}
}
This will always append the data from the textField to the allCellsText array.
this method is init the cell,u have not model to save this datas,so
text = cell.textfield.text
is nothing!
you can init var textString in viewcontroller,an inherit UITextFieldDelegate
optional func textFieldDidEndEditing(_ textField: UITextField)
{
textString = _textField.text
}
optional func textFieldShouldReturn(_ textField: UITextField) -> Bool{
return true
}
and cell.textField.text = textString
create a variable
var arrayTextField = [UITextField]()
after this in your func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{}
add
self.arrayTextField.append(textfield)
before returning cell, after this to display the values using
for textvalue in arrayTextField{
println(textvalue.text)
}
So here is a way to do it using the suggestion of having a textfield array. It uses the tag of the textfield to ensure it does not get added multiple times when you scroll.
// Assumes that you have a label and a textfield as a part of you tableViewCell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as? BodyStatsTableViewCell else {
return UITableViewCell()
}
cell.rowLabel.text = bodyTableArray[indexPath.row].rowTitle
let tagValue = indexPath.row + 100
var newRow = true
for textvalue in arrayTextField{
if textvalue.tag == tagValue {
newRow = false
}
}
if newRow {
cell.rowTextField.tag = tagValue
self.arrayTextField.append(cell.rowTextField)
cell.rowTextField.text = bodyTableArray[indexPath.row].rowValue
}
return cell
}
// And then you cam get the values when you want to save with where tag - 100 will be the array index value to update
for textvalue in arrayTextField{
print(textvalue.text)
}

Resources