How to scroll view up when keyboard appears?

46,296

Solution 1

I have made solutions that work with scroll and non-scroll views using keyboard notification and a detection of the current first responder, but sometimes I use this trivial solution instead: The simple way is to detect the opening keyboard via the text field delegate's textViewDidBeginEditing: method and to move the entire view up. The easiest way to do this is with something along the lines of changing self.view.bounds.origin.y to -100 (or whatever). Use the corresponding textViewShouldEndEditing: method to set it to the opposite, which is 100 in this case. Changing bounds is a relative procedure. After changing it the frame is moved but the bounds origin is still zero.

Solution 2

Since I found it, I use TPKeyboardAvoiding - https://github.com/michaeltyson/TPKeyboardAvoiding.

It is working great, and is very easy to setup:

  • Add a UIScrollView into your view controller's xib
  • Set the scroll view's class to TPKeyboardAvoidingScrollView (still in the xib, via the identity inspector)
  • Place all your controls within that scroll view

You can also create it programmatically, if you want.


There is a class for the same need inside a UITableViewController ; it is only needed in case you support a version of iOS below 4.3.

Solution 3

@BenLu and other users who are facing problem of the function are never getting called is because of following reason: As the delegate inbuild function bydefaults return void instead of BOOL this is how it should be as follows:

 -(void)textFieldDidBeginEditing:(UITextField *)textField
{
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.35f];
    CGRect frame = self.view.frame;
    frame.origin.y = -100;
    [self.view setFrame:frame];
    [UIView commitAnimations];
}

-(void)textFieldDidEndEditing:(UITextField *)textField
{
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.35f];
    CGRect frame = self.view.frame;
    frame.origin.y = 100;
    [self.view setFrame:frame];
    [UIView commitAnimations];
}

Solution 4

I spent sometime on this problem and gathered pieces code to create one final solution. My problem was related to UITableView scrolling and keyboard open/close.

You need two partial methods in your cell class:

    void EditingBegin(UITextField sender)
    {
        // Height of tallest cell, you can ignore this!
        float tableMargin = 70.0f;
        float tableHeight = _tableView.Frame.Size.Height;
        float keyBoardHeight = KeyboardHeight();

        NSIndexPath[] paths = this._tableView.IndexPathsForVisibleRows;
        RectangleF rectLast = this._tableView.RectForSection(paths[paths.Length - 1].Section);
        RectangleF rectFirst = this._tableView.RectForSection(paths[0].Section);
        float lastCellY = rectLast.Y - rectFirst.Y;
        if (lastCellY > tableHeight - keyBoardHeight)
        {
            float diff = lastCellY - (tableHeight - tableMargin - keyBoardHeight);
            this._tableView.ContentInset = new UIEdgeInsets(0.0f, 0.0f, diff, 0.0f);
        }

        float cellPosition = this._tableView.RectForSection(this._section).Y;
        if (cellPosition > tableHeight - keyBoardHeight)
        {
            if (this._tableView.ContentInset.Bottom == 0.0f)
            {
                float diff = cellPosition - (tableHeight - tableMargin - keyBoardHeight);
                this._tableView.ContentInset = new UIEdgeInsets(0.0f, 0.0f, diff, 0.0f);
            }
            else
            {
                this._tableView.ScrollToRow(NSIndexPath.FromItemSection(0, this._section), UITableViewScrollPosition.Middle, true);
            }
        }
    }

    partial void EditingEnd(UITextField sender)
    {
        UIView.BeginAnimations(null);
        UIView.SetAnimationDuration(0.3f);
        this._tableView.ContentInset = new UIEdgeInsets(0.0f, 0.0f, 0.0f, 0.0f);
        UIView.CommitAnimations();
    }

and then in your view controller class:

    public override void WillAnimateRotation(UIInterfaceOrientation toInterfaceOrientation, double duration)
    {
        base.WillAnimateRotation(toInterfaceOrientation, duration);

        float bottom = this.TableView.ContentInset.Bottom;
        if (bottom > 0.0f)
        {
            if (toInterfaceOrientation == UIInterfaceOrientation.Portrait || toInterfaceOrientation == UIInterfaceOrientation.PortraitUpsideDown)
            {
                bottom = bottom * UIScreen.MainScreen.Bounds.Width / UIScreen.MainScreen.Bounds.Height;
            }
            else
            {
                bottom = bottom * UIScreen.MainScreen.Bounds.Height / UIScreen.MainScreen.Bounds.Width;
            }

            UIEdgeInsets insets = this.TableView.ContentInset;
            this.TableView.ContentInset = new UIEdgeInsets(0.0f, 0.0f, bottom, 0.0f);
        }
    }  
Share:
46,296
Henry F
Author by

Henry F

I'm an iOS software engineer, here gain knowledge, insight, and most importantly give help.

Updated on July 12, 2022

Comments

  • Henry F
    Henry F almost 2 years

    I know that this question has been asked over and over again, but nothing seems to be working for me. Most of the solutions around are pretty out of date, and the rest are incredibly huge blocks of code that are ten times larger then the actual projects coding. I have a few UITextFields lined up vertically, but when the keyboard launches to edit one, it covers up the text field. I was wondering if there is a simple beginner way to scroll the view up, and then back down when the editing starts and ends?

    Thank you.