Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UI Elements Moving When Character Typed In Text Field

When a user selects the bottom text field all elements in the view move up by the height of the keyboard until the user dismisses the keyboard.

The problem occurs after the user selects the bottom text field. Initially the elements all move up correctly. However, when the first character is typed by the user all of the elements move back down to the original position. As a result, the user can no longer see the text field they are editing. Once the user dismisses the keyboard they see the elements go up where they should have been, and then come right back down to the original position.

I have narrowed down what is causing the issue, but I do not understand why it is happening. My project can be found on GitHub at https://github.com/JMNolan/memesicle

I am still very new to Swift and fairly new to coding in general, so all help is really appreciated. I have also included the code snippets below that are relevant to this process for anyone who does not want to use GitHub

This is what moves the elements up the height of the keyboard

//moves the view up when the keyboard appears to keep the text field 
visible
    @objc func keyboardWillShow (notification: NSNotification){
        if bottomTextFieldActive == true{
            keyboardHeight = getKeyboardHeight(notification: 
notification)
            imagePickerView.frame.origin.y -= keyboardHeight
            topText.frame.origin.y -= keyboardHeight
            bottomText.frame.origin.y -= keyboardHeight
            toolbar.frame.origin.y -= keyboardHeight
        }
    }

This is what moves the elements back down the height of the keyboard when the keyboard is dismissed

//moves the view down when the keyboard is dismissed to show the full view again
@objc func keyboardWillHide (notification: NSNotification){
    imagePickerView.frame.origin.y += keyboardHeight
    topText.frame.origin.y += keyboardHeight
    bottomText.frame.origin.y += keyboardHeight
    toolbar.frame.origin.y += keyboardHeight
    //shareButton.frame.origin.y += keyboardHeight
    print("keyboard just hid")
}

This is what calls the function above

func subscribeToKeyboardNotifications(){
        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)
    }

This is how I get the keyboardHeight used when moving the elements up and down the height of the keyboard.

//get the height of the keyboard to determine how far up to move the view when editing the bottom text field
func getKeyboardHeight(notification: NSNotification) -> CGFloat {
    let userinfo = notification.userInfo
    let keyboardSize = userinfo![UIKeyboardFrameEndUserInfoKey] as!NSValue
    return keyboardSize.cgRectValue.height
}
like image 748
John Nolan Avatar asked Jan 27 '26 12:01

John Nolan


2 Answers

The reason your screen elements are jumping around when you type in the UITextField is because of your view constraints. When you add constraints to your view, you kind of forfeit the ability to later move the subviews around by altering their frames - each time the view recalculates the location of its subviews, it will go back to using the original values as provided by the constraints and ignore the frame changes you made.

Since you've got a few different screen elements you want to move, the easiest way to solve this is to put all your subviews (text field, image view, etc) inside a UIScrollView and then resize the scroll view's content inset property when the keyboard comes up. This would completely replace your code that changes the frame sizes. Apple has a help document about how to do this, but the important parts are below:

Adjusting your content typically involves temporarily resizing one or more views and positioning them so that the text object remains visible. The simplest way to manage text objects with the keyboard is to embed them inside a UIScrollView object or one of its subclasses, like UITableView. Note that UITableViewController automatically resizes and repositions its table view when there is inline editing of text fields (to learn more, see View Controllers and Navigation-Based Apps).

When the keyboard is displayed, all you have to do is reset the content area of the scroll view and scroll the desired text object into position. Thus, in response to a UIKeyboardDidShowNotification, your handler method would do the following:

  1. Get the size of the keyboard.

  2. Adjust the bottom content inset of your scroll view by the keyboard height.

  3. Scroll the target text field into view.

// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
    scrollView.contentInset = contentInsets;
    scrollView.scrollIndicatorInsets = contentInsets;

    // If active text field is hidden by keyboard, scroll it so it's visible
    // Your app might not need or want this behavior.
    CGRect aRect = self.view.frame;
    aRect.size.height -= kbSize.height;
    if (!CGRectContainsPoint(aRect, activeField.frame.origin) ) {
        [self.scrollView scrollRectToVisible:activeField.frame animated:YES];
    }
}

// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    scrollView.contentInset = contentInsets;
    scrollView.scrollIndicatorInsets = contentInsets;
}
like image 119
shocking Avatar answered Jan 29 '26 01:01

shocking


I faced the same issue, and after read shocking's answer, I found a solution. Thank shocking

I overrode updateViewConstraints() method, and inside, I updated constraint for TextView bottom to View bottom, with constant = keyboard height.

override func updateViewConstraints() { 
    writeCommentView.autoPinEdge(toSuperviewEdge: .bottom, withInset: keyboardHeight)  //I use PureLayout library

    super.view.updateConstraints()
}

And then, I call updateViewConstraints() in keyboardWillShow(), keyboardWillHide()

@objc func keyboardWillShow(notification: NSNotification) {

     //Code for move up textview here

      self.updateViewConstraints()
}
like image 36
Tà Truhoada Avatar answered Jan 29 '26 02:01

Tà Truhoada



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!