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.
Related
I have a table view controller with a custom cell which contains a text field - it's a form basically.
i want to automatically go to the next text field when users press "return" on their keyboard but for some reason my solution doesn't work.
In TableViewController, I do:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? CustomCell
cell?.box.tag = indexPath.row
In my custom table view cell, I have
override func awakeFromNib() {
super.awakeFromNib()
box.delegate = self
...
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if let nextField = textField.superview?.viewWithTag(textField.tag+1) as? UITextField {
nextField.becomeFirstResponder()
} else {
textField.resignFirstResponder()
}
return true
}
The issue is that textField.superview?.viewWithTag(textField.tag+1) is always nil. I don't know why because I clearly set the tag and also mark it as a delegate. thank you.
Adding some clarity and more suggestions to the valid answer by #jawadAli, as I feel you are still new to iOS development.
You are trying to get the tableView from the textField. But you will not get it by referring to the superview of textField. Because the view hierarchy would be like this:
UITableView > UITableViewCell > contentView > Your text field.
There can also be some more views in the view hierarchy, so you need to keep traversing through the superview chain till you get the UITableView. And #jawadAli has posted the code on how to get it.
But overall that is an incorrect approach. You should use delegation. I.e. your cell should call a method when it has resigned as first responder. And your table view controller will receive that call.
Then your view controller has to get the next cell and make it the first responder.
And if this doesn't make any sense to you, then I would very strongly suggest that you learn about Delegation. It's ubiquitous in iOS' libraries.
EDIT:
Approach to use delegation.
Create a protocol, let's say CellDelegate that has a function like func didFinishDataCapture(forCell: UITableViewCell).
The cell will have a delegate property of type CellDelegate.
The controller will conform to CellDelegate and will set itself as the cell's delegate in func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
Now in your cell, when you are done with the text field (which you would know as cell would be the text field's delegate), you call your own delegate's function i.e. delegate.didFinishDataCapture(forCell: self).
In your implementation of didFinishDataCapture in the controller, you will know which cell has finished with the data capture and can put the logic on what to do next.
It should be nil as textField.superview is your cell class ... and your cell class does not have the view with required Tag .. so it will return nil..
import UIKit
extension UIView {
func lookForSuperviewOfType<T: UIView>(type: T.Type) -> T? {
guard let view = self.superview as? T else {
return self.superview?.lookForSuperviewOfType(type: type)
}
return view
}
}
Get tableView through this extension like this
let tableView = self.view.lookForSuperviewOfType(type: UITableView.self)
your function will become
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
let tableView = self.view.lookForSuperviewOfType(type: UITableView.self)
if let cell = tableView?.cellForRow(at: IndexPath(row: textField.tag+1, section: 0)) as? CustomCell {
cell.box.becomeFirstResponder()
} else {
textField.resignFirstResponder()
}
return true
}
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.
I created a custom UITableViewCell, and a UITextView was put inside this prototype cell. When I click on this textView, keyboard can bounce automatically. However, if I want to hide the keyboard, I will have to click Return key. It isn't quite convenient.
Here's the question.
How can I resign the textView's firstResponder for hiding the keyboard when I scroll the tableview.
cellForRowAtIndex method is below.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = UITableViewCell()
if(indexPath.section == 0){
cell = self.tableView.dequeueReusableCellWithIdentifier("InputCell")!
let textView = cell.viewWithTag(102) as! UITextView
textView.editable = true
textView.keyboardType = UIKeyboardType.Default
textView.delegate = self
textView.targetForAction(#selector(FeedBackViewController.getTextViewInsideCell(_:)), withSender: textView)
}
if(indexPath.section == 1){
cell = self.tableView.dequeueReusableCellWithIdentifier("ConfirmButtonCell")!
let label = cell.textLabel
label?.text = "send"
label?.textAlignment = NSTextAlignment.Center
label?.textColor = UIColor.redColor()
}
return cell
}
Here are some methods I have implemented.
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool{
if(text == "\n"){
textView.resignFirstResponder()
return false
}
return true
}
And I have no idea how to implement this method.
func scrollViewWillBeginDragging(scrollView: UIScrollView) {
}
You can try implement this on viewDidLoad, it will auto dismiss keyboard when tableview start dragging:
tableView.keyboardDismissMode = .Interactive or .OnDrag
UITableView inherited from UIScrollView that conforms to UIScrollViewDelegateProtocol. Try to override scrollViewDidScroll function from it and resign first responder from textview.
Be sure to assign tableView's delegate to your view controller, and then add the following code
func scrollViewDidScroll(scrollView: UIScrollView) {
yourTextView.resignFirstResponder()
}
As per docs scrollViewDidScroll
Tells the delegate when the user scrolls the content view within the receiver.
Update
Another approach to resign first responder is to set endEditing to true for your view:
Causes the view (or one of its embedded text fields) to resign the first responder status.
func scrollViewDidScroll(scrollView: UIScrollView) {
self.view.endEditing(true)
}
it is quite easy You can do same with storyboard too
open storyboard
select tableview or collection view
and select on Drag
I have a couple of UITextfields in each table cell. By hitting the "Done" button or touching outside the keyboard, the keyboard should be dismissed.
My problem: the textFieldShouldEndEditing method is only called when I tap another textfield and the keyboard won't be dismissed.
I think i've implemented the necessary parts (Delegate and protocol methods).
Does anyone know what I'm missing here....?
Here is the code (the relevant part):
class myVC: UIViewController, UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate {...
This is the cell setup...
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let tcell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "tbCell")
let textfield: UITextField = UITextField(frame:...
switch (indexPath.section) {
case 0: ...
case 1:
textfield.text = section2[indexPath.row]
tcell.addSubview(textfield)
textfield.delegate = self
return tcell
and this the protocol method:
func textFieldShouldEndEditing(textField: UITextField) -> Bool {
textField.resignFirstResponder()
print("method is called")
return true
}
Thank you!
I am giving this answer in Objective-C because I don't use Swift
tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
when you will scroll your tableview, and:
tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;
when you will touch outside textfield.
Swift 4.0
tableView.keyboardDismissMode = .onDrag
or
tableView.keyboardDismissMode = .interactive
why dont you try textFieldShouldReturn delegate of UITextfield.
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return NO;}
I have an uitableview with a custom cell which gets data from the array.
Custom cell has an uilabel and an uibutton (which is not visible until the uilabel text or the array object which loads for the text - is nil).
On launch everything is fine. When i press the uibutton the array is being appended, the new cells are being inserted below the cell.
But when i scroll - all of a sudden the uibutton appears on other cells where this conditional uilabel text isEmpty is not implied.
Here is how the whole process looks like
Here is my code for cellForRowAtIndexPath
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:TblCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as! TblCell
cell.lblCarName.text = someTagsArray[indexPath.row]
if let text = cell.lblCarName.text where text.isEmpty {
cell.act1.hidden = false
} else {
println("Failed")
}
cell.act1.setTitle(answersdict[answersdict.endIndex - 2], forState:UIControlState.Normal)
cell.act2.setTitle(answersdict.last, forState:UIControlState.Normal)
return cell
}
So my general question is how do i stop the reuse of those custom cells?
As far as i'm aware there is no direct way of doing this on reusablecellswithidentifier in swift, but maybe there are some workarounds on that issue?
When a cell is reused, it still has the old values from its previous use.
You have to prepare it for reuse by resetting that flag which showed your hidden control.
You can do this either in tableView:cellForRowAtIndexPath: or the cell's prepareForReuse method.
Update:
Here's an example you can add for TblCell:
override func prepareForReuse()
{
super.prepareForReuse()
// Reset the cell for new row's data
self.act1.hidden = true
}