calculating keyboard height without using NSNotification in swift - swift

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) {
}

Related

Move textfield up when it is not visible

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

Text view up when keyboard appears swift

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

iOS keyboard hides a UITextField

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
}
}

Swift Unexpectedly found nil while unwrapping an optional value while trying to move up the layout

I need to move up the layout when the keyboard appears and the textfield won't be shown because of the size of the keyboard. Therefore I created this:
var activeField: UITextField!
in my ViewDidLoad:
let center: NotificationCenter = NotificationCenter.default;
center.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
center.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
and here are the methods:
func textFieldDidBeginEditing(_ textField: UITextField) {
activeField = textField
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
#objc func keyboardWillShow(notification: Notification) {
let info: NSDictionary = notification.userInfo as! NSDictionary
let keyboardSize = (info[UIResponder.keyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
let keyboardY = self.view.frame.size.height - keyboardSize.height
let editingTextFieldY: CGFloat = self.activeField.frame.origin.y
if editingTextFieldY > keyboardY - 60 {
UIView.animate(withDuration: 0.25) {
self.view.frame = CGRect(x: 0, y: self.view.frame.origin.y - (editingTextFieldY - (keyboardY-60)), width: self.view.bounds.width, height: self.view.bounds.height)
}
}
}
#objc func keyboardWillHide(notification: Notification) {
UIView.animate(withDuration: 0.25, animations: {
self.view.frame = CGRect(x:0, y:0, width: self.view.bounds.width, height: self.view.bounds.height)
}, completion: nil)
}
the error appears at this line:
let editingTextFieldY: CGFloat = self.activeField.frame.origin.y
This textFieldDidBeginEditing isn't being called.
You need to set the delegate of the origin textfield in viewDidLoad
self.mainTexF.delegate = self

Move button when keyboard appears swift

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
}
}