I have two classes. In one of them, the return key (for the virtual keyboard) works perfectly. In the other, it does not. As far as I can tell, the code is pretty much identical. Can someone help me figure out why my its not firing on the one that doesn't work?
This one works:
class ChangePasswordVC: UIViewController, UITextFieldDelegate {
func textFieldShouldReturn(textField: UITextField) -> Bool {
if textField == self.tempPasswordTextField {
self.changeTempPasswordTextField.becomeFirstResponder()
}
else if textField == self.changeTempPasswordTextField {
self.confirmChangeTempPasswordTextField.becomeFirstResponder()
}
else {
changePasssword()
}
return true
}
}
This one does not work:
class ResetPasswordVC: UIViewController, UITextFieldDelegate {
func textFieldShouldReturn(textField: UITextField) -> Bool {
if textField == self.emailTextField {
print("go button tapped")
submitEmailForPasswordReset()
}
return true
}
}
I put the print statement in to see if it fires at all but it doesn't print anything to the console.
You have forgot probably some of the delegate settings, check for:
self.tempPasswordTextField.delegate = self
self.changeTempPasswordTextField.delegate = self
self.confirmChangeTempPasswordTextField.delegate = self
self.emailTextField.delegate = self
In your code especially check the last (self.emailTextField).
You have to set UITextField delegate either using StoryBoard/XIB or using code. It will work fine when UITextField delegate assigned correctly.
Related
I'm simply trying to use a UITextField for my iMessage App.
The problem is with when it is in compact mode (MSMessagesAppPresentationStyleCompact) once you select the textfield, all the views disappear. It seems to work fine in expanded mode.
What is the proper way of using a textfield in compact mode? Thanks
It appears that you can only use textfields while in expanded mode, so you'll need to implement something like this:
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
if([self presentationStyle] == MSMessagesAppPresentationStyleCompact) {
[self requestPresentationStyle:MSMessagesAppPresentationStyleExpanded];
self.didRequestKeyboard = YES;
return NO;
}
return YES;
}
-(void)didTransitionToPresentationStyle:(MSMessagesAppPresentationStyle)presentationStyle {
// Called after the extension transitions to a new presentation style.
// Use this method to finalize any behaviors associated with the change in presentation style.
if(presentationStyle == MSMessagesAppPresentationStyleExpanded){
if(self.didRequestKeyboard){
[self.textField becomeFirstResponder];
self.didRequestKeyboard = NO;
}
}
}
I struggled with this problem (still present as of iOS 10.2) and ended on this workaround:
fileprivate class TextField: UITextField {
override var canBecomeFirstResponder: Bool {
if let viewController = viewController as? MSMessagesAppViewController,
viewController.presentationStyle == .compact {
viewController.requestPresentationStyle(.expanded)
return false
}
return super.canBecomeFirstResponder
}
}
I say "workaround" because I feel this is a problem Apple should solve ergo this solution should be temporary. This implementation, as an alternative to the original answer's, is segregated and can be easily ripped out.
Same solution but using blocks
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
if presentationStyle != .expanded {
didTransitionHandler = {
textField.becomeFirstResponder()
self.didTransitionHandler = nil
}
requestPresentationStyle(.expanded)
return false
}
return true
}
I happening the following problem:
I have two TextField, one has the default behavior, and on the other, captures the textFieldDidBeginEditing method delegate, to present a UIViewController with PresentationStyle (Custom) and TransitionStyle (CrossDissolve). So far everything works fine. But if I edit the first textField (and leave the keyboard open) and then go to the second, the keyboard is open and I have no way to close it (as if the first textField had lost focus, not even the textFieldShouldReturn is called when I press the button intro).
I tried with:
TextFieldDidEndEditing (for calling resignFirstResponder)
In viewWillDissaper method (I also called resignFirstResponder)
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
func textFieldDidEndEditing(textField: UITextField) {
print("Resign Last TextField")
textField.resignFirstResponder()
}
func textFieldDidBeginEditing(textField: UITextField) {
print("Did Begin editing")
if textField == self.departing || textField == self.returning{
textField.resignFirstResponder()
self.lastTextFieldSelected = textField
let datePickerViewController = Util.getViewController("DatePickerViewController") as! DatePickerViewController
datePickerViewController.dateStyle = NSDateFormatterStyle.ShortStyle
datePickerViewController.modalTransitionStyle = UIModalTransitionStyle.CrossDissolve
datePickerViewController.modalPresentationStyle = UIModalPresentationStyle.Custom
datePickerViewController.datePickerDelegate = self
self.presentViewController(datePickerViewController, animated: true, completion: nil)
}
}
Edit:
I try with self.view.endEditing(true) nothing.
I made a little example (something I check, is that textFieldShouldBeginEditing allows me to close the keyboard.):
https://github.com/Abreu0101/TextFieldBug
It looks like your textFieldDidEndEditing and the other methods are not even called. Make sure you set the UITextField's delegate:
textField.delegate = self
Also import the UITextFielDelegate in your class.
Hope that helps :)
i'm trying to change the default action when user press on a text field. I tried to connect my action at Editing Did Begin event using storyboard as you can see below. The problem is that the keyboard always appear but I want that the keyboard doesn't never appear.
I cannot delete text field delegate methods cause i have others text field in the same view.
How can i do?
Set your view controller as your textField delegate and implement UITextField textFieldShouldBeginEditing delegate method.
func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
if textField == yourTextField {
// implement custom behaviour
return false
}
return true
}
Update
Try this for single textfield keyboard never show
func textFieldDidBeginEditing(textField: UITextField) {
if textField == yourTextField
{
textField.inputView = UIView()
}
}
Simple:
func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
if(textField == YourtextField){
return false
}
return true
}
OR:
in your viewDidLoad() set yourTextField.inputView = UIView()
Works in both ways. Use suitable one.
In the following code I am trying to transfer control from UITextField to the next via a next button.
I am doing this by calling becomeFirstResponder on the next UITextField.
If I don't type anything in the first and current UITextField the next button works as expected. The keyboard stays up and the focus is transferred.
If I do type something, and only if the field is empty. The method becomeFirstResponder for the next field is called and returns true, yet the keyboard is dismissed and focus is not transferred.
public func numberPad(numberPad: APNumberPad, functionButtonAction:UIButton, textInput: UIResponder) {
var current:UITextField?
for field in editCells {
if (current != nil) {
field.valueTextField.becomeFirstResponder()
return;
}
if (field.valueTextField == activeField) {
current = field.valueTextField
}
}
textInput.resignFirstResponder()
}
This function is called when the NEXT or DONE button is pressed on the keyboard. Which is a custom number keypad. APNumberPad specifically.
https://github.com/podkovyrin/APNumberPad
It is my delegate function.
Anyone know any reason becomeFirstResponder would return true and not work, only in some cases, but work in others?
And yes this is the main UI thread. Adding a call to resignFirstResponder on the current field, then a delay and calling becomeFirstResponder works. This causes the keypad to flicker, no matter how small the delay though.
Edit... I am now doing this... and am living with the keyboard flicker for now:
Delay is a helper function for GCD
public func numberPad(numberPad: APNumberPad, functionButtonAction:UIButton, textInput: UIResponder) {
var current:UITextField?
for field in editCells {
if (current != nil) {
current?.resignFirstResponder()
delay (0) {
field.valueTextField.becomeFirstResponder()
}
return;
}
if (field.valueTextField == activeField) {
current = field.valueTextField
}
}
textInput.resignFirstResponder()
}
I don't know if it helps you, or not. I wrote a simple UITextField extension that contains a returnView variable which decides what the textfield should do on return key press:
turn to next text field (if the returnView is an UITextField)
simulate button touch (if the returnView is a UIButton)
or hide keyboard
class NextTextField: UITextField, UITextFieldDelegate {
#IBOutlet weak var returnView: UIView? {
didSet {
if returnView is UITextField {
returnKeyType = UIReturnKeyType.Next
}
}
}
override func awakeFromNib() {
super.awakeFromNib()
delegate = self
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
if let nextTextField = self.returnView as? UITextField {
nextTextField.becomeFirstResponder()
} else if let nextButton = self.returnView as? UIButton {
nextButton.sendActionsForControlEvents(.TouchUpInside)
} else {
self.resignFirstResponder()
}
return true
}
}
Ok so I have a function that allows my user to use the keyboard to go to the next field (Which I got the code from SO) It works perfect. My problem is, once my user gets to the final text field, in which, I've selected "GO" as the return button, and I want to use the go as the ideal submit button. As the flow through the form goes, its presentably right, but the functionality at the end isn't there. I found an answer here, but it looks like its calling the same functions as the "next field" code. So they don't work well together. So here's what the Next Field code looks like:
override func viewDidLoad() {
super.viewDidLoad()
// Keyboard Next Field & Delegate
enterEmailTextField.delegate = self
enterPasswordTextField.delegate = self
self.enterEmailTextField.nextField = self.enterPasswordTextField
self.enterPasswordTextField.nextField = self.enterNameTextField
// ...
}
And the next block is displayed below override (which i'm sure you know) func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() }
// Next Field
func textFieldShouldReturn(textField: UITextField) -> Bool {
if let nextField = textField.nextField {
nextField.becomeFirstResponder()
}
return true
}
Ok that works just fine down to the last text field, But since the last field is "Go" I'm trying to mimic what I would do with say an #IBAction for a button, but instead the go button. Here's where I got the idea/code for the Go to work:
Action of the "Go" button of the ios keyboard
Any Ideas on how to implement these? Or maybe just to work with the next function, and implement a "keyboard go" action similar to an #IBaction? Maybe just an all around better way to implement both of these so they coincide with each other? Any help is much appreciated!
EDIT!
I forgot the actual NextField.swift File which I'm sure is important (sorry)
import Foundation
import UIKit
private var kAssociationKeyNextField: UInt8 = 0
extension UITextField {
#IBOutlet var nextField: UITextField? {
get {
return objc_getAssociatedObject(self, &kAssociationKeyNextField) as? UITextField
}
set(newField) {
objc_setAssociatedObject(self, &kAssociationKeyNextField, newField, UInt(OBJC_ASSOCIATION_RETAIN))
}
}
}
this would help a lot I'm assuming
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
if (textField.returnKeyType == UIReturnKeyNext) {
// tab forward logic here
return YES;
}
else if (textField.returnKeyType == UIReturnKeyGo) {
// submit action here
return YES;
}
return NO;
}
On a cleaner way to handle tab order and form submitting, read my answer here.
First set return key to Go of your TextField, then implement the following method:
func textFieldShouldReturn(textField: UITextField) -> Bool {
if (textField.returnKeyType == UIReturnKeyType.Go)
{
// Implement your IBAction method here
}
return true
}
then see in below image:
Available for iOS 15 in SwiftUI. You can use .submitLabel(.go) to do it.
#available(iOS 15.0, *)
struct TextFieldSubmitView: View {
#Binding var name: String
var body: some View {
VStack(alignment: .leading) {
TextField("Type text", text: $name)
.textFieldStyle(.roundedBorder)
.padding()
#if os(iOS)
.submitLabel(.go)
#endif
}
}
}
#available(iOS 15.0, *)
struct TextFieldSubmitView_Previews: PreviewProvider {
static var previews: some View {
TextFieldSubmitView(name: .constant("Name"))
.previewLayout(.sizeThatFits)
}
}