This problem has been driving me crazy. It seems no matter what I try I cannot get the keyboard to hide once it is shown in my simple Swift program.
It does not work when I resignFirstResponder() in textFieldShouldReturn nor does it work when handing a background touch by calling endEditing() from touchesBegan(...). I can see these respective methods are all being called when I set debugger break points to them, so the delegate is properly set and being called as expected.
Here are the specific steps I took:
Create a new single-view application Swift project
Drag a UITextField onto the view, wire up the IBOutlet, and set the ViewController up as UITextFieldDelegate.
Run in iPhone 6 Simulator or on an iPhone 6 device
Once the keyboard is presented, it is never dismissed!!
I am out of ideas - what am I missing???
Here is the entire contents of my ViewController:
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var myTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
myTextField.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
self.view.endEditing(true)
}
func textFieldDidBeginEditing(textField: UITextField!) {
return
}
func textFieldShouldEndEditing(textField: UITextField!) -> Bool {
return false
}
func textFieldShouldReturn(textField: UITextField!) -> Bool {
textField.resignFirstResponder()
return true
}
}
You are returning 'false' from 'textFieldShouldEndEditing'. The following is an excerpt from the 'UITextFieldDelegate' documentation:
Return Value
YES if editing should stop; otherwise, NO if the editing session
should continue
Discussion
This method is called when the text field is asked to resign the first
responder status. This might occur when your application asks the text
field to resign focus or when the user tries to change the editing
focus to another control. Before the focus actually changes, however,
the text field calls this method to give your delegate a chance to
decide whether it should.
Normally, you would return YES from this method to allow the text
field to resign the first responder status. You might return NO,
however, in cases where your delegate detects invalid contents in the
text field. By returning NO, you could prevent the user from switching
to another control until the text field contained a valid value.
Source
So, either return 'true' from it or remove the method completely, unless you really need to do something useful inside it. 'textFieldDidBeginEditing'and 'touchesBegan' should also probably be removed. I'm really surprised that the same code worked in Objective-C.
Related
I am trying to have the keyboard dismiss when clicking the return key on the keyb board when using a UITextField. The class is set with the UITextFieldDelegate, I am setting the textfield's delegate to self and also have the textFieldShouldReturn function. With all this, I am still unable to get it to work.
EDIT: After trying with a print statement, the textFieldShouldReturn function is not being called at all.
After removing all other code from the view controller except the one below, it started working. My only clue to why would be due to me using self.loadview() in viewWillAppear and viewDidDissapear, might this be the case?
FIXED: problem was due to using self.loadview(). After changing that part of the code, everything started working properly.
Part of code for this function shown below.
class ConfigurationViewController: UIViewController, UITextFieldDelegate {
#IBOutlet var storeNameVal: UITextField!
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true;
}
override func viewDidLoad() {
super.viewDidLoad()
storeNameVal.delegate = self
}
}
I'm working on a program in Swift that is practically like a mini-test (if you are familiar with MVC, the Model holds all the information, questions, answers, etc.) However, I am unable to get my program's textbox to respond to return on the virtual keyboard in iOS. Am I doing something wrong? Thanks!
func textFieldShouldReturn(textField: UITextField) -> Bool {
model.recordAnswer(textField.text!)
numCorrect = model.numOfCorrectAnswers
numWrong = model.numOfIncorrectAnswers
txtViewQuestionStatus.text = "\(model.incorrectItems())\n"
model.theQuestion++
if model.hasMoreQuestions == true {
updateQuestionAndAnswer()
}
textField.resignFirstResponder() //hide keyboard
return true
}
Please make sure that the above function is called. If it is not called, then you need to set the delegate of your textField. You can do that as follows:
If txtViewQuestionStatus this is your UITextField, in your viewDidLoad() method, add the following line:
txtViewQuestionStatus.delegate = self
If there is error in the above line showing delegate is not set, You need to add UITextFieldDelegate in your class. Like :
class ViewController : UIViewController <UITextFieldDelegate>
there are many similar questions about TextFields delegate method textfieldshouldreturn not being called, but all were solved by setting the delegate. Ive set the delegate, and also have a perfectly fine example in another project I've copied almost line for line. A print statement confirms no call is made. Whats more curious is that I set a random variable to test if I was even accessing the right object, but when I tried to access that variable, it crashed with a BAD_ACCESS error.
class TitleTextField: UITextField, UITextFieldDelegate {
var randomElement: Bool = true
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
print("text field return pressed")
return true
}
}
and here is where I'm using it
class EditViewController: UIViewController {
#IBOutlet weak var titleTextField: TitleTextField!
func configureView() {
navigationItem.title = "Edit Goal"
}
override func viewDidLoad() {
super.viewDidLoad()
print("editor loaded")
configureView()
titleTextField.text = "placeholder"
titleTextField.delegate = titleTextField
titleTextField.delegate = titleTextField.self
if let textField = titleTextField {
textField.delegate = titleTextField
}
print("textfield delegate = \(titleTextField?.delegate)")
}
If listed some of the different ways I tried setting the delegate. I even conformed the viewController to UITextFieldDelegate and set the delegate to self but that didn't matter either. I added "randomVariable" to TitleTextField to make sure I was accessing the correct object, but when I used titleTextField.randomVariable = true in viewDidLoad, I got a BAD_ACCESS crash.
Ive also double checked the storyboard connection. I even deleted the connection and IBoutlet and redid them, no difference. cleaned project etc.
Wow ok, so the problem was I hadnt set the textfield class to TitleTextField in my identity inspector. I had it programmatically set, I guess I didnt realize i had to do it in the storyboard too.
The issue is that you're conforming to the UITextFieldDelegate on your custom TitleTextField itself. Instead, you should conform to the protocol on your UIViewController, like so:
class EditViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var titleTextField: TitleTextField!
func configureView() {
navigationItem.title = "Edit Goal"
}
override func viewDidLoad() {
super.viewDidLoad()
print("editor loaded")
configureView()
titleTextField.text = "placeholder"
titleTextField.delegate = self
print("textfield delegate = \(titleTextField?.delegate)")
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
print("text field return pressed")
return true
}
The purpose of the delegate is to respond to editing-related messages from the text field (link to docs). This means that the UITextField is already aware of these editing events. What you need to do is allow the class containing your custom UITextField to listen to the events that it is sending out. In your situation, that class is EditViewController. You can make EditViewController listen to the UITextView's events by setting it as the delegate.
The reason for your BAD_ACCESS error is a memory-related issue. Your UITextField is calling itself infinitely through recursion. If you look through the calling stack you'll probably see it calling the same method hundreds of times. See this post for more insight.
The textFieldShouldReturn function is not being called at all: there are no errors but the keyboard does not respond at all.
My case is different from How to hide keyboard in swift on pressing return key? as in my case nothing is happening at all and other cases are in Objective-C.
Here is my code:
import UIKit
class ViewController: UIViewController {
#IBOutlet var textField: UITextField!
func textFieldShouldReturn(textField: UITextField) -> Bool {
resignFirstResponder()
return true
}
}
textField is an outlet to a text field on my storyboard. I also tried self.endEditing instead of resignFirstResponder.
The rest of this answer is still very useful, and I'll leave it there as it can potentially help other askers... but here, I missed the obvious problem with this specific example...
We're not calling resignFirstResponder on the text field. We're calling it on the view controller. We need to call it on the text field, so modify your code to look like this:
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
A UITextField will only call the textFieldShouldReturn property on the object which is its delegate.
We can fix this programmatically by adding a viewDidLoad method to set that:
override func viewDidLoad() {
super.viewDidLoad()
self.textField.delegate = self
}
But we can also set this up via the storyboard at build time.
Right click on the textfield to check and see whether or not the delegate has been set:
If that circle next to delegate is unfilled, we haven't set the delegate for our UITextField yet.
To set the delegate, hover over this circle. It will change to a plus sign. Now click and drag to the view controller that you want to delegate the text field (the view controller the text field is part of).
When you've appropriately hooked the view controller up as a delegate, this menu should look like this:
If using Swift 3+, you have to add an underscore before the first property. Like:
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
This is also very well documented in the Apple Documentation.
https://developer.apple.com/documentation/uikit/uitextfielddelegate/1619603-textfieldshouldreturn
I'm enrolled in a Swift 4 Udemy course, and the instructor said to add the UITextFieldDelegate class for the ViewController in addition to Cntrl - dragging from the textField to the ViewController button and selecting delegate.
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}
Well, in my case. I accidentally enable hardware keyboard. Make sure you unchecked "Connect to hardware keyboard" in order for the keyboard to show up in the simulator.
Hardware -> Keyboard -> Connect to hardware keyboard
Hope this will help others too!
You can set all textFields delegate in a loop:
var tF: [UITextField] = []
tf = [my1TextField, my2TextField, my3TextField]
for textField in tf {
textField.delegate = self
}
I really want to be able to detect a paste event in a UITextView, however it appears this cannot be done.
I originally tried subclassing a UITextView and overriding the paste: method, but it never gets called on a paste event.
Has anyone been able to do this? A previous question on the same ilk didn't have an answer back in August...
The text view doesn't catch the paste: event because it wasn't the actual responder is not the text view, but the private web view (UIWebDocumentView) that powers the text view.
However, on paste, the web view will call the text view's (private) -[UITextView keyboardInput:shouldInsertText:isMarkedText:], and in turn, the text view's delegate's -textView:shouldChangeTextInRange:replacementText:.
Therefore, you just need to implement -textView:shouldChangeTextInRange:replacementText: in the text view's delegate.
(Of course, normal keyboard input will trigger this method too. There's no perfect way to distinguish them.)
#KennyTM what I did for one of my applications was keep up with the current text length and the previous text length. If the (currentTextLength - previousTextLength) was greater than 1, then the user must have pasted something
With iOS 14 you have to do this in two parts to avoid showing the user notification that you are checking the UIPasteboard. In my case I did not want to do anything bad with the user data but I did want to do some special formating when the user did paste into the UITextView.
Step 1: Create a custom UITextView and override paste()
import UIKit
protocol TouchableTextViewDelegate : class{
func touchesDidBegin()
func pasting()
}
class TouchableTextView: UITextView {
weak var touchableDelegate : TouchableTextViewDelegate?
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
if self.isFirstResponder{
return true
}
touchableDelegate?.touchesDidBegin()
return false
}
override func paste(_ sender: Any?) {
touchableDelegate?.pasting()
super.paste(sender)
}
}
Step 2: In the file location where you handle the shouldChangeTextIn create a variable and be sure to set the delegate for the TouchableTextView. In my case
//top of the view
var isPasting : Bool = false
//also when creating UITextView use both delegates
textView.touchableDelegate = self
//add the normal delegate
textView.delegate = self
extension SliderTextView : TouchableTextViewDelegate{
func pasting() {
self.isPaste = true
}
func touchesDidBegin() {
sliderEditingDelegate?.touchesDidBegin(sliderTextView: self)
}
}
Step 3: Inside shouldChangeTextIn I handle the action like this
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let isPaste = self.isPaste
//be sure to set this to false
self.isPaste = false
if isPaste,
let pt = UIPasteboard.general.string,
text.contains(pt){
//you will see the paste notification and that is good for the user
// but only when the user pastes
// do whatever special thing or formatting you want to do
}
return true
}
The good is that you will not trigger the notification unless the user is pasting in the UITextView.
To detect if a user is parsing a text in a textView, compare the replacementText in the shouldChangeTextInRange delegate with the text the user is currently holding in the UIPasteboard. Then take action depending on requirements.
for code, see my answer in the following question:
how to know when text is pasted into UITextView