How to scroll view up when keyboard appears?

后端 未结 7 1382
小蘑菇
小蘑菇 2021-01-31 02:54

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 incre

相关标签:
7条回答
  • 2021-01-31 03:23

    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);
            }
        }  
    
    0 讨论(0)
  • 2021-01-31 03:24

    If you have a UITableView or a UIScrollView it's better to change values for contentOffset instead of making changes to the frame.

    Working on Peter's Answer, adding this method to your class works nicely:

    - (void)textViewDidBeginEditing:(UITextField *)textField {
        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:0.35f];
        CGPoint offset = self.tableView.contentOffset;
        offset.y += 200; // You can change this, but 200 doesn't create any problems
        [self.tableView setContentOffset:offset];
        [UIView commitAnimations];
    }
    

    That's it, no need to add the textViewDidEndEditing method.


    I shouldn't need to say this, but for this to work your UITextField or UITextView must be a delegate of your controller.

    0 讨论(0)
  • 2021-01-31 03:28

    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.

    0 讨论(0)
  • 2021-01-31 03:34

    Starting with Peter's answer, I developed the following approach in Swift 3.0 under iOS 10.1. I'm doing this for a textView, so I have implemented the UITextViewDelegate functions textViewDidBeginEditing and textViewDidEndEditing where I adjust the view's bounds. As you can see, I set the origin Y value to a small positive number to scroll up and then back to 0 to return to the original position.

    Here is the relevant code from my ViewController. You don't need to animate, but it adds a nice touch.

    func textViewDidBeginEditing(_ textView: UITextView)
    {
        if UIScreen.main.bounds.height < 568 { 
            UIView.animate(withDuration: 0.75, animations: {
                self.view.bounds.origin.y = 60
            })
        }
    }
    
    func textViewDidEndEditing(_ textView: UITextView)
    {
        if UIScreen.main.bounds.height < 568 {
            UIView.animate(withDuration: 0.75, animations: {
                self.view.bounds.origin.y = 0
            })
        }
    }
    
    0 讨论(0)
  • 2021-01-31 03:36

    i have a scrollview and 3 text fields in this. I have a simple code from my own application :

    .h file is :

    #import <UIKit/UIKit.h>
    
    @interface AddContactViewController : UIViewController<UITextFieldDelegate, UIScrollViewDelegate>
    
    @property (nonatomic, retain) NSDictionary *dict_contactDetail;
    
    @property (nonatomic, retain) IBOutlet UILabel *lbl_name;
    @property (nonatomic, retain) IBOutlet UITextField *txtField_tel;
    @property (nonatomic, retain) IBOutlet UITextField *txtField_address;
    @property (nonatomic, retain) IBOutlet UITextField *txtField_email;
    
    @property (nonatomic, retain) IBOutlet UIScrollView *scrollView;
    
    @end
    

    .m file :

    #import "AddContactViewController.h"
    
    @interface AddContactViewController ()
    
    @end
    
    @implementation AddContactViewController
    
    @synthesize dict_contactDetail;
    
    @synthesize lbl_name, txtField_tel, txtField_email, txtField_address, scrollView;
    
    - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil       
    {
        self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
        if (self) {
            // Custom initialization
        }
        return self;
    }
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view from its nib.
    
       // NSLog(@"dict_contactDetail : %@", dict_contactDetail);
    
        UIBarButtonItem * rightButton = [[UIBarButtonItem alloc] initWithTitle:@"Add" style:UIBarButtonSystemItemDone target:self action:@selector(addEmergencyContact:)];
        self.navigationItem.rightBarButtonItem = rightButton;
    
    
        lbl_name.text = [NSString stringWithFormat:@"%@ %@", [dict_contactDetail  valueForKey:@"fname"], [dict_contactDetail  valueForKey:@"lname"]];
    
        txtField_tel.returnKeyType = UIReturnKeyDone;
        txtField_email.returnKeyType = UIReturnKeyDone;
        txtField_address.returnKeyType = UIReturnKeyDone;
    
    }
    
    
    
    -(void)addEmergencyContact:(id)sender
    {
        scrollView.frame = CGRectMake(0, 0, 320, 460);
    }
    
    #pragma mark - text field delegates
    - (void)textFieldDidBeginEditing:(UITextField *)textField
    {
        if([textField isEqual:txtField_tel])
        {
            [scrollView setContentOffset:CGPointMake(0, 70)];
            scrollView.frame = CGRectMake(0, 0, 320, 210);
        }
        if([textField isEqual:txtField_address])
        {
            [scrollView setContentOffset:CGPointMake(0, 140)];
            scrollView.frame = CGRectMake(0, 0, 320, 210);
        }
        if([textField isEqual:txtField_email])
        {
            [scrollView setContentOffset:CGPointMake(0, 210)];
            scrollView.frame = CGRectMake(0, 0, 320, 210);
        }
    }
    
    - (BOOL)textFieldShouldReturn:(UITextField *)textField
    {
        scrollView.frame = CGRectMake(0, 0, 320, 460);
        [textField resignFirstResponder];
        return YES;
    }
    
    
    
    @end
    
    0 讨论(0)
  • 2021-01-31 03:39

    @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];
    }
    
    0 讨论(0)
提交回复
热议问题