I am using a table view controller to display content. I am trying to make an editable UITextField, but it is not editable. I can get them to display in each cell, but when I tap on them they aren't editable. I am also trying to store what the user enters in each cell. Please ignore the commented out parts. Here is my code:
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return words.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "transportCell", for: indexPath)
self.tableView.rowHeight = 100
//var a = Array(words[indexPath.row])
//a.shuffle()
//var shuffledWord = String(a)
//shuffledWord = shuffledWord.lowercased()
let sampleTextField = UITextField(frame: CGRect(x:60, y: 30, width: 150, height: 40))
sampleTextField.placeholder = "Enter text here"
sampleTextField.font = UIFont.systemFont(ofSize: 15)
sampleTextField.borderStyle = UITextBorderStyle.roundedRect
sampleTextField.autocorrectionType = UITextAutocorrectionType.no
sampleTextField.keyboardType = UIKeyboardType.default
sampleTextField.returnKeyType = UIReturnKeyType.done
sampleTextField.clearButtonMode = UITextFieldViewMode.whileEditing;
sampleTextField.contentVerticalAlignment = UIControlContentVerticalAlignment.center
sampleTextField.delegate = self as? UITextFieldDelegate
var userEntry = sampleTextField.text
sampleTextField.tag = indexPath.item // You will access the text field with this value
cell.addSubview(sampleTextField)
//cell.textLabel?.text = shuffledWord
//var imageName = UIImage(named: words[indexPath.row])
//cell.imageView?.image = imageName
return cell
}
Changecell.addSubview(sampleTextField) to cell.contentView.addSubview(sampleTextField)
Please refer to https://developer.apple.com/documentation/uikit/uitableviewcell/1623229-contentview for details about contentView
There could be couple of reasons for textfield is not editable .
Check if you have used the UITextFieldDelegate and set the textfield delegate to self i.e. textfield.delegate = self
When you add subviews to cell make sure you add it to the content view of the cell. e.g cell.contentView.addSubview(textField)
Make sure there is no other view on top of textfield.
If you have implemented :
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool then it should return true otherwise keyboard will not appear and you won't be able edit text field.
Check if textfield is enabled both view swift file and storyboard .
6.Make sure proper connection is made between textfield in your storyboard or Xib file and #IBOutlet textfield in your view controller where you have declared textfield.
please check that you are not resigning keyboard or endEditing is set to true on textFieldShouldBeginEditing, shouldChangeCharactersIn and textFieldShouldBeginEditing delegates of textfield.
I hope this helps you out!!
According to me,
You need to set priority of sampleTextField upon tableview cell selection.
Whenever you are trying to select the sampleTextField to edit it,
didselect function of tableview is getting call. Check by putting
breakpoints in didselect function. If this is happening, you need to
set the priority.
Also, check if you are not resigning keyboard in textFieldShouldEndEditing in delegate function of keyboard.
sampleTextField.isUserInteractionEnabled = true
Also, add sampleTextField on cell.contentView instead directly to cell.
Once,
You are able to edit, you can directly get the data from the textfield for storing it by sampleTextField.text
Hope, this will be effective. If you still find issue, feel free to ask.
Related
I have a UITableView that uses custom UITableViewCell. cell contains a UITextField. like in image below.
each TextField is configured in the cellForRowAtIndexPath method. eg. textContentType, keyboardType etc.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ReuseCellIdentifier", for: indexPath) as! FormTableViewCell
let inputItem = inputItems[indexPath.row]
cell.titleLabel.text = inputItem.title
cell.inputTextField.placeholder = inputItem.placeholder
cell.inputTextField.textContentType = inputItem.contentType
cell.inputTextField.keyboardType = inputItem.keyboardType
cell.inputTextField.isSecureTextEntry = inputItem.isSecure
return cell
}
However when editing last TextField(Re-Password) it shows email addresses as autofill suggestions although the textContentType is set to newPassword.
if tapped on one of the suggestions, the email(3rd textField) is populated with the email. not the textField that was being edited. also 4th textfield(password) becomes first responder.
weirdly, if I remove this line, the problem goes away
cell.inputTextField.isSecureTextEntry = inputItem.isSecure
InputItem class,
class InputItem:Mappable {
var title:String?
var placeholder:String?
var contentType:UITextContentType?
var keyboardType:UIKeyboardType?
var isSecure:Bool = false
}
// you can set autocorrectionType to turn on/off suggestions
// UITextAutocorrectionType can be .no or .yes
cell.inputTextField.autocorrectionType = inputItem.autocorrectionType // set .no to turn off suggestions
I have a table view of custom table view cells. Each of the cells has a text field where I can fill in some numeric data. I have set up a delegate method i.e. textFieldDidEndEditing which after editing will add the value entered into a text field into a swift hashtable.
However, I see that some other text field which belongs to another completely different table view cell also now has the same value that I entered.
In order to solve this problem, I tried to add other delegate based text field methods thinking that they should solve the problem at hand. One of the methods I used was the textFieldDidChange method and in that method, I wrote the check that if the text field tag was not the same as the tag of the deliberately edited text field, then I clear the text field out.
func textFieldDidChange(_ textField: UITextField) {
if textField.tag != self.service!.id {
print("CLEARING AFFECTED TEXTFIELD")
textField.text = ""
}
}
I probably used the method the wrong way as it did not have any effect on the problem.
I am adding the code snippets which are involved in the problem at hand:-
BookingServiceChargeViewCell.swift
import UIKit
import PineKit
import SwiftMoment
class BookingServiceChargeViewCell: UITableViewCell, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate {
//Other variables
let price = TextField(placeholder: "Price")
//Other methods
func layoutContent() {
//function to set the layout of the cell
self.price.font = Config.Font.get(.Regular, size: 13)
self.price.delegate = self
self.price.setValue(UIColor.init(colorLiteralRed: 71/255, green: 72/255, blue: 73/255, alpha: 1.0), forKeyPath: "_placeholderLabel.textColor")
self.price.keyboardType = UIKeyboardType.numberPad
self.price.addDoneButtonOnKeyboard()
self.price.setBottomBorder()
self.price.snp.makeConstraints { (make) in
make.centerY.equalTo(cover)
make.width.equalTo(75)
make.right.equalTo(content.snp.right).offset(-40)
}
}
func configure(_ service: Service, subServices: [Service], index: Int, parentView: OnboardingChosenServicesViewController) {
self.service = service
self.subServices = subServices
self.itemIndex = index
self.parentView = parentView
if (self.service!.defaultImage != nil){
ImageLoader.sharedLoader.imageForUrl(urlString: self.service!.defaultImage!) { (image, url) in
self.cover.image = image
}
}
self.serviceName.text = self.service!.name!
self.price.tag = self.service!.id
self.table.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.subServices.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! BookingSubServicesChargeViewCell
cell.configure(self.subServices[indexPath.row], index: indexPath.row, parentView: self.parentView!)
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80
}
func textFieldDidEndEditing(_ textField: UITextField) {
self.parentView!.serviceAndCharges[textField.tag] = Int(textField.text!)
print(self.parentView!.serviceAndCharges)
}
}
I am uploading a couple of screenshots showing the problem:-
As you can see, I have entered a numeric value to the text field that is in the 'Daycare' cell
In this screenshot the text field in the 'Walking' cell should not have been edited at all, it should have remained blank like all other text fields except the one I just edited.
How can I solve this problem?
This problem arises when you dequeue your cell with the same identifier. To solve this problem, you have to save the values written in the cell in some data set and while reloading table view in cellForRow method, use that data set to configure your cell.
You can do that by making a delegate in your CustomCell and make your custom cell a delegate of the text field present in your cell and when text field did end editing you can pass those values to your controller via delegate and save those values in the datasource. While loading your tableview use that datasource to configure your cell
I have a dynamic Table as UITableView and all cells are as normal (retrieved form my array)
However I need only one cell as TextView to be able input text. On text Change I need to retrieve the text user input.
How to make this?
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count+1 //to allow this input field
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if(indexPath.row < array.cont){
//normal cell from array
let cell = Table.dequeueReusableCell(withIdentifier: "myCell")
cell?.textLabel?.text = array[indexPath.row]
cell?.isUserInteractionEnabled = true;
cell?.textLabel?.adjustsFontSizeToFitWidth = true
cell?.textLabel?.textAlignment = .center;
return cell!;
}else{
//create input text field (DON'T KNOW HOW)
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if(indexPath.row < array.cont){
//.. perform action ..
}else{
//retrieve input text (DONT know How)
}
}
Creating UITextView inside UITableViewCell is quite simple :
let textView: UITextView = UITextView(frame: CGRect(x: 0, y: 20, width: 311.00, height: 50.00)) // Set frames as per requirements
textView.textAlignment = NSTextAlignment.justified
cell.contentView.addSubView(textView)
But this would lead to incorrect values while scrolling the table. Best approach would be to create a custom cell and add UITextView there. Here is the custom cell. Keep the constraints intact.
Before using the custom cell, you need to register it in your table. So :
let nib = UINib(nibName: "TextCell", bundle: nil)
Table.register(nib, forCellReuseIdentifier: "TextCell")
Don't forget to put identifier of cell in xib.
Now in cellForRowAtIndexPath :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if(indexPath.row < array.cont){
//normal cell from array
let cell = Table.dequeueReusableCell(withIdentifier: "myCell")
cell?.textLabel?.text = array[indexPath.row]
cell?.isUserInteractionEnabled = true;
cell?.textLabel?.adjustsFontSizeToFitWidth = true
cell?.textLabel?.textAlignment = .center;
return cell!;
}else{
//create input text field (DON'T KNOW HOW)
let cell = tableView.dequeueReusableCell(withIdentifier: "TextCell", for: indexPath) as! TextCell
// Access UITextView by cell.textView
return cell
}
}
The main issue is - dynamic cell size as per UITextView height. But that entirely depends on your requirement. You can follow this post for that.
You can achieve this with delegation pattern or NSNotification.
Here's the solution for this using delegation pattern.
Create new UITableViewCell using xib and add the textView on contentView of cell, set the reuse identifier and than register the xib in the ViewController with
tableView.register(UINib(nibName: "name of the xib file", bundle: nil), forCellReuseIdentifier: "Identifier here")
Now define protocol anywhere outside of the class
// You can give any name
// Here we are confirming to class to avoid any retain cycles
protocol CustomCellDelegate :class {
func returnText(text :String)
}
Now initialise " var delegate : CustomCellDelegate? " in same class of UITableViewCell that we created above while creating xib.
and confirm to protocol UITextViewDelegate and than in the cell class write this
override func awakeFromNib() {
super.awakeFromNib()
textView.delegate = self
}
after that add these functions in same class of tableViewCell
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if(text == "\n") {
textView.resignFirstResponder()
return false
}
return true
}
func textViewDidEndEditing(_ textView: UITextView) {
delegate.returnText(text : textView.text ?? "")
}
Now in the ViewController class
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == array.count { // this will call the cell with TextView at the end , you can play with any indexPath to call the cell
let cell = tableView.de... // Deque the cell with TextView here using reuse identifier
cell.delegate = self
return cell
}
else {
// deque other cells
}
}
we'll write an extension of ViewController and confirm to our custom protocol
extension ViewController : CustomCellDelegate {
// this function will get called when you end editing on textView
func returnText(text :String) {
print(text) // you may save this string in any variable in ViewController class
}
}
Add a TextView in to your custom cell, hide it, show when you need
if you want to have the textView on the top of all cells, drag and drop a UIView inside the tableView before the cell.
this view will scroll with cells.
design this view as you need insert a textView inside it, and use textView's delegate methods to perform operations.
This question already has answers here:
Cannot assign a value of type ViewController to a value of type UITextFieldDelegate?
(4 answers)
Closed 6 years ago.
I have a table view. In that I am creating the UITextField dynamically.
But I am not able to fire the events in it.
func tableView(_ tableView: UITableView, cellForRowAt indexPath:IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCell(withIdentifier: "cell",for: indexPath) as! DynamicTableCell
var dynamicTxtField1: UITextField = UITextField()
dynamicTxtField1.backgroundColor = UIColor.white
dynamicTxtField1.rightViewMode = .always
dynamicTxtField1.layer.cornerRadius = 5;
dynamicTxtField1.clipsToBounds = true
dynamicTxtField1.borderStyle = .roundedRect
// Here i am not able to assign the
//Error in this line // dynamicTxtField1.delegate = self
// Here object "self" is referring to the view. Because of this i am not able to fire any events of the UITextField
cell.addSubview(dynamicTxtField1)
}
Please suggest how to assign the delegate to the UITextField in this scenario so that I can fire an event to show a view to pick some values from it.
The error is:
"Cannot assign the value of ViewName(classname) to type UITextFieldDelegate"
on the line:
dynamicTxtField1.delegate = self
enter image description hereYou should create your textField in your cell's subclass then modify its attributes in your cellForRowAtIndexPath. Does your class implement UITextFieldDelegate?
EDIT: try this
textField.addTarget(self, action: #selector(ViewController.textfieldDidchange(_:)), forControlEvents: .ValueChanged)
cell.contentView.addSubview(textField)
and here is the method
func textfieldDidchange(textField: UITextField) {
//your code
}
I have a custom UITableViewCell with an image and UITextView property. The textview spans to the edge of the cell. My problem is tapping the textview does not register in didSelectRowAtIndexPath.
How can I make it so that I can "click through" my textview?
For UITextView set textView.userInteractionEnabled = false and if you have UITextField, set textField.userInteractionEnabled = false.
If you want the textView or textField to be editable after the cell with it is tapped, do something like this:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
let cell = tableView.cellForRowAtIndexPath(indexPath)! as UITableViewCell
// find first textField inside this cell and select it
for case let textField as UITextField in cell.subviews {
textField.userInteractionEnabled = true
textField.becomeFirstResponder()
return
}
// find first textView inside this cell and select it
for case let textView as UITextView in cell.subviews {
textView.userInteractionEnabled = true
textView.becomeFirstResponder()
return
}
}
Then make sure to disable user interaction after you finish editing:
func textFieldDidEndEditing(textField: UITextField) {
textField.userInteractionEnabled = false
// rest of the function
}
func textViewDidEndEditing(textView: UITextView) {
textView.userInteractionEnabled = false
// rest of the function
}
Don't forget to set the UITextFieldDelegate and/or UITextViewDelegate
I hope this helped someone :)
If you don't need it to be editable, just set your text view's enabled property to NO.
You can assign a delegate to your UITextView, and in its textViewShouldBeginEditing: method, you can manually call the didSelectRowAtIndexPath method. If you can't easily get the indexPath of the row to select, you can use a subclass of UITextView that has an indexPath property, and in cellForRowAtIndexPath: method, when you create your UITextView, set the indexPath property.