Changing Constraint when Keyboard Appears - Swift
The problem is that the view not going up in first click of the textView is that the showKeyboard observer is added in beginEditing , so this line should be in viewDidLoad
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), name: .UIKeyboardWillHide, object: nil)
in addition to the following fixes
func textViewDidBeginEditing(_ textView: UITextView) {
// I think no need for it
}
@objc func keyboardWillShow(notification: Notification) {
let keyboardSize = (notification.userInfo? [UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
let keyboardHeight = keyboardSize?.height
if #available(iOS 11.0, *){
self.composeViewBottomConstraint.constant = keyboardHeight! - view.safeAreaInsets.bottom
}
else {
self.composeViewBottomConstraint.constant = view.safeAreaInsets.bottom
}
UIView.animate(withDuration: 0.5){
self.view.layoutIfNeeded()
}
}
@objc func keyboardWillHide(notification: Notification){
self.composeViewBottomConstraint.constant = 0 // or change according to your logic
UIView.animate(withDuration: 0.5){
self.view.layoutIfNeeded()
}
}
Swift: Change autolayout constraints when keyboard is shown
Personally I find it a lot simpler to adjust the bottom content inset of the text view. This code is for a text view that occupies the whole window (so its bottom is the bottom of the screen); a text view that doesn't come down that far would require a little more elementary arithmetic:
func keyboardShown(n:NSNotification) {
let d = n.userInfo!
var r = (d[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue()
r = self.textView.convertRect(r, fromView:nil)
self.textView.contentInset.bottom = r.size.height
self.textView.scrollIndicatorInsets.bottom = r.size.height
}
Constraints Not Updating When Keyboard Appears
Ok. I had this problem when i first started out on iOS with Swift. See the problem is with your understanding of anchors.
The constant that you specify doesn't function like how you are expecting it to. (You are expecting it to function like some kind of listener which will keep updating based on the update in the value of the variable. It doesn't) It will just take the value of the variable at the time of setting and then not look back unless you access that anchor and change the constant manually.
Which is why you have to store the instance of the anchor and change the constant maually like this.
Define the constraint variable:
var topAnchorConstraint: NSLayoutConstraint!
Store the appropriate constraint in the variable
topAnchorConstraint = passwordTextField.topAnchor.constraint(equalTo: emailTextField.bottomAnchor, constant: 35)
topAnchorConstraint.isActive = true
Now you need to change the constant as required.
func textFieldDidBeginEditing(_ textField: UITextField) {
UIView.animate(withDuration: 1.0, animations: {
self.topAnchorConstraint.constant = 15
self.view.layoutIfNeeded()
}, completion: nil)
}
Move textfield when keyboard appears swift
There are a couple of improvements to be made on the existing answers.
Firstly the UIKeyboardWillChangeFrameNotification is probably the best notification as it handles changes that aren't just show/hide but changes due to keyboard changes (language, using 3rd party keyboards etc.) and rotations too (but note comment below indicating the keyboard will hide should also be handled to support hardware keyboard connection).
Secondly the animation parameters can be pulled from the notification to ensure that animations are properly together.
There are probably options to clean up this code a bit more especially if you are comfortable with force unwrapping the dictionary code.
class MyViewController: UIViewController {
// This constraint ties an element at zero points from the bottom layout guide
@IBOutlet var keyboardHeightLayoutConstraint: NSLayoutConstraint?
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self,
selector: #selector(self.keyboardNotification(notification:)),
name: UIResponder.keyboardWillChangeFrameNotification,
object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
@objc func keyboardNotification(notification: NSNotification) {
guard let userInfo = notification.userInfo else { return }
let endFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
let endFrameY = endFrame?.origin.y ?? 0
let duration:TimeInterval = (userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
let animationCurveRawNSN = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber
let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIView.AnimationOptions.curveEaseInOut.rawValue
let animationCurve:UIView.AnimationOptions = UIView.AnimationOptions(rawValue: animationCurveRaw)
if endFrameY >= UIScreen.main.bounds.size.height {
self.keyboardHeightLayoutConstraint?.constant = 0.0
} else {
self.keyboardHeightLayoutConstraint?.constant = endFrame?.size.height ?? 0.0
}
UIView.animate(
withDuration: duration,
delay: TimeInterval(0),
options: animationCurve,
animations: { self.view.layoutIfNeeded() },
completion: nil)
}
}
Handling keyboard with bottom constraint
You have to use self.view.layoutIfNeeded()
after Update constraint
i write complete solution for you
class ViewController: UIViewController {
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)
}
@objc func keyboardWillShow(notification: Notification) {
self.keyboardControl(notification, isShowing: true)
}
@objc func keyboardWillHide(notification: Notification) {
self.keyboardControl(notification, isShowing: false)
}
private func keyboardControl(_ notification: Notification, isShowing: Bool) {
/* Handle the Keyboard property of Default*/
var userInfo = notification.userInfo!
let keyboardRect = (userInfo[UIKeyboardFrameEndUserInfoKey]! as AnyObject).cgRectValue
let curve = (userInfo[UIKeyboardAnimationCurveUserInfoKey]! as AnyObject).uint32Value
let convertedFrame = self.view.convert(keyboardRect!, from: nil)
let heightOffset = self.view.bounds.size.height - convertedFrame.origin.y
let options = UIViewAnimationOptions(rawValue: UInt(curve!) << 16 | UIViewAnimationOptions.beginFromCurrentState.rawValue)
let duration = (userInfo[UIKeyboardAnimationDurationUserInfoKey]! as AnyObject).doubleValue
var pureheightOffset : CGFloat = -heightOffset
if isShowing { /// Wite space of save area in iphonex ios 11
if #available(iOS 11.0, *) {
pureheightOffset = pureheightOffset + view.safeAreaInsets.bottom
}
}
// Here change you Consrant
// self.actionBarPaddingBottomConstranit?.update(offset:pureheightOffset)
UIView.animate(
withDuration: duration!,
delay: 0,
options: options,
animations: {
self.view.layoutIfNeeded()
},
completion: { bool in
})
}
Keep Bottom of TableView Visible When Keyboard Shows With Autolayout in Swift
One approach:
- constrain the top of the tableView to the top of the view
- constrain the bottom of the tableView to the top of the textField
- constrain the bottom of the textField to the bottom of the view
- create an
@IBOutlet
for the textField's bottom constraint
When the keyboard is shown, change the .constant
of the textField's bottom constraint to the height of the keyboard view.
This will move the textField up, and because it's top is constrained to the bottom of the tableView, it will also move the tableView's bottom edge up.
Then scroll to the bottom of the tableView.
Layout:
Initial hierarchy, with 20 rows (scrolled to the bottom):
Hierarchy view (tableView background color set to green, so we can see its frame):
View after the keyboard is shown:
Hierarchy after the keyboard is shown:
Little tough to see from static screen caps, but the frame of the green rectangle (the tableView background) is now shorter... the user can still scroll up and down to see all the rows, but the bottom of the tableView is still constrained to the top of the textField.
When you the keyboard is dismissed, set the .constant
of the textField's bottom constraint back to Zero.
You can see a full, working example project up on GitHub: https://github.com/DonMag/KBAdjust
SWIFT: UIView which moves up with keyboard, moves very strangely after initial move, doesn't come back down
You are doing too many things wrong for me to list, so I have just fixed your project and made a pull request. Merge the pull request into your repo and you will see that it now works fine.
Just for the record, here are some of the main things you were doing wrong:
You added a bottom constraint, in code, to the blue view. But you already had a bottom constraint on the blue view. Thus you now have two of them, and any change in one of them will cause a conflict. The Xcode console was telling you very clearly that this was happening, but you ignored what it told you.
You were changing the constraint constant but also changing the blue view
center
. That probably caused no harm but it was pointless. You cannot govern a view's position by itscenter
if you are governing it with constraints; they are opposites.In your show and hide methods you examined
keyboardFrameBeginUserInfoKey
. That's wrong. You want to examinekeyboardFrameEndUserInfoKey
. The question is not where the keyboard is now but where it will be when it finishes moving.The animation is wrong. There is no need for a UIView animation; you are already in an animation block. Just call
layoutIfNeeded
and the animation will happen together with the movement of the keyboard.Your entire way of speaking of and accessing constraints is wrong. You use an incorrect expression
super.view
(you probably meantself.view
). But even more important, you attempt to access the desired constraint by sayingself.constraints[2]
. That sort of thing is fragile in the extreme. The correct approach is to keep a reference to the actual constraint (an instance property). In this situation, since the constraint already exists (in the storyboard), that reference can be an outlet.
So, with all that said, here's my rewrite of your code; this is the complete code needed:
class ViewController: UIViewController {
@IBOutlet weak var sampleTextField: UITextField!
@IBOutlet weak var bottomConstraint: NSLayoutConstraint!
var originalConstant: CGFloat = 0
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIWindow.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIWindow.keyboardWillHideNotification, object: nil)
self.originalConstant = bottomConstraint.constant
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
sampleTextField.endEditing(true)
}
}
extension ViewController {
@objc func keyboardWillShow(notification: NSNotification) {
print("keyboardWillShow")
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
self.bottomConstraint.constant += keyboardSize.height + 5
self.view.layoutIfNeeded()
}
}
@objc func keyboardWillHide(notification: NSNotification){
print("keyboardWillHide")
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
self.bottomConstraint.constant = self.originalConstant
self.view.layoutIfNeeded()
}
}
}
With all of that said, the code is still wrong, because you are not taking account of the very real possibility that you will get a keyboardWillShow
notification when the keyboard is already showing. However, I leave that for your later investigation.
Related Topics
iOS Mkmapview Custom Images Display on Top Left Corner
Transfer Gestures on a Uiview to a Uitableview in Swift - iOS
How to Change Uiwebview Orientation Programmatically in Swift
Getting Uitableview Error "Unable to Dequeue a Cell with Identifier Cell"
Swift Conform to Protocol Subclass
Creating a Custom UI View Class to Use as a Map Annotation
Realmswift Cannot Cast Results<Someojbect> to Results<Object>
Retrieving Uiimage from Uiimageview in Swift
Making the Map Zoom to User Location and Annotation (Swift 2)
Using Huffman Coding to Compress Images Taken by the iPhone Camera
How to Get Stack Trace Error in Swift
Google Signin Cocoapods Deprecated
How to Use Alamofires Servertrustpolicy.Disableevaluation in Swift 3
How to Send Emails in Swift Using Mailgun
Uitableviewcell Shows Incorrect Results from Document Folder