I wasn't able to find a solution here for my problem which seems to be just that little step above the regular "move up view when keyboard appears" thing.
Although this is exactly what I need I want this only to happen on an iPhone 5S or iPhone SE.
So I've got the following code so far which is working fine with iOS 11:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange(notification:)), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
#objc func keyboardWillHide() {
self.view.frame.origin.y = 0
}
#objc func keyboardWillChange(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
if myTextField.isFirstResponder {
self.view.frame.origin.y = -keyboardSize.height
}
}
}
I've tried several things to put this into an if case and I've searched for how to define things only for types of devices but as a beginner (6th week learning...) I've totally failed so far.
After #rmaddy gave me the right hint I'm giving the answer myself. All I did was adding an if case checking the view size with view.bounds.height (which is 568pt for an iPhone 5).
So the above code was changed to:
override func viewDidLoad() {
super.viewDidLoad()
let screenHeight = view!.bounds.height
//Checking the view size in pt here
if screenHeight <= 568 {
//add this to perform only for devices with view size 568 or lower
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange(notification:)), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
}
#objc func keyboardWillHide() {
self.view.frame.origin.y = 0
}
#objc func keyboardWillChange(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
if myTextField.isFirstResponder {
self.view.frame.origin.y = -keyboardSize.height
}
}
}
Related
so I have a small app where I choose an image, get it into an image view
and I have 2 textfield to insert a funny phrase
(Meme editor app)
my problem is since the bottom textfield is covered when the keyboard is shown I had to shift the view upwards every time the keyboard is shown for the bottom texfield and I succeed in doing that, what goes wrong is that every time I re-tap the beginning or the end of an existing text in the text filed the view shifts up again in undesirable behavior
here is a small GIF that shows what happens exactly
here is my code so far:
Function to get Kyboard height:
func getKeyboardHeight(_ notification:Notification) -> CGFloat {
let userInfo = notification.userInfo
let keyboardSize = userInfo![UIResponder.keyboardFrameEndUserInfoKey] as! NSValue // of CGRect
return keyboardSize.cgRectValue.height
}
Function to shift the view up in the condition that bottom textfield is what the user taps
#objc func keyboardWillShow(_ notification:Notification) {
if bottomTextField.isFirstResponder{
view.frame.origin.y -= getKeyboardHeight(notification)
}
}
Function to return the view to its normal position when the user finishes editing the bottom text field
#objc func keyboardWillHide(_ notification:Notification) {
view.frame.origin.y = 0
}
Functions to add and remove observers of keyboard notifications
func subscribeToKeyboardNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
}
func subscribekeyboardWillHide() {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
func unsubscribeFromKeyboardNotifications() {
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
}
func unsubscribekeyboardWillHide() {
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
}
and where I call them
override func viewWillAppear(_ animated: Bool) {
super .viewWillAppear(true)
cameraButton.isEnabled = UIImagePickerController.isSourceTypeAvailable(.camera)
subscribeToKeyboardNotifications()
subscribekeyboardWillHide()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
unsubscribeFromKeyboardNotifications()
unsubscribekeyboardWillHide()
}
if you could be kind to provide a simple explanation for your solution I would appreciate it
This is what I do while managing keyboard. It causes no problems.
Declare in your UIViewController class
private let notificationCenter = NotificationCenter.default
then in
override func viewDidLoad() {
super.viewDidLoad()
notificationCenter.addObserver(self, selector: #selector(adjustForKeyboard), name: UIResponder.keyboardWillHideNotification, object: nil)
notificationCenter.addObserver(self, selector: #selector(adjustForKeyboard), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
}
This is the adjust for keyboard function
#objc private func adjustForKeyboard(notification: Notification) {
guard let userInfo = notification.userInfo else { return }
guard let keyboardScreenEndFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else { return }
let keyboardViewEndFrame = view.convert(keyboardScreenEndFrame, from: view.window)
if notification.name == UIResponder.keyboardWillHideNotification {
scrollView.contentInset = UIEdgeInsets.zero
} else {
scrollView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardViewEndFrame.height, right: 0)
}
scrollView.scrollIndicatorInsets = scrollView.contentInset
}
Deinit here -
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(true)
notificationCenter.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
notificationCenter.removeObserver(self, name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
}
Every time you change the cursor location, UIResponder.keyboardWillShowNotification notification triggered, thats why every time you tap the textfield it moves up one keyboard height more.
You can use UIResponder.keyboardDidShowNotification notification instead of UIResponder.keyboardWillShowNotification. This one is not triggered when cursor location changes.
I am trying to build an input screen for the iPhone in swift. The screen has a number of input fields. Most of them on the top of the screen, but three fields are at the bottom. When the user tries to edit the text on the bottom of the screen, the keyboard will pop up and it will cover the screen. I found a simple solution to move the screen up when this happens, but the result is that the screen always moves up and the fields on top of the screen move out of reach when the user tries to edit those.
for example : I want form txt1 to txt4 the view does not go up.
Is there a way to have the screen only move when the bottom fields are edited?
I have used this code I found here:
override func viewDidLoad() {
txt1.delegate = self
txt2.delegate = self
txt3.delegate = self
txt4.delegate = self
txt5.delegate = self
txt6.delegate = self
txt7.delegate = self
txt8.delegate = self
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)
}
func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if view.frame.origin.y == 0 {
self.view.frame.origin.y -= keyboardSize.height
}
}
}
#objc func keyboardWillHide(notification: NSNotification) {
if view.frame.origin.y != 0 {
self.view.frame.origin.y = 0
}
}
**
I did this function to start show keyboard while I start editing on textfields:
public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool{
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}
but here it's going for all the textfield that I have and its the same problem.
how can I make it for specific textfield?
This is my view.
When I click inside the text view the keyboard was coming on top. so I added made a class and in that class, I added these functions.
var objectObserver:UIViewController?
func setKeyboardResponsiviness(observer:UIViewController){
objectObserver = observer
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}
#objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if objectObserver!.view.frame.origin.y == 0 {
objectObserver!.view.frame.origin.y -= keyboardSize.height
}
}
}
#objc func keyboardWillHide(notification: NSNotification) {
if objectObserver!.view.frame.origin.y != 0 {
objectObserver!.view.frame.origin.y = 0
}
}
After adding the code the whole screen slides up which was the intended goal but as a side effect, half of the text view is out of the screen. Any idea how I can fix this?
The simple solution is to use IQKeyboardManagerSwift.
pod 'IQKeyboardManagerSwift' // add this in your pod file.
Add the following code in didFinishLaunchingWithOptions.
IQKeyboardManager.shared.enable = true
I hope this helps.
In my app, I wanted a notification for UIResponder.keyboardWillShowNotification in order to update the y position of my text field. It was working prior to iOS 12; now, it is not called in one of my view controllers (it works for other ones).
Here is my code to do this:
#objc func keyboardWillShow(_ notification: Notification) {
print("keyboard will show 2")
guard let frameValue: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else {
return
}
let keyboardFrame = frameValue.cgRectValue
UIView.animate(withDuration: animationTime) {
self.addViewBottomConstraint.constant = keyboardFrame.size.height
self.view.layoutIfNeeded()
print("Bottom contraint height = \(self.addViewBottomConstraint.constant)")
}
}
#objc func keyboardWillHide(_ notification: Notification) {
UIView.animate(withDuration: animationTime) {
self.addViewBottomConstraint.constant = 0
self.view.layoutIfNeeded()
}
}
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)
}
Here, "keyboard will show 2" is not printed, but it is printed for other view controllers with the same notifications. Is there anything new in iOS 12 that caused this? Otherwise, is there a particular reason why it is not being called?
This can be related to simulator setup, see menu "Hardware > Keyboard > Connect Keyboard Hardware". If this option is ON, you will get UIKeyboardWillHideNotification, but never UIKeyboardWillShowNotification.
I am working on a project, and I am developing a login screen that has UIView of two textfields and I change the position of that view when keyboard hides or shows.
I am getting a problem when I move from the email textfield to the password text field. The view return to its original location/frame without asking it to.
Here's code snippet:
var isKeyboardOpened = false
#IBOutlet weak var viewLoginContainer: UIView!
override func viewDidLoad() {
super.viewDidLoad()
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)
}
func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if !isKeyboardOpened {
isKeyboardOpened = true
self.viewLoginContainer.frame.origin.y -= keyboardSize.height - 100
self.viewLoginContainer.layoutIfNeeded()
}
}
}
func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y != 0{
isKeyboardOpened = false
self.viewLoginContainer.frame.origin.y += keyboardSize.height - 100
}
}
}
Problem solved by editing the constrains programmatically by adding:
self.viewLoginContainer_topConstraint.constant = x