Navigate through textfields in UITableView swift - ios

Trying to navigate through text fields in UITableView. Able to navigate through text fields on simple view but not getting how to navigate when text fields are in UITableView.
Below is the code tried so far:
func textFieldDidBeginEditing(textField: UITextField)
{
//textField.inputAccessoryView = numberToolbar
if(textField == txtConfirmPassword)
{
textField.returnKeyType = UIReturnKeyType.Done
}
else
{
textField.returnKeyType = UIReturnKeyType.Next
}
}
Please guide thanks.
Update:
func textFieldDidBeginEditing(textField: UITextField)
{
if(delegate != nil)
{
delegate?.performSelector(NSSelectorFromString("editingTextField"))
}
if(textField.tag == 3)
{
textField.returnKeyType = UIReturnKeyType.Done
}
else
{
textField.returnKeyType = UIReturnKeyType.Next
}
}
func textFieldShouldReturn(textField: UITextField) -> Bool
{
if(delegate != nil)
{
delegate?.performSelector(NSSelectorFromString("editingDone"))
}
if(textField.tag == 3)
{
textField.resignFirstResponder()
delegate?.performSelector(NSSelectorFromString("editingDone"))
}
let nextTage=textField.tag+1
// Try to find next responder
let nextResponder=textField.superview?.viewWithTag(nextTage) as UIResponder!
if (nextResponder != nil){
// Found next responder, so set it.
nextResponder?.becomeFirstResponder()
}
else
{
// Not found, so remove keyboard
textField.resignFirstResponder()
}
return true
}

Here is the code for Swift 2.1
Here I have taken SampleTableViewCell which is a custom cell in which i have created textField.
For the purpose I have just taken the tag based on cell, so while accessing it in the textField's delegate method, You can know the textField is for which cell.
Here is the code :
//UITableView Delegate
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! SampleTableViewCell
cell.txtFld.delegate = self;
cell.txtFld.tag = indexPath.row + 100
cell.selectionStyle = UITableViewCellSelectionStyle.Gray;
return cell;
}
UPDATE : Here is the delegate for TextField
//UITextField Delegate
func textFieldDidBeginEditing(textField: UITextField)
{
//textField.inputAccessoryView = numberToolbar
if(textField.tag == 100)
{
textField.returnKeyType = UIReturnKeyType.Done
}
else
{
textField.returnKeyType = UIReturnKeyType.Next
}
}
Here I have navigate to next textfield by clicking the return button of text field.
// called when 'return' key pressed. return NO to ignore.
func textFieldShouldReturn(textField: UITextField) -> Bool
{
textField.resignFirstResponder();
if(textField.tag == 100)
{
let txtFld = self.tblList.viewWithTag(101);
txtFld?.becomeFirstResponder();
}
return true;
}
Hope it helps.
Happy coding ...

You should use the tag to check if the current textfield is the first responder.
Note: Swift 3.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// let's say that you are reading the date from an array...
return myArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! TableViewCell
// here you set the tag
cell.myTextfield?.tag = indexPath.row
// ...
return cell
}
func textFieldDidBeginEditing(textField: UITextField) {
// now, based on textField you can check (tag == myArray.count - 1 means it is the last)
textField.returnKeyType = (textField.tag == myArray.count - 1) ? .done : .next
}
Hope that helped.

Best way for me.
UITableViewCell
class CustomTableViewCell: UITableViewCell {
var nextTextField: (() -> Void)?
}
UITableViewDataSource, UITableViewDelegate
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
...
cell.nextTextField = { in
guard let cell = tableView.cellForRow(at: IndexPath(row: indexPath.row + 1, section: 0)) as? CustomTableViewCell else {
return
}
cell.textField.becomeFirstResponder()
}
return cell
}
UITextFieldDelegate
...
func textFieldDidBeginEditing(textfield: RCTextField) {
if viewModel.items.count-1 == textfield.tag {
textField.returnKeyType = UIReturnKeyType.done
} else {
textField.returnKeyType = UIReturnKeyType.next
}
}
...

Related

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
}

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

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

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

Change tableview data according to textfield in swift

I want to change the TableView data according to Textfield. when a user taps on Textfield and starts editing it will change the TableView data accordingly. I saw a lot of examples on but mainly I found about search bar any help would be appreciated. Please note that this is textfield not seacrhbar
You can try
var searchActive : Bool = false
var data = ["San Francisco","New York","San Jose","Chicago","Los Angeles","Austin","Seattle"]
var filtered:[String] = []
textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)),
for: UIControlEvents.editingChanged)
and handle method:
#objc func textFieldDidChange(_ textField: UITextField) {
// filter tableViewData with textField.text
let searchText = textField.text
filtered = data.filter({ (text) -> Bool in
let tmp: NSString = text as NSString
let range = tmp.range(of: searchText, options: NSString.CompareOptions.caseInsensitive)
return range.location != NSNotFound
})
if(filtered.count == 0){
searchActive = false;
} else {
searchActive = true;
}
self.tableView.reloadData()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier:CellIdentifier1) as! generalTableViewCell
if(searchActive){
cell.titlelb.text = filtered[indexPath.row]
} else {
cell.titlelb.text = data[indexPath.row];
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if(searchActive){
return filtered.count
} else {
return data.count
}
}
You can implement textFieldDelegate in the view controller and then in the delegate method textFieldDidChange you can change the tableview datasource according to your use and reload the tableview after that.

Resources