Text positioning in 2nd VC - ios

I have set the notifications to keep the text in textView above the keyboard. My problem is, when I select the table view cell to display my text in the next VC, that the text appears few lines below the top and only after I start editing (keyboard shows up) and than swipe to dismiss the keyboard, text repositions itself at the top, where it should be.How can I force the text to be at the top as soon as VC displays its content, before the keyboard appears? Thanks.
override func viewDidLoad() {
super.viewDidLoad()
let notificationCenter = NSNotificationCenter.defaultCenter()
notificationCenter.addObserver(self, selector: "adjustForKeyboard:", name: UIKeyboardWillHideNotification, object: nil)
notificationCenter.addObserver(self, selector: "adjustForKeyboard:", name: UIKeyboardWillChangeFrameNotification, object: nil)
storyTextView.text = passedText
title = passedTitle
navigationController?.navigationBar.tintColor = UIColor.redColor()
}
func adjustForKeyboard(notification: NSNotification) {
let userInfo = notification.userInfo!
let keyboardScreenEndFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue()
let keyboardViewEndFrame = view.convertRect(keyboardScreenEndFrame, fromView: view.window)
if notification.name == UIKeyboardWillHideNotification {
storyTextView.contentInset = UIEdgeInsetsZero
}else {
storyTextView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardViewEndFrame.height, right: 0)
}
storyTextView.scrollIndicatorInsets = storyTextView.contentInset
let selectedRange = storyTextView.selectedRange
storyTextView.scrollRangeToVisible(selectedRange)
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
storyTextView.contentInset = UIEdgeInsetsZero
}

Related

safeAreaInsets changes its value after keyboard dismissed in iOS 13

I have bottomView (the one with black border in the images) its bottom anchor has a constraint to bottom view safeAreaLayoutGuide, but when keyboard will show the bottomView became toolbar to the keyboard.
Here every thing was working as expected in iOS 14 (like image 1 and 3) but when running the project in iOS 13 I found that safeAreaInsets changes its value after the keyboard dismissed (red space increases its height like image 2)
I've tried some of the solutions that mentioned here but it didn't help
can anyone suggest a solution for this?
#objc func adjustForKeyboard(notification: Notification) {
guard let keyboardValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return }
let keyboardScreenEndFrame = keyboardValue.cgRectValue
let keyboardViewEndFrame = view.convert(keyboardScreenEndFrame, from: view.window)
if notification.name == UIResponder.keyboardWillHideNotification {
bottomViewConstraint?.constant = 0
NotesText.contentInset = .zero
} else {
bottomViewConstraint?.constant = -(keyboardViewEndFrame.height - self.view.safeAreaInsets.bottom)
NotesText.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: -(keyboardViewEndFrame.height + bottomViewConstraint!.constant), right: 0)
//FIXME:- force unwrap
}
NotesText.scrollIndicatorInsets = NotesText.contentInset
let selectedRange = NotesText.selectedRange
NotesText.scrollRangeToVisible(selectedRange)
}
and called this function in viewDidAppear also tried to called it at viewSafeAreaInsetsDidChange but the behavior didn't change
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
addKeyboardNotification()
// Show keyboard by default
NotesText.becomeFirstResponder()
}
Keyboard notification function:
fileprivate func addKeyboardNotification() {
let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(self, selector: #selector(adjustForKeyboard), name: UIResponder.keyboardWillHideNotification, object: nil)
notificationCenter.addObserver(self, selector: #selector(adjustForKeyboard), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
}

Make the textfiled swipe up when keyboard is used swift 5

I'm trying to make the text field txtAdd swipe up when the keyboard shows up, but I'm not really sure how to do it.
This is the code for adding items to the list:
#IBAction func submitBntFunc(_ sender: Any) {
if let text = txtAdd.text{
if text == ""{
return
}
txtAdd.text = ""
txtAdd.resignFirstResponder()
return txtField.text.append("\(text) \n")
}
}
I tried with the code below but it didn't really work.
guard let keyboardSize = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue else {return}
try with this code
var originButton : CGFloat?
override func viewDidLoad()
{
originButton = self.YOURBUTTON.frame.origin.y
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}
#objc func keyboardWillShow(notification: NSNotification) {
if let keyboard = ((notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue) {
if self.view.frame.origin.y == 0 {
self.YOURBUTTON.frame.origin.y -= keyboard.height
}
}
}
#objc func keyboardWillHide(notification: NSNotification) {
if self.YOURBUTTON.frame.origin.y != originButton {
self.YOURBUTTON.frame.origin.y = originButton!
}
}
add this Observer in your viewDidLoad methods:=
NotificationCenter.default.addObserver(self, selector: #selector(keyboard), name: UIResponder.keyboardWillHideNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboard), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
And it is call this function:=
#objc func keyboard(notification: Notification){
let userInfo = notification.userInfo!
let keyboardScreenEndFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
let keyboardViewEndFrame = view.convert(keyboardScreenEndFrame, to: view.window)
if notification.name == UIResponder.keyboardWillHideNotification{
//add your constrain here when keyboard is hiden
self.scrollView.contentInset = UIEdgeInsets.zero
}else{
//add your constrain here when keyboard is visible
self.scrollView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardViewEndFrame.height, right: 0)
}
scrollView.scrollIndicatorInsets = scrollView.contentInset
}

keyboardWillShow Notification not called immediately after becomeFirstResponder

I have implemented keyboardWillShow: and keyboardWillHide: notifications. I am registering the notifications and they work perfectly after directly touching the screen on the UITextField, but there's a problem. In my viewDidLoad right after registering the notifications I'm calling becomeFirstResponder. The keyboard pops up but the keyboardWillShow: is not getting called (as mentioned, only the first time. It seems like there's a delay from the time you call the function to register the notification and the time it is actually registered, and I shouldn't delay the execution of becomeFirstResponder). Any ideas?
#objc func keyboardWillShow(_ notification: NSNotification) {
print("Show")
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
var userInfo = notification.userInfo!
var keyboardFrame:CGRect = (userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
keyboardFrame = self.view.convert(keyboardFrame, from: nil)
var contentInset: UIEdgeInsets = self.tv_main.contentInset
contentInset.bottom = keyboardSize.height
self.tv_main.contentInset = contentInset
let indexpath = IndexPath(row: 0, section: 0)
self.tv_main.scrollToRow(at: indexpath, at: UITableViewScrollPosition.top, animated: true)
}
}
#objc func keyboardWillHide(_ notification: NSNotification) {
print("Hide")
if let _ = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
let contentInset:UIEdgeInsets = UIEdgeInsets.zero
self.tv_main.contentInset = contentInset
}
}
override func viewDidLoad() {
super.viewDidLoad()
tv_main.delegate = self
tv_main.dataSource = self
tf_search.delegate = self
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
self.tf_search.becomeFirstResponder()
if let placeholder = tf_search.placeholder {
tf_search.attributedPlaceholder = NSAttributedString(string:placeholder, attributes: [NSAttributedStringKey.foregroundColor: UIColor.white])
}
}
You should call becomeFirstResponder in viewWillAppear or viewDidAppear.

How to move bottom view to top of UIKeyboard

Hi I am trying to make a view's bottom align with the top of UIKeyboard.
Update 1: I have created a github project if you would like to give it a try: https://github.com/JCzz/KeyboardProject
Note: I need the aView to be dynamic.
Update 2: Just pushed - to include using frames
I might have been looking at this for too long, I can not wrap my brain around it :-)
Do you know how?
How do I know if the UIKeyboard is on the way down or up?
If UIKeyboard is up, then how to align it with the view(attachKeyboardToFrame - see code).
I have found the following UIView extension:
import UIKit
extension UIView {
func bindToKeyboard(){
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil)
}
func unbindFromKeyboard(){
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil)
}
#objc
func keyboardWillChange(notification: NSNotification) {
guard let userInfo = notification.userInfo else { return }
let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as! Double
let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as! UInt
let curFrame = (userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
let targetFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
// To get the total height of view
let topView = UIApplication.shared.windows.last
//
let attachKeyboardToFrame = Singleton.sharedInstance.attachKeyboardToFrame
let global_attachKeyboardToFrame = self.superview?.convert(attachKeyboardToFrame!, to: topView)
if (targetFrame.height + attachKeyboardToFrame!.height) > (topView?.frame.height)! {
self.frame.origin.y = -targetFrame.origin.y
}else{
}
}
}
You can achieve it using following Autolayout solution.
First you need UILayoutGuide that will be used simulate Keyboard aware bottom anchor, and a NSLayoutConstraint that will control this layout guide:
fileprivate let keyboardAwareBottomLayoutGuide: UILayoutGuide = UILayoutGuide()
fileprivate var keyboardTopAnchorConstraint: NSLayoutConstraint!
In the viewDidLoad add the keyboardAwareBottomLayoutGuide to the view and setup the appropriate contraints:
self.view.addLayoutGuide(self.keyboardAwareBottomLayoutGuide)
// this will control keyboardAwareBottomLayoutGuide.topAnchor to be so far from bottom of the bottom as is the height of the presented keyboard
self.keyboardTopAnchorConstraint = self.view.layoutMarginsGuide.bottomAnchor.constraint(equalTo: keyboardAwareBottomLayoutGuide.topAnchor, constant: 0)
self.keyboardTopAnchorConstraint.isActive = true
self.keyboardAwareBottomLayoutGuide.bottomAnchor.constraint(equalTo: view.layoutMarginsGuide.bottomAnchor).isActive = true
Then use following lines to start listening to keyboard showing and hiding:
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShowNotification(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHideNotification(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
And finally, use following methods to control the keyboardAwareBottomLayoutGuide to mimic the keyboard:
#objc fileprivate func keyboardWillShowNotification(notification: NSNotification) {
updateKeyboardAwareBottomLayoutGuide(with: notification, hiding: false)
}
#objc fileprivate func keyboardWillHideNotification(notification: NSNotification) {
updateKeyboardAwareBottomLayoutGuide(with: notification, hiding: true)
}
fileprivate func updateKeyboardAwareBottomLayoutGuide(with notification: NSNotification, hiding: Bool) {
let userInfo = notification.userInfo
let animationDuration = (userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue
let keyboardEndFrame = (userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
let rawAnimationCurve = (userInfo?[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber)?.uint32Value
guard let animDuration = animationDuration,
let keybrdEndFrame = keyboardEndFrame,
let rawAnimCurve = rawAnimationCurve else {
return
}
let convertedKeyboardEndFrame = view.convert(keybrdEndFrame, from: view.window)
let rawAnimCurveAdjusted = UInt(rawAnimCurve << 16)
let animationCurve = UIViewAnimationOptions(rawValue: rawAnimCurveAdjusted)
// this will move the topAnchor of the keyboardAwareBottomLayoutGuide to height of the keyboard
self.keyboardTopAnchorConstraint.constant = hiding ? 0 : convertedKeyboardEndFrame.size.height
self.view.setNeedsLayout()
UIView.animate(withDuration: animDuration, delay: 0.0, options: [.beginFromCurrentState, animationCurve], animations: {
self.view.layoutIfNeeded()
}, completion: { success in
//
})
}
Now with all this set up, you can use Autolayout to constraint your views to keyboardAwareBottomLayoutGuide.topAnchor instead of self.view.layoutMarginsGuide.bottomAnchor (or self.view.bottomAnchor, whichever you use). keyboardAwareBottomLayoutGuide will automatically adjust to the keyboard showed or hidden.
Example:
uiTextField.bottomAnchor.constraint(equalTo: keyboardAwareBottomLayoutGuide.topAnchor).isActive = true
EDIT: Directly setting frames
While I strongly recommend using Autolayout, in cases when you cannot go with this, directly setting frames can be also a solution. You can use the same principle. In this approach you don't need layout guide, so you don't need any additional instance properties. Just use viewDidLoad to register for listening notifications:
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShowNotification(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHideNotification(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
Then implement methods that will react to these notifications:
#objc fileprivate func keyboardWillShowNotification(notification: NSNotification) {
adjustToKeyboard(with: notification, hiding: false)
}
#objc fileprivate func keyboardWillHideNotification(notification: NSNotification) {
adjustToKeyboard(with: notification, hiding: true)
}
fileprivate func adjustToKeyboard(with notification: NSNotification, hiding: Bool) {
let userInfo = notification.userInfo
let animationDuration = (userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue
let keyboardEndFrame = (userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
let rawAnimationCurve = (userInfo?[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber)?.uint32Value
guard let animDuration = animationDuration,
let keybrdEndFrame = keyboardEndFrame,
let rawAnimCurve = rawAnimationCurve else {
return
}
let convertedKeyboardEndFrame = view.convert(keybrdEndFrame, from: view.window)
let rawAnimCurveAdjusted = UInt(rawAnimCurve << 16)
let animationCurve = UIViewAnimationOptions(rawValue: rawAnimCurveAdjusted)
// we will go either up or down depending on whether the keyboard is being hidden or shown
let diffInHeight = hiding ? convertedKeyboardEndFrame.size.height : -convertedKeyboardEndFrame.size.height
UIView.animate(withDuration: animDuration, delay: 0.0, options: [.beginFromCurrentState, animationCurve], animations: {
// this will move the frame of the aView according to the diffInHeight calculated above
// of course here you need to set all the frames that would be affected by the keyboard (this is why I prefer using autolayout)
self.aView?.frame = (self.aView?.frame.offsetBy(dx: 0, dy: diff))!
// of course, you can do anything more complex than just moving the aView up..
})
}
In both cases, don't forget to unregister observing the notifications once the viewController is deinitialized to prevent retain cycles:
deinit {
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}

Move up textfield above the keyboard

I tryed to use something to move up the view because when I go at the end of my form and I tap on the last textfield I can't see what I write in because the keyboard appears over the text field, so I found something but here if I tap on a textfield on the top of the view this one gonna gonna be hide by going upper, that's the code:
override func viewDidLoad() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil)
}
func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
self.view.frame.origin.y -= keyboardSize.height
}
}
func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
self.view.frame.origin.y += keyboardSize.height
}
}
But here there is an another problem, when I tap two times one an another textfield, a black bloc appears.
So what I wan't to do is detect the textfield and put the keyboard under it so move up the textfield. And detect if the keyboard is already here do don't show a black bloc. But I haven't found solution about.
I have used this code in my project :
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(true)
// Register Keyboard Notification
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
// Remove Keyboard notification observer
NSNotificationCenter.defaultCenter().removeObserver(self)
}
func keyboardWillShow(notification: NSNotification)
{
var userInfo = notification.userInfo!
var keyboardFrame:CGRect = (userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue).CGRectValue()
keyboardFrame = self.view.convertRect(keyboardFrame, fromView: nil)
var contentInset:UIEdgeInsets = self.scrollView.contentInset
contentInset.bottom = keyboardFrame.size.height - 30 //Set this value (30) according to your code as i have navigation tool bar for next and prev.
self.scrollView.contentInset = contentInset
}
func keyboardWillHide(notification: NSNotification) {
let contentInset:UIEdgeInsets = UIEdgeInsetsZero
self.scrollView.contentInset = contentInset
}
Hope It will help you!!
Add a bool property self.isKeyBoardUp
In keyboardWillShow:
If isKeyBoardUp return, else set it to true and do your stuff.
In keyboardWillHide:
If not isKeyBoardUp return, else set it to false and do your stuff.
Please check this code i am try it and works for get this one from
Move textfield when keyboard appears swift
func keyboardWasShown(notification: NSNotification) {
var info = notification.userInfo!
var keyboardFrame: CGRect = (info[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue()
UIView.animateWithDuration(0.1, animations: { () -> Void in
self.bottomConstraint.constant = keyboardFrame.size.height + 20
})
}

Resources