Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Text field sudden jump when text is typed using keyboard on devices with safe area. #1733

Closed
chaubss opened this issue Jun 20, 2020 · 16 comments

Comments

@chaubss
Copy link

chaubss commented Jun 20, 2020

Describe the bug
On certain devices, when IQKeyboardManagerSwift is used, text fields suddenly jump when text is typed into them. This appears to be an issue with safe area only, it works as expected on other devices. I was able to workaround this issue by having constraints with respect to superview rather than safe area.

To Reproduce
Steps to reproduce the behavior:

  1. Add a Text Field and add constraints with respect to safe area from bottom or top.
  2. Enable IQKeyboardManagerSwift (from CocoaPods).

Expected behavior
Text Field should not jump when text is typed into it.

Screenshots
iq keyboard issue

Versions

Xcode: 11.5
Mac OS: 10.15.4
Simulator/Device: iPhone 11 Pro Simulator, iPhone XR
Library Version: 6.5.5

@hackiftekhar
Copy link
Owner

Sorry but I'm not able to reproduce the issue with the version specified. Can you please share a demo project?

@chaubss
Copy link
Author

chaubss commented Jul 19, 2020

KeyboardManagerDemo.zip

@Yudi26
Copy link

Yudi26 commented Sep 3, 2020

Same issue happening with me. Specially in Notch iPhones, Giving constraints from SafeArea is causing this issue.
Please fix it.
Before typing any text:
Screenshot 2020-09-03 at 1 44 09 PM
After typing any text UI is disturbed:
Screenshot 2020-09-03 at 1 44 21 PM

@pk26-lab
Copy link

I am also facing the same issue as I recently update to iOS 14, and after dismissing the keyboard the objects on the UIView pulled up remains hidden instead of returning back to their original position. Any help would be highly appreciated! Thanks:)

@tahamuneeb
Copy link

I am also experiencing same problem in iOS 14 simulator iPhone 11 Pro. I have given constraints to safe area layout guide. for textfields above the keyboard works fines but textfield below keyboard make whole view dances up and down on each key press, also the textfield below keyboard is not moving above keyboard.

@pk26-lab
Copy link

@tahamuneeb I was able to resolve the issue by changing the constraints from Safe Area Layout to View Layout:)

@tahamuneeb
Copy link

@pkhurana2610 still behaving same

@tahamuneeb
Copy link

This seems like to be a issue of iOS keyboard, I fixed It by disabling auto keyboard distance manager and changing constraint
on run time by moving textfield move up and down, I register the frame of all textfields first after constraints being applied then on keyboard appear notification I check current selected field and I get its position from that array in which I have saved frames, this way I compare the difference on how much to move up and down.

I am using snapkit, if anyone needs my code I will share and explain.

@i0sa
Copy link

i0sa commented Nov 8, 2020

same issue
@tahamuneeb please share

@tahamuneeb
Copy link

`//
// KeyboardManager.swift
// Fastorder
//
// Created by Taha Muneeb on 10/20/20.
// Copyright © 2020 Taha Muneeb. All rights reserved.
//

import Foundation
import UIKit
import SnapKit

@objc protocol KeyboardManagerDataSource: class {
@objc func keyboardWillAppear(notification: NSNotification?)
@objc func keyboardWillDisappear(notification: NSNotification?)

}
class KeyboardManager {
private var topConstraint: Constraint?
private var bottomContrainst: Constraint?
private var view: UIView
private var keyboardHeight: CGFloat = 0
private var duration: Double = 0
private var curve: UInt = 0
private var topPreviousValue: CGFloat = 0

private var currentField: UITextField?
private var fields: [UITextField] = []
private var endingHeight: [CGFloat] = []

init (view: UIView, topConstraint: Constraint?, bottomContrainst: Constraint?) {
    self.view = view
    self.topConstraint = topConstraint
    self.bottomContrainst = bottomContrainst
    topPreviousValue = topConstraint?.layoutConstraints.first?.constant ?? 0
}
func addField(_ field: UITextField) {
    if !fields.contains(field) {
        fields.append(field)
        let frame = field.convert(field.bounds, to: view)
        let distanceFromViewBottom = frame.origin.y + 80
        endingHeight.append(distanceFromViewBottom)
    }
}
func remove() {
    NotificationCenter.default.removeObserver(view)
}
func listen() {
    if let holder = view as? KeyboardManagerDataSource {
        NotificationCenter.default.addObserver(view, selector: #selector(holder.keyboardWillAppear(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.addObserver(view, selector: #selector(holder.keyboardWillDisappear(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
    }
}

func keyboardWillAppear(notification: NSNotification?) {
    guard let keyboardFrame = notification?.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else {
        return
    }
    guard (notification?.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue) != nil else {
        return
    }
    keyboardHeight = keyboardFrame.cgRectValue.height - view.safeAreaInsets.bottom
    duration = (notification?.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber ?? NSNumber()).doubleValue
    curve = (notification?.userInfo?[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber ?? NSNumber()).uintValue
    DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + duration) {
        self.process()
    }
}

func keyboardWillDisappear(notification: NSNotification?) {
duration = (notification?.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber ?? NSNumber()).doubleValue
let curve = (notification?.userInfo?[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber ?? NSNumber()).uintValue
self.keyboardHeight = 0
currentField = nil
UIView.animate(withDuration: duration, delay: 0, options: UIView.AnimationOptions(rawValue: curve), animations: {
self.topConstraint?.update(inset: self.topPreviousValue)
self.view.layoutIfNeeded()
})
}

private func process() {
    guard let field = view.selectedTextField else { return }
    if field == currentField {
        return
    }
    currentField = field
    guard  let index =  fields.firstIndex(of: field) else {
        return
    }
    let distanceFromViewBottom = endingHeight[index]
    let difference = view.bounds.size.height - keyboardHeight

    if distanceFromViewBottom > difference {
        UIView.animate(withDuration: duration == 0 ? 0.1 : duration, delay: 0, options: UIView.AnimationOptions(rawValue: curve), animations: {
            let distance = distanceFromViewBottom - difference
            if distance < 0 {
                self.topConstraint?.update(offset: distance )
            } else {
                self.topConstraint?.update(inset: self.topPreviousValue - distance - 50)
            }
            field.superview?.layoutIfNeeded()
        })
    } else {
        UIView.animate(withDuration: duration == 0 ? 0.1 : duration, delay: 0, options: UIView.AnimationOptions(rawValue: curve), animations: {
            self.topConstraint?.update(inset: self.topPreviousValue)
            field.superview?.layoutIfNeeded()
        })
    }
}

}
`

This class is compatible with Snapkit and IQkeyboard manager. Just register the fields with func addField(_ field: UITextField) function and it will start working

@tahamuneeb
Copy link

@i0sa in short I am giving the positions of textfield to may manager and changing bottom or top constraint based on textfield location relative to keboard

@i0sa
Copy link

i0sa commented Nov 8, 2020

So after checking the original issue, i found that it is caused by iOS 14 simulator, but not in my actual iOS 14 device,
This is not the first time i see an issue on simulator but not in actual device

Can someone confirm ?
Edit: nevermind, this issue appeared on iPhone 11, but not in iPhone 8 plus

@tahamuneeb
Copy link

@i0sa I don't have original device atm, but I observed same issue using iOS 13 iPhone 6s Plus

@ueen
Copy link

ueen commented Jan 11, 2021

Its happening on iOS14 device as well, if something is typed and then the keyboard closed, the (in my case) button algined to safe area jumps down

@ueen
Copy link

ueen commented Jan 11, 2021

quick workaround: align to superview rather than safe area

@hackiftekhar
Copy link
Owner

I found the root cause of the issue, it's because when you start typing, the safe area for that view get's changed. You can see the gap at the bottom of the constraint.

Screen Shot 2022-04-05 at 4 02 30 PM
Screen Shot 2022-04-05 at 4 02 49 PM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants