I have a UIViewController with a UITextField in it and I'm trying to dismiss the keyboard when I click away or the view is dismissed. However, when I call resignFirstResponder(), the keyboard still doesn't dismiss and I'm not quite sure why. Here's my code:
class MessageViewController: UIViewController, UITextFieldDelegate {
var messageTextField : UITextField = UITextField()
override func viewDidLoad() {
...
messageTextField.frame = CGRectMake(10, UIScreen.mainScreen().bounds.size.height-50, UIScreen.mainScreen().bounds.size.width-80, 40)
messageTextField.delegate = self
messageTextField.borderStyle = UITextBorderStyle.Line
messageTextField.becomeFirstResponder()
self.view.addSubview(messageTextField)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)
...
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
self.view.endEditing(true)
println("Touched")
}
func keyboardWillShow(notification: NSNotification) {
var keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey]as? NSValue)?.CGRectValue()
let messageFrame = messageTextField.frame
let newY = messageFrame.origin.y - keyboardSize!.height
messageTextField.frame = CGRectMake(messageFrame.origin.x, newY, messageFrame.size.width, messageFrame.size.height)
}
func keyboardWillHide(notification: NSNotification) {
var keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey]as? NSValue)?.CGRectValue()
let messageFrame = messageTextField.frame
let newY = messageFrame.origin.y - keyboardSize!.height
messageTextField.frame = CGRectMake(messageFrame.origin.x, newY, messageFrame.size.width, messageFrame.size.height)
}
}
Does anyone know why the keyboard isn't dismissing? I added the UITextField to the view programmatically as opposed to using storyboard. Does that make a difference?
class ViewController: UIViewController,UITextFieldDelegate {
confirm protocols
messageTextField.delegate=self
set delegate
func textFieldShouldReturn(textField: UITextField!) -> Bool
{
messageTextField.resignFirstResponder()
return true;
}
Use this code..
The following is how I did for that problem. I hope this method solve your problem.
textfield
#IBOutlet var userID : UITextField!
function.
func textFieldShouldReturn(textField: UITextField!)-> Bool
{ userID.resignFirstResponder( )
return true
}
In your desired function, you need to write this syntax.
#IBAction func login(sender: AnyObject)
{
userID.resignFirstResponder( )
}
This is in ViewDidLoad or ViewDidAppear
override func viewDidLoad( )
{
userID.delegate = self;
}
I cannot comment on the previous user. That's why I write this one.
I hope this gives you idea.
func textFieldShouldReturn(textField: UITextField) -> Bool {
self.view.endEditing(true)
//textField.resignFirstResponder()
return false
}
check delegate add into your viewDidLoad()
self.yourTextField.delegate = self;
how-to-dismiss-uitextfields-keyboard-in-your-swift-app
This might helps you :)
#vijeesh's answer will probably work, and the logic is almost correct, but it is technically wrong if you ever use more than one UITextField. textField is the UITextField parameter that is passed when textFieldShouldReturn is called. The problem is, you're just declaring:
textField.resignFirstResponder()
Your program doesn't know what UITextField you're referring to. Even though you may only have one textField in your program, and you know that it's your messageTextField, the program still doesn't know that. It just sees "textField". So you have have to tell it what to do for each UITextField in your program. Even if you have just one. This should work:
func textFieldShouldReturn(textField: UITextField) -> Bool {
if textField == messageTextField {
messageTextField.resignFirstResponder()
}
return true
}
very simple.
first you add Tap Gesture
var tap = UITapGestureRecognizer(target: self, action: "handle:")
view.addGestureRecognizer(tap)
in function handle
func handle(tap: UITapGestureRecognizer){
view.endEditing(true)
}
so you can dismiss keyboard when you click outside UITextField
Related
This has been asked a few times before: 1 2 3 4
These threads did not provide the solution I was looking for, and are getting a bit outdated with the release of Swift 5, so I've posted my solution below.
I recommend using IQKeyboardManagerSwift (or IQKeyboardManager written in ObjC) library that you can install with cocoapods, all tutorials included in link. For me it works better that custom solutions. Here are 2 versions of the library, ObjC and Swift :
Swift verion: https://cocoapods.org/pods/IQKeyboardManagerSwift
ObjC version: https://cocoapods.org/pods/IQKeyboardManager
This is my current solution:
import UIKit
// For UITextViews, exact same code, but using UITextViewDelegate
class viewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var textField: UITextField!
// Keeps track of our editing frame
// Kept it as a CGRect so that it can work with both UITextFields and UITextViews
var editingFrame: CGRect?
override func viewDidLoad() {
super.viewDidLoad()
// Set the delegate for the textField(s)
textField.delegate = self
// Add notification observers for keyboard
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillChangeFrame(notification:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
}
func textFieldDidBeginEditing(_ textField: UITextField) {
editingFrame = textField.frame
// This is the bit that is important, especially if you have
// your textfield inside another view (UIStackViews for example)
// The loop essentially goes through each successive superview the textfield has
// and redefines the centre in that superview's frame of reference
var currentView: UIView? = textField.superview
while currentView != nil {
editingFrame?.origin.x += currentView?.frame.origin.x ?? CGFloat(0.0)
editingFrame?.origin.y += currentView?.frame.origin.y ?? CGFloat(0.0)
currentView = currentView?.superview
}
}
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
editingFrame = nil
return true
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
view.endEditing(true)
return true
}
#objc func keyboardWillChangeFrame(notification: Notification) {
if let editingFrame = editingFrame {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect) {
let offset = editingFrame.maxY - keyboardSize.minY
if offset > self.view.frame.origin.y {
self.view.frame.origin.y -= offset
} else {
if self.view.frame.origin.y != 0 {
self.view.frame.origin.y = 0
}
}
}
} else {
if self.view.frame.origin.y != 0 {
self.view.frame.origin.y = 0
}
}
}
#objc func endEditingTextFields() {
view.endEditing(true)
}
}
I'm populating a vertical UIScrollView with many UITextField fields dynamically on runtime. The problem I have is that the keyboard will hide the fields that are in the area where it will appear, this may include the field I'm editing.
I tried KeyboardManagement solution from the apple documentation and also tried with notifications on the textFieldDidBeginEditing and textFieldDidEndEditing but the problem in both cases is that the keyboardWillShow notification comes first sometimes, and in that case it doesn't let me know which field is the one being edited.
I have this code in a class that implements the UITextFieldDelegate protocol, each object of this class holds a reference to one of those fields and works as it's delegate
func textFieldDidBeginEditing(_ textField: UITextField) {
self.activeTextfield = self.valueTextField
}
func textFieldDidEndEditing(_ textField: UITextField) {
self.activeTextfield = nil
}
The activeTextfield variable is a weak reference to the variable in the UIViewController where all of this happens. In that view controller I have the following code
class MyClass: UIViewController {
var activeTextfield: CustomTextField! // This is the variable I was talking about on the previous paragraph
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self)
}
#objc func keyboardWillShow(_ notification: Notification) {
if self.view.frame.origin.y == 0 {
guard let userInfo = notification.userInfo else { return }
guard let keyboardSize = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return }
let keyboardFrame = keyboardSize.cgRectValue
let textFieldFrame = activeTextfield!.frame // activeTextfield sometimes is nil because this notification happens before the previous code block
if textFieldFrame.origin.y + textFieldFrame.size.height > keyboardFrame.origin.y {
self.view.frame.origin.y -= keyboardFrame.height
}
}
}
#objc func keyboardWillHide(_ notification: Notification) {
if self.view.frame.origin.y != 0 {
guard let userInfo = notification.userInfo else { return }
guard let keyboardSize = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return }
let keyboardFrame = keyboardSize.cgRectValue
self.view.frame.origin.y += keyboardFrame.height
}
}
}
Is there any way I can force the UITextField delegate methods to be called before the keyboard notification?
Is this the correct way to handle this kind of situation?
If not, how should I handle it?
Thanks
As stated in your question:
the problem in both cases is that the keyboardWillShow notification
comes first sometimes, and in that case it doesn't let me know which
field is the one being edited
As per the sequence of events described in apple's documentation, textFieldShouldBeginEditing is the first delegate method called.
So, you can
implement textFieldShouldBeginEditing in the delegate to set your active text field, instead of textFieldDidBeginEditing (make sure you return true from textFieldShouldBeginEditing to allow editing)
use keyboardDidShowNotification instead of keyboardWillShowNotification.
This will ensure you have your UITextField marked before getting the keyboard frame / details.
You can do so fairly simply by doing the following. First add notification observers in your view will appear.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Keyboard notification
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
Then in your selector function you can have something like this
#objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue,
let currentTextField = view.getSelectedTextField() {
let keyboardHeight = keyboardSize.height
let textFieldFrame = currentTextField.superview?.convert(currentTextField.frame, to: nil)
}
}
}
And your getSelectedTextField() extension looks like this
// Inside UIView Extension
// Get currently active textfield
func getSelectedTextField() -> UITextField? {
let totalTextFields = getTextFieldsInView(view: self)
for textField in totalTextFields{
if textField.isFirstResponder{
return textField
}
}
return nil
}
func getTextFieldsInView(view: UIView) -> [UITextField] {
var totalTextFields = [UITextField]()
for subview in view.subviews as [UIView] {
if let textField = subview as? UITextField {
totalTextFields += [textField]
} else {
totalTextFields += getTextFieldsInView(view: subview)
}
}
return totalTextFields
}
}
You need to define tag property to your textFields and check in
textFieldDidBeginEditing and textFieldDidEndEditing what UITextField was called.
I am trying to move UITextFields when the Keyboard shows. Now I've seen videos and read articles on how to do it. I haven't seen one that uses the textfield itself, rather they use the bottom constraint of the textfield. Here is a video of what my code does, below is my code.
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var nameTF: UITextField!
#IBOutlet weak var emailTF: UITextField!
var selectedTextField: UITextField?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
createKeyboardNotification()
}
func createKeyboardNotification() {
NotificationCenter.default.addObserver(self, selector: #selector(respondToKeyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(respondToKeyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
#objc func respondToKeyboardWillShow(notification: Notification) {
adjustHeightForTextFields(isKeyboardHidden: false, notification: notification, textField: selectedTextField)
}
#objc func respondToKeyboardWillHide(notification: Notification) {
adjustHeightForTextFields(isKeyboardHidden: true, notification: notification, textField: selectedTextField)
}
func adjustHeightForTextFields(isKeyboardHidden: Bool, notification: Notification, textField: UITextField?) {
guard let userInfo = notification.userInfo else { return }
let keyboardFrameRect = userInfo[UIKeyboardFrameEndUserInfoKey] as! CGRect
if let textField = textField {
let textFieldYPosition = textField.frame.origin.y
if view.frame.maxY - textFieldYPosition > keyboardFrameRect.height {
UIView.animate(withDuration: 0.25) {
textField.frame.origin.y = (self.view.frame.maxY - textField.frame.size.height - keyboardFrameRect.height - 8)
}
}
else {
UIView.animate(withDuration: 0.25) {
let difference = textFieldYPosition - keyboardFrameRect.height
textField.frame.origin.y = difference + 16 + self.view.safeAreaInsets.bottom - 8
}
}
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
func textFieldDidBeginEditing(_ textField: UITextField) {
switch textField {
case nameTF:
print("NAME")
selectedTextField = nameTF
break
case emailTF:
print("EMAIL")
selectedTextField = emailTF
break
default:
break
}
}
}
If you have seen the video, I've come across some strange things. First when you tap on the textfield it works like its suppose to, but when you start typing the textfield just disappears. I didn't come across this when I was using the textfield bottom constraint. Now the second part is when the keyboard is already shown the textfield doesn't animate correctly, until you click it twice.
Now I am not using a scrollview, but would like to push the whole content or would I need to use a scrollview. If you take a look at this video, you can better understand what I mean by wanting to push the content.
Would really appreciate any help provided, Thanks. :)
You need to move the view up only when the textField on the bottom becomes active.
//Create a global variable to use as our keyboardHeight
var keyboardHeight: CGFloat = 0.0
override func viewDidLoad() {
super.viewDidLoad()
//Set the delegate only for the emailTF
emailTF.delegate = self
//Set up an observer. This will help us calculate keyboard height dynamically, depending on the iPhone the app runs on.
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
}
#objc private func keyboardWillShow(notification: NSNotification) {
if let keyboardRectValue = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
keyboardHeight = keyboardRectValue.height
}
}
Then move the view up and down when the textField becomes active/inactive.
func textFieldDidBeginEditing(_ textField: UITextField) {
print("MOVE VIEW UP")
if self.view.frame.origin.y == 0{
self.view.frame.origin.y -= keyboardHeight
}
}
func textFieldDidEndEditing(_ textField: UITextField) {
print("MOVE VIEW DOWN")
if self.view.frame.origin.y != 0{
self.view.frame.origin.y += keyboardHeight
}
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
print("MOVE VIEW DOWN")
if self.view.frame.origin.y != 0{
self.view.frame.origin.y += keyboardHeight
}
return true
}
This should definitely work. Good luck!
I agree that it's not clear always. We do this in our app and we used a scroll view. We embed the entire page in the scroll view. Then we move the bottom of the scroll view up. Scrollviews are easy to implement.
#objc func keyboardWillShow(notification: NSNotification) {
// Only deal with this if the window is active and visible.
if !self.isViewLoaded || self.view.window == nil {
return
}
if let userInfo = notification.userInfo {
let keyboardFrame = userInfo[UIKeyboardFrameEndUserInfoKey] as! CGRect
scrollView.frame = CGRect(x: view.frame.origin.x,y: view.frame.origin.y,width: view.frame.width, height: view.frame.height - keyboardFrame.height - 64)
}
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard)))
}
And when the keyboard disappears:
#objc func keyboardWillHide(notification: NSNotification) {
scrollView.frame = scrollViewOriginalFrame
}
I looked at and tried multiple solutions for Swift 3, Xcode 8 but couldn't get any to work. I've tried:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
and also setting a text field input as first responder:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
pressureInput.resignFirstResponder()
}
I don't know if something from Xcode 8 to Xcode 9 that cause these methods to not work, or if I messed elsewhere. I have 9 text fields and they've all set delegate to self. Their tags are incremented to move on to the next text field on pressing return. Don't think that would affect it. Sorry, new at this! The code runs fine with either of those attempted functions, but they keyboard stays. I would just like to dismiss keyboard when touched outside of any text field.
first of all write this extension in any swift file
extension UIViewController {
func hideKeyboardWhenTappedAround() {
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard))
view.addGestureRecognizer(tap)
}
func dismissKeyboard() {
view.endEditing(true)
}
}
Than in viewDidLoad of that View only call in any view controller there are textFields.
self.hideKeyboardWhenTappedAround()
Swift 4, 5. I always use hide keyboard when tapped around and return button.
override func viewDidLoad() {
super.viewDidLoad()
hideKeyboardWhenTappedAround()
emailTextField.delegate = self // your UITextfield
passwordTextField.delegate = self // your UITextfield
}
// Hide Keyboard
extension EmailAutorization: UITextFieldDelegate {
// Return button tapped
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
// Around tapped
func hideKeyboardWhenTappedAround() {
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(EmailAutorization.dismissKeyboard))
tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
}
#objc func dismissKeyboard() {
view.endEditing(true)
}
}
Here is Solution of Dismiss Keyboard and Move View Up on Keyboard Open : Swift 5
override func viewDidLoad() {
super.viewDidLoad()
let tap = UITapGestureRecognizer(target: self, action: #selector(taped))
view.addGestureRecognizer(tap)
NotificationCenter.default.addObserver(self, selector: #selector(KeyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(KeyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}
//This Method Will Hide The Keyboard
#objc func taped(){
self.view.endEditing(true)
}
#objc func KeyboardWillShow(sender: NSNotification){
let keyboardSize : CGSize = ((sender.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.size)!
if self.view.frame.origin.y == 0{
self.view.frame.origin.y -= keyboardSize.height
}
}
#objc func KeyboardWillHide(sender : NSNotification){
let keyboardSize : CGSize = ((sender.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size)!
if self.view.frame.origin.y != 0{
self.view.frame.origin.y += keyboardSize.height
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(true)
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
}
Did you tried to debug the program to see if the code stops in the function at all(with break point)? Usually this code should work...Check if those textFields are in the super view or in a child view and if they are maybe you should call self.childView.endEditing(true).
If you really work with multiple textFields maybe you should try IQKeyboardManager library. I use it in all my projects. You can find it here: https://github.com/hackiftekhar/IQKeyboardManager. Simple to use and with good support. Just install it trough cocoa pods, put IQKeyboardManager.sharedManager().enable = true in the AppDelegate and you're ready to go. :)
Are you sure that touchesBegan is being called? If you're sure, try adding self.resignFirstResponder() to your touchesBegan function. This tells your view controller that it's no longer the first responder and should dismiss the keyboard.
If not, what you'll want to do is create a UITapGestureRecognizer, add it to your view, and wire it to a function that calls self.resignFirstResponder().
I have a MainView that adds a subview (signUpWindow) when a sign up button is pressed.
In my signUpWindow subview (SignUpWindowView.swift), I set up each field with a function, as an example:
func confirmPasswordText()
{
confirmPasswordTextField.frame=CGRectMake(50, 210, 410, 50)
confirmPasswordTextField.placeholder=("Confirm Password")
confirmPasswordTextField.textColor=textFieldFontColor
confirmPasswordTextField.secureTextEntry=true
confirmPasswordTextField.returnKeyType = .Next
confirmPasswordTextField.clearButtonMode = .WhileEditing
confirmPasswordTextField.tag=5
self.addSubview(confirmPasswordTextField)
}
I have the keyboard moving the signUpWindow up and down when it appears and disappears in the MainView.
SignUpWindowView implements the UITextFieldDelegate
My problem is that I am trying to configure the Next/Done button on the keyboard and am not sure which view (MainView or SignUpWindowView) to add the textFieldShouldReturn function. I have tried both, but can't even get a println to fire to test to see if the function is even being executed. Once I get the textFieldShouldReturn to fire, I am confident I can execute the necessary code to get the Next/Done buttons to do what I want, and will post the final solution to include the Next/Done function.
UPDATED to include an abbreviated version of SignUpWindowView.swift
import UIKit
class SignUpWindowView: UIView,UITextFieldDelegate {
let firstNameTextField:UITextField=UITextField()
let lastNameTextField:UITextField=UITextField()
override func drawRect(rect: CGRect){
func firstNameText(){
firstNameTextField.delegate=self
firstNameTextField.frame=CGRectMake(50, 25, 200, 50)
firstNameTextField.placeholder="First Name"
firstNameTextField.returnKeyType = .Next
self.addSubview(firstNameTextField)
}
func lastNameText(){
lastNameTextField.delegate=self
lastNameTextField.frame=CGRectMake(260, 25, 200, 50)
lastNameTextField.placeholder="Last Name"
lastNameTextField.returnKeyType = .Done
self.addSubview(lastNameTextField)
}
func textFieldShouldReturn(textField: UITextField!) -> Bool{
println("next button should work")
if (textField === firstNameTextField)
{
firstNameTextField.resignFirstResponder()
lastNameTextField.becomeFirstResponder()
}
return true
}
firstNameText()
lastNameText()
}
You need to implement UITextFieldDelegate in your class and set that object as the delegate for the UITextField. Then implement the method textFieldShouldReturn: like this:
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
if textField == someTextField { // Switch focus to other text field
otherTextField.becomeFirstResponder()
}
return true
}
In your example you are missing this line:
confirmPasswordTextField.delegate = self
If you have implemented the delegate of course.
I was attempting to test my textfields in the SignUpWindowView.swift, which is where all of the textFields are created. But, since I place SignUpWindowView into my MainViewController as a subview, all of my UITextField "handling" needed to be done in the MainView and NOT its subview.
So here is my entire code (at the moment) for my MainViewController, which handles moving my SignUpWindowView up/down when the keyboard is shown/hidden and then moves from one field to the next. When the user is in the last text field (whose keyboard Next button is now set to Done in the subview) the keyboard tucks away and the user can then submit the form with a signup button.
MainViewController:
import UIKit
#objc protocol ViewControllerDelegate
{
func keyboardWillShowWithSize(size:CGSize, andDuration duration:NSTimeInterval)
func keyboardWillHideWithSize(size:CGSize,andDuration duration:NSTimeInterval)
}
class ViewController: UIViewController,UITextFieldDelegate
{
var keyboardDelegate:ViewControllerDelegate?
let signUpWindow=SignUpWindowView()
let signUpWindowPosition:CGPoint=CGPointMake(505, 285)
override func viewDidLoad()
{
super.viewDidLoad()
// Keyboard Notifications
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)
// set the textFieldDelegates
signUpWindow.firstNameTextField.delegate=self
signUpWindow.lastNameTextField.delegate=self
signUpWindow.userNameTextField.delegate=self
signUpWindow.passwordTextField.delegate=self
signUpWindow.confirmPasswordTextField.delegate=self
signUpWindow.emailTextField.delegate=self
}
func keyboardWillShow(notification: NSNotification)
{
var info:NSDictionary = notification.userInfo!
let keyboardFrame = info[UIKeyboardFrameEndUserInfoKey] as! NSValue
let keyboardSize = keyboardFrame.CGRectValue().size
var keyboardHeight:CGFloat = keyboardSize.height
let animationDurationValue = info[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber
var animationDuration : NSTimeInterval = animationDurationValue.doubleValue
self.keyboardDelegate?.keyboardWillShowWithSize(keyboardSize, andDuration: animationDuration)
// push up the signUpWindow
UIView.animateWithDuration(animationDuration, delay: 0.25, options: UIViewAnimationOptions.CurveEaseInOut, animations: {
self.signUpWindow.frame = CGRectMake(self.signUpWindowPosition.x, (self.signUpWindowPosition.y - keyboardHeight+140), self.signUpWindow.bounds.width, self.signUpWindow.bounds.height)
}, completion: nil)
}
func keyboardWillHide(notification: NSNotification)
{
var info:NSDictionary = notification.userInfo!
let keyboardFrame = info[UIKeyboardFrameEndUserInfoKey] as! NSValue
let keyboardSize = keyboardFrame.CGRectValue().size
var keyboardHeight:CGFloat = keyboardSize.height
let animationDurationValue = info[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber
var animationDuration : NSTimeInterval = animationDurationValue.doubleValue
self.keyboardDelegate?.keyboardWillHideWithSize(keyboardSize, andDuration: animationDuration)
// pull signUpWindow back to its original position
UIView.animateWithDuration(animationDuration, delay: 0.25, options: UIViewAnimationOptions.CurveEaseInOut, animations: {
self.signUpWindow.frame = CGRectMake(self.signUpWindowPosition.x, self.signUpWindowPosition.y, self.signUpWindow.bounds.width, self.signUpWindow.bounds.height)
}, completion: nil)
}
func textFieldShouldReturn(textField: UITextField) -> Bool
{
switch textField
{
case signUpWindow.firstNameTextField:
signUpWindow.lastNameTextField.becomeFirstResponder()
break
case signUpWindow.lastNameTextField:
signUpWindow.userNameTextField.becomeFirstResponder()
break
case signUpWindow.userNameTextField:
signUpWindow.passwordTextField.becomeFirstResponder()
break
case signUpWindow.passwordTextField:
signUpWindow.confirmPasswordTextField.becomeFirstResponder()
break
case signUpWindow.confirmPasswordTextField:
signUpWindow.emailTextField.becomeFirstResponder()
break
default:
textField.resignFirstResponder()
}
return true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillDisappear(animated: Bool) {
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
}
#IBAction func signup()
{
signUpWindow.frame=CGRectMake(signUpWindowPosition.x, signUpWindowPosition.y, 485,450)
signUpWindow.backgroundColor=UIColor.clearColor()
self.view.addSubview(signUpWindow)
}
}
Using tags makes it easier. Assign tags in ascending order to all the text fields you are using on your screen.
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
let textTag = textField.tag+1
if let nextResponder = textField.superview?.viewWithTag(textTag) as UIResponder
{
//textField.resignFirstResponder()
nextResponder.becomeFirstResponder()
}
else {
// stop editing on pressing the done button on the last text field.
self.view.endEditing(true)
}
return true
}
You connect the DidEndOnExit(I wrote this from memory so maybe its not called this exactly but similar) UIControl event using an #IBAction and in that func you use textF.resignFirstResponder() or .becomeFirstResponder()
EDIT
UITextField is subclass of UIControl and to programatically add a new event you use the addTarget() method. Ex:
func a(sender: AnyObject) {}
textField.addTarget(self, action: "a:", forControlEvents: .EditingDidEndOnExit)
UIControl docs