I want to move textfield up when keyword covers the textfield. Now I am facing a problem with the moving textfield up: it moves up but every time when I click one of the textfields.
How to move the textfield up only when it is covered by keyword?
Also, I have scrolling when the textfield tapped, but it does not work correctly
Here is my code:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
self.hideKeyboardWhenTappedAround()
}
#objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
if view.frame.origin.y == 0 {
self.view.frame.origin.y -= keyboardSize.height
}
}
guard let userInfo = notification.userInfo else { return }
var keyboardFrame:CGRect = (userInfo[UIResponder.keyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
keyboardFrame = self.view.convert(keyboardFrame, from: nil)
var contentInset:UIEdgeInsets = self.scrollView.contentInset
contentInset.bottom = keyboardFrame.size.height + 20
scrollView.contentInset = contentInset
}
#objc func keyboardWillHide(notification: NSNotification) {
let contentInset:UIEdgeInsets = UIEdgeInsets.zero
scrollView.contentInset = contentInset
if self.view.frame.origin.y != 0 {
self.view.frame.origin.y = 0
}
}
Simply use this cocoapods to manage all text fields
pod 'IQKeyboardManagerSwift'
Install pods in your project
Add the below line in your AppDelegate file under the didFinishLaunchingWithOptions method
IQKeyboardManager.shared.enable = true
Here is a reference link -- IQKeyboardManagerSwift
Solutions.
First way you can listen keyboardWillChangeFrameNotification
Second way you can hide keywords textField.autocorrectionType = .no
Related
I have textField and textView in the table. When editing textFiled, this code works and all text fields rise above the keyboard. When I edit a textView, nothing happens. It will help to edit the code so that for textView this code also works. Please do not offer third-party libraries. Thanks
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)
}
override func viewDidLoad() {
super.viewDidLoad()
}
#objc
fileprivate func keyboardWillShow(_ notification: Notification) {
let keyboardFrame = ((notification as NSNotification).userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue ?? CGRect.zero
let contentInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: keyboardFrame.height, right: 0.0)
self.tableView.contentInset = contentInsets
self.tableView.scrollIndicatorInsets = contentInsets
UIView.animate(withDuration: 0.25) {
self.tableView.layoutIfNeeded()
self.view.layoutIfNeeded()
}
}
#objc
fileprivate func keyboardWillHide(_ notification: Notification) {
tableView.contentInset = .zero
}
yes you can!
all you need to do is knowing where you textfield position,
then set your scroll Offset
write this :
NotificationCenter.default.addObserver(self, selector: #selector(yourMethod(_:)), name: UITextField.textDidBeginEditingNotification, object: nil)
and your function
#objc func yourMethod(_ sender: NSNotification) {
if let tfActive = sender.object as? UITextField {
let frameRelatedToSuper = tfActive.convert(yourScrollView.contentOffset, to: nil)
//[mockTF convertPoint:self.parentScrollView.contentOffset toView:nil];
yourScrollView.setContentOffset(frameRelatedToSuper, animated: true)
}
}
the rest is your logic.
good luck
note: without adding additional height it might stopped on the top of your textfield
you can declare this
var padding: CGFloat = 10
padding = yourTF.bounds.height + padding
frameRelatedToSuper += padding
edit : the rest is your logic what i meant was ,because you need to calculate your keyboard height and add to framerelatedtosuper
When I press on a UITextField that is on the lower part of the screen, it is hidden by the keyboard.
What I wanted to do is moving up the view, with the standard iOS animation, reaching the UITextField that in which I am inserting some text.
I am developing the app in Swift 5 (Xcode 10.2)
The result that I have reached is that now I can move the view (a little earlier than desired) but the view moves every time I press on a UITextField, not only the one that will be hided by the keyboard.
class ViewController: UIViewController {
deinit {
NotificationCenter.default.removeObserver(self)
}
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
#objc func keyboardWillShow(notification: NSNotification) {
guard let userInfo = notification.userInfo else {
return
}
guard let keyboardSize = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else {
return
}
let keyboardFrame = keyboardSize.cgRectValue
if self.view.frame.origin.y == 0 {
self.view.frame.origin.y -= keyboardFrame.height
}
}
#objc func keyboardWillHide(notification: NSNotification) {
guard let userInfo = notification.userInfo else {
return
}
guard let keyboardSize = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else {
return
}
let keyboardFrame = keyboardSize.cgRectValue
if self.view.frame.origin.y != 0 {
self.view.frame.origin.y += keyboardFrame.height
}
}
}
The result that I want to obtain is that if the user presses on a UITextField that will be hided by the keyboard, then, a little bit after the keyboard appeared, the view is moved up until the user can see the UITextField that has pressed.
I've searched a long for a solution to this problem but all others that I've seen seems outdated or not doing what I'm trying to achieve.
you can try by taking scrollview :
import UIKit
class ViewController: UIViewController {
#IBOutlet var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
NotificationCenter.default.addObserver(self,selector:#selector(self.keyboardWillShow),name:UIResponder.keyboardDidShowNotification, object: nil)
NotificationCenter.default.addObserver(self,selector: #selector(self.keyboardWillHide),name:UIResponder.keyboardDidHideNotification, object: nil)
}
#objc func keyboardWillShow(notification: Notification) {
guard let userInfo = notification.userInfo,
let frame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
else{
return
}
let contentInset = UIEdgeInsets(top: 0, left: 0, bottom: frame.height, right: 0)
scrollView.contentInset = contentInset
}
#objc func keyboardWillHide(notification: Notification)
{
scrollView.contentInset = UIEdgeInsets.zero
}
}
I have a very small question - can we calculate the Keyboard Height with out using Notification. All the answers in stake overflow is using NSNotification but is there simpler way of calculating it?
below is the code:
NotificationCenter.default.addObserver( self, selector: #selector(keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil
#objc func keyboardWillShow(notification: ) {
if let userInfo = notification.userInfo {
if let keyboardSize = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
let kbHeight = keyboardSize.height
}
}
}
Code to use keyboard height in textFieldDidBeginEditing:
var kbHeight: CGFloat?
#objc func keyboardWillShow(notification: NSNotification) {
if let userInfo = notification.userInfo {
if let keyboardSize = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
kbHeight = keyboardSize.height
}
}
}
func textFieldDidBeginEditing(_ textField: UITextField) {
if textField.frame.maxY > self.kbHeight!
{
self.scrollView.setContentOffset(CGPoint.init(x: 0, y: textField.frame.maxY - (self.kbHeight! + 2.0)), animated: true)
}
else{
return
}
print(textField.frame.maxY)
print(self.view.frame.height * 0.6)
print(textField.frame.maxY - self.view.frame.height * 0.6)
}
func textFieldDidEndEditing(_ textField: UITextField)
{
self.scrollView.setContentOffset(CGPoint.init(x: 0, y: 0), animated: true)
self.view.endEditing(true);
}
actually i don't have any idea for getting keyboard hight directly.. but you can save the keyboard height in variable when keyboard is present and use them where you want
Use these two Observers for keyboard and manage the keyboard hight
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
Must be remove these observer at dinit method when pop or dismiss the view controller.
deinit {
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
Selector methods for keyboard notification ...
#objc func keyboardWillShow(notification: NSNotification) {
var keyBoardHeight: CGFloat = 0
if let keyboardFrame: NSValue = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue {
let keyboardRectangle = keyboardFrame.cgRectValue
keyBoardHeight = keyboardRectangle.height
}
}
#objc func keyboardWillHide(notification: NSNotification) {
}
I have recently started to develop my own app following the instructions on internet. I am just a beginner (with no knowledge of coding) and hence may be doing very stupid mistake that I am not able to catch.
In my app I am facing a situation where my email text field is hiding behind the keyboard whenever I try to type email address. I did some research (on stack overflow) and wrote a piece of code that suppose to move my text field up but it is not ... I believe overall structure of code is right (I may be wrong here though) but it may be just tiny mistake that making my code ineffective.
can anyone guide me on what I am doing wrong here?
below is the piece of code I wrote:
{
import UIKit
import WebKit
import CoreGraphics
import AVFoundation
import QuartzCore
import Foundation
class StudentSignUpViewController: UIViewController,UIScrollViewDelegate, UITextFieldDelegate {
#IBOutlet weak var yourEmail: UITextField!
#IBOutlet weak var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
//setting portrait
AppUtility.lockOrientation(.portrait)
//hide keyboard when click outside
self.hideKeyboardWhenTappedAround()
//hide keyboard when click on return
self.yourEmail.delegate = self
self.scrollView.delegate = self
//boarder line for yourEmail
yourEmail.frame.size.height = UIScreen.main.fixedCoordinateSpace.bounds.size.width * CGFloat(0.05)
yourEmail.font = UIFont.italicSystemFont(ofSize: UIScreen.main.fixedCoordinateSpace.bounds.size.width * CGFloat(0.04))
bottomBoader(BottomLine: "UrEmailTextBottomLine", length: 1.0, yourTextBox: yourEmail)
yourEmail.applyCustomClearButton(yourTextBox: yourEmail)
registerForKeyboardNotifications()
deregisterFromKeyboardNotifications()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
AppUtility.lockOrientation(.portrait)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
AppUtility.lockOrientation(.all)
}
// *************************************************** moving textfiles when keyborad present ***********************************************************
func registerForKeyboardNotifications(){
//Adding notifies on keyboard appearing
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
func deregisterFromKeyboardNotifications(){
//Removing notifies on keyboard appearing
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
#objc func keyboardWasShown(notification: NSNotification){
//Need to calculate keyboard exact size due to Apple suggestions
self.scrollView.isScrollEnabled = true
var info = notification.userInfo!
let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
let contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize!.height, 0.0)
self.scrollView.contentInset = contentInsets
self.scrollView.scrollIndicatorInsets = contentInsets
var aRect : CGRect = self.view.frame
aRect.size.height -= keyboardSize!.height
if let activeField = self.yourEmail {
if (!aRect.contains(activeField.frame.origin)){
self.scrollView.scrollRectToVisible(activeField.frame, animated: true)
}
}
}
#objc func keyboardWillBeHidden(notification: NSNotification){
//Once keyboard disappears, restore original positions
var info = notification.userInfo!
let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
let contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, -keyboardSize!.height, 0.0)
self.scrollView.contentInset = contentInsets
self.scrollView.scrollIndicatorInsets = contentInsets
self.view.endEditing(true)
self.scrollView.isScrollEnabled = false
//self.scrollView.contentInset = UIEdgeInsets.zero
}
func textFieldDidBeginEditing( textField: UITextField){
yourEmail = textField
}
func textFieldDidEndEditing(textField: UITextField){
yourEmail = nil
}
The problem is you are registerForKeyboardNotifications() and then immediately deregisterFromKeyboardNotifications() so you aren't getting keyboard notifications. You should move the deregister to the deinit:
deinit {
deregisterFromKeyboardNotifications()
}
Edit
As #matt pointed out you don't need to deregisterFromKeyboardNotifications so just delete that code (including my suggestion of deinit)
Embedding your controls in a UITableView with static cells on a Storyboard will let the system take care of the scrolling for you.
hey bro why are call both the functions in viewDidLoad
registerForKeyboardNotifications()
deregisterFromKeyboardNotifications()
In viewDidLoad call only registerForKeyboardNotifications() and in deinit call deregisterFromKeyboardNotifications()
final solution that is working fine, I have copied it from stack overflow and tweak it little bit for my purpose:
var activeField: UITextField?
func registerForKeyboardNotifications(){
//Adding notifies on keyboard appearing
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
#objc func keyboardWasShown(notification: NSNotification){
//Need to calculate keyboard exact size due to Apple suggestions
self.scrollView.isScrollEnabled = true
var info = notification.userInfo!
let keyboardSize = (info[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.size
let contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize!.height, 0.0)
self.scrollView.contentInset = contentInsets
self.scrollView.scrollIndicatorInsets = contentInsets
var aRect : CGRect = self.view.frame
aRect.size.height -= keyboardSize!.height
if let activeField = self.activeField {
if activeField.frame.maxY > (scrollView.frame.height - keyboardSize!.height){
self.scrollView.setContentOffset(CGPoint.init(x: 0, y: activeField.frame.maxY - (scrollView.frame.height - keyboardSize!.height) + 20), animated: true)
} else {
return
}
print(activeField.frame.maxY)
print(scrollView.frame.height)
print(keyboardSize!.height)
print(scrollView.frame.height - keyboardSize!.height)
print(activeField.frame.maxY - (scrollView.frame.height - keyboardSize!.height) + 20)
}
}
#objc func keyboardWillBeHidden(notification: NSNotification){
//Once keyboard disappears, restore original positions
var info = notification.userInfo!
let keyboardSize = (info[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.size
let contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, -keyboardSize!.height, 0.0)
self.scrollView.contentInset = contentInsets
self.scrollView.scrollIndicatorInsets = contentInsets
self.view.endEditing(true)
self.scrollView.isScrollEnabled = false
}
func textFieldDidBeginEditing(_ textField: UITextField){
activeField = textField
}
func textFieldDidEndEditing(_ textField: UITextField){
activeField = nil
}
In a UIViewController I have several text fields and a button is on the bottom of the UIViewController.
For the button, I have set a bottom constraint with a constant of 0.
Then I made an outlet from the bottom constraint to the UIViewController.
When I run my code, the button does not move upwards. I have seen suggestions on stackoverflow that I should add UIScrollView, but that means, I would have to delete all the objects on the UIViewController, put the UIScrollView and then put my objects on the UIVIewController again.
#IBOutlet weak var bottomConstraint: NSLayoutConstraint!
// When tapping outside of the keyboard, close the keyboard down
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.view.endEditing(true)
}
// Stop Editing on Return Key Tap. textField parameter refers to any textfield within the view
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
// When keyboard is about to show assign the height of the keyboard to bottomConstraint.constant of our button so that it will move up
func keyboardWillShow(notification: NSNotification) {
if let userInfo = notification.userInfo {
if let keyboardSize: CGRect = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
bottomConstraint.constant = keyboardSize.size.height
view.setNeedsLayout()
}
}
}
// When keyboard is hidden, move the button to the bottom of the view
func keyboardWillHide(notification: NSNotification) {
bottomConstraint.constant = 0.0
view.setNeedsLayout()
}
The typical way to address this would be to move the keyboard with code like this:
in ViewController class:
func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
if view.frame.origin.y == 0{
let height = keyboardSize.height
self.view.frame.origin.y += height
}
}
}
func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
if view.frame.origin.y != 0 {
let height = keyboardSize.height
self.view.frame.origin.y -= height
}
}
}
in ViewDidLoad method:
NotificationCenter.default.addObserver(self, selector: Selector("keyboardWillShow:"), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: Selector("keyboardWillHide:"), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
Please Read This:
The way you are trying to solve your problem is not allowed. In the code above, if you change view to your button variable name, the button will shoot up and then fall back down. This is because Auto Layout and Programmatic layout do not work together, it is one or the other. The way you fix this is by programmatically creating that button (with CGRect), then using the code above to move only that button on keyboard press. (Do that by changing view to your button variable name.
func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if view.frame.origin.y == 0{
let height = keyboardSize.height
self.yourBtn.frame.origin.y += height
}
}
}
func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if view.frame.origin.y != 0 {
let height = keyboardSize.height
self.yourBtn.frame.origin.y -= height
}
}
}
To programmatically create the button you would use code similar to this:
myButton.frame = CGRect(...)
Complimentary to Ryan's answer above, this can be done all with auto-layout and no need for frames and CGRect.
Swift 5
In your view, constrain your button as you normally would but add a reference to the constraint for modification when the keyboard hides/shows:
var bottomButtonConstraint = NSLayoutConstraint()
bottomButtonConstraint = yourButton.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor, constant: -12)
bottomButtonConstraint.isActive = true
In your ViewController's viewDidLoad():
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
Also in your ViewController:
#objc private func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
self.yourCustomView.bottomButtonConstraint.constant -= keyboardSize.height
}
}
#objc private func keyboardWillHide(notification: NSNotification) {
self.yourCustomView.bottomButtonConstraint.constant = -12
}
You need add(viewDidLoad) observers to call your functions:
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(keyboardWillShow), name: UIKeyboardDidShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(keyboardWillHide), name: UIKeyboardDidHideNotification, object: nil)
Consider using this pod: https://cocoapods.org/pods/IQKeyboardManager
In AppDelegate.swift, just import IQKeyboardManagerSwift framework and enable IQKeyboardManager.
import IQKeyboardManagerSwift
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
IQKeyboardManager.shared.enable = true
return true
}
}