Move UIView up when the keyboard appears in iOS

后端 未结 18 1770
再見小時候
再見小時候 2020-11-28 20:38

I have a UIView, it is not inside UIScrollView. I would like to move up my View when the keyboard appears. Before I tried to use this solution: How can I make a UITextField

相关标签:
18条回答
  • 2020-11-28 21:03

    I wrote a little category on UIView that manages temporarily scrolling things around without needing to wrap the whole thing into a UIScrollView. My use of the verb "scroll" here is perhaps not ideal, because it might make you think there's a scroll view involved, and there's not--we're just animating the position of a UIView (or UIView subclass).

    There are a bunch of magic numbers embedded in this that are appropriate to my form and layout that might not be appropriate to yours, so I encourage tweaking this to fit your specific needs.

    UIView+FormScroll.h:

    #import <Foundation/Foundation.h>
    
    @interface UIView (FormScroll) 
    
    -(void)scrollToY:(float)y;
    -(void)scrollToView:(UIView *)view;
    -(void)scrollElement:(UIView *)view toPoint:(float)y;
    
    @end
    

    UIView+FormScroll.m:

    #import "UIView+FormScroll.h"
    
    
    @implementation UIView (FormScroll)
    
    
    -(void)scrollToY:(float)y
    {
    
        [UIView beginAnimations:@"registerScroll" context:NULL];
        [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
        [UIView setAnimationDuration:0.4];
        self.transform = CGAffineTransformMakeTranslation(0, y);
        [UIView commitAnimations];
    
    }
    
    -(void)scrollToView:(UIView *)view
    {
        CGRect theFrame = view.frame;
        float y = theFrame.origin.y - 15;
        y -= (y/1.7);
        [self scrollToY:-y];
    }
    
    
    -(void)scrollElement:(UIView *)view toPoint:(float)y
    {
        CGRect theFrame = view.frame;
        float orig_y = theFrame.origin.y;
        float diff = y - orig_y;
        if (diff < 0) {
            [self scrollToY:diff];
        }
        else {
            [self scrollToY:0];
        }
    
    }
    
    @end
    

    Import that into your UIViewController, and then you can do

    - (void)textFieldDidBeginEditing:(UITextField *)textField
    {
        [self.view scrollToView:textField];
    }
    
    -(void) textFieldDidEndEditing:(UITextField *)textField
    {
        [self.view scrollToY:0];
        [textField resignFirstResponder];
    }
    

    ...or whatever. That category gives you three pretty good ways to adjust the position of a view.

    0 讨论(0)
  • 2020-11-28 21:04

    I found theDuncs answer very useful and below you can find my own (refactored) version:


    Main Changes

    1. Now getting the keyboard size dynamically, rather than hard coding values
    2. Extracted the UIView Animation out into it's own method to prevent duplicate code
    3. Allowed duration to be passed into the method, rather than being hard coded

    - (void)viewWillAppear:(BOOL)animated {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
    }
    
    - (void)viewWillDisappear:(BOOL)animated {
        [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
        [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
    }
    

    - (void)keyboardWillShow:(NSNotification *)notification {
        CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
    
        float newVerticalPosition = -keyboardSize.height;
    
        [self moveFrameToVerticalPosition:newVerticalPosition forDuration:0.3f];
    }
    
    
    - (void)keyboardWillHide:(NSNotification *)notification {
        [self moveFrameToVerticalPosition:0.0f forDuration:0.3f];
    }
    
    
    - (void)moveFrameToVerticalPosition:(float)position forDuration:(float)duration {
        CGRect frame = self.view.frame;
        frame.origin.y = position;
    
        [UIView animateWithDuration:duration animations:^{
            self.view.frame = frame;
        }];
    }
    
    0 讨论(0)
  • 2020-11-28 21:08

    Bind a view to keyboard is also an option (see GIF at the bottom of the answer)

    Swift 4

    Use an extension: (Wasn't fully tested)

    extension UIView{
        func bindToKeyboard(){
            NotificationCenter.default.addObserver(self, selector: #selector(UIView.keyboardWillChange(notification:)), name: Notification.Name.UIKeyboardWillChangeFrame, object: nil)
        }
    
        func unbindToKeyboard(){
            NotificationCenter.default.removeObserver(self, name: Notification.Name.UIKeyboardWillChangeFrame, object: nil)
        }
        @objc
        func keyboardWillChange(notification: Notification) {
            let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
            let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt
            let curFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
            let targetFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
            let deltaY = targetFrame.origin.y - curFrame.origin.y
    
            UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: {
                self.frame.origin.y+=deltaY
    
            },completion: nil)
    
        }
    }
    

    Swift 2 + 3

    Use an extension:

    extension UIView{
        func bindToKeyboard(){
            NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(UIView.keyboardWillChange(_:)), name: UIKeyboardWillChangeFrameNotification, object: nil)
        }
    
    
        func keyboardWillChange(notification: NSNotification) {
    
            let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
            let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt
            let curFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).CGRectValue()
            let targetFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue()
            let deltaY = targetFrame.origin.y - curFrame.origin.y
    
    
            UIView.animateKeyframesWithDuration(duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: {
                    self.frame.origin.y+=deltaY
    
            },completion: nil)
    
        }  
    }
    

    Usage:

    // view did load...
    textField.bindToKeyboard()
    

    ...

    // view unload
    textField.unbindToKeyboard()
    

    result:

    important
    Don't forget to remove the observer when view is unloading

    0 讨论(0)
  • 2020-11-28 21:08

    Simple solution without adding observer notification

    -(void)setViewMovedUp:(BOOL)movedUp
    {
        [UIView beginAnimations:nil context:NULL];
    
        [UIView setAnimationDuration:0.3]; // if you want to slide up the view
    
        CGRect rect = self.view.frame;
    
        if (movedUp)
        {
            // 1. move the view's origin up so that the text field that will be hidden come above the keyboard
            // 2. increase the size of the view so that the area behind the keyboard is covered up.
            rect.origin.y -= kOFFSET_FOR_KEYBOARD;
            rect.size.height += kOFFSET_FOR_KEYBOARD;
        }
        else
        {
            // revert back to the normal state.
            rect.origin.y += kOFFSET_FOR_KEYBOARD;
            rect.size.height -= kOFFSET_FOR_KEYBOARD;
        }
        self.view.frame = rect;
    
        [UIView commitAnimations];
    }
    
    
    -(void)textFieldDidEndEditing:(UITextField *)sender
    {
         if  (self.view.frame.origin.y >= 0)
            {
                [self setViewMovedUp:NO];
            }
    }
    
    -(void)textFieldDidBeginEditing:(UITextField *)sender
    {
            //move the main view, so that the keyboard does not hide it.
            if  (self.view.frame.origin.y >= 0)
            {
                [self setViewMovedUp:YES];
            }
    }
    

    Where

    #define kOFFSET_FOR_KEYBOARD 80.0
    
    0 讨论(0)
  • 2020-11-28 21:12

    Swift 5

    Updated version of answer by Daniel Krom above:

    extension UIView {
    
        func bindToKeyboard() {
            NotificationCenter.default.addObserver(
                self,
                selector: #selector(UIView.keyboardWillChange(notification:)),
                name: UIResponder.keyboardWillChangeFrameNotification,
                object: nil
            )
        }
    
        func unbindToKeyboard() {
            NotificationCenter.default.removeObserver(
                self,
                name: UIResponder.keyboardWillChangeFrameNotification,
                object: nil
            )
        }
    
        @objc func keyboardWillChange(notification: Notification) {
            let duration = notification.userInfo![UIResponder.keyboardAnimationDurationUserInfoKey] as! Double
            let curve = notification.userInfo![UIResponder.keyboardAnimationCurveUserInfoKey] as! UInt
            let curFrame = (notification.userInfo![UIResponder.keyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
            let targetFrame = (notification.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
            let deltaY = targetFrame.origin.y - curFrame.origin.y
    
            UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIView.KeyframeAnimationOptions(rawValue: curve), animations: {
                self.frame.origin.y += deltaY
            })
        }
    
    }
    
    0 讨论(0)
  • 2020-11-28 21:12

    try this one:-

     [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector (keyboardDidShow:)
                                                     name: UIKeyboardDidShowNotification object:nil];
    
    
    [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector (keyboardDidHide:)
                                                     name: UIKeyboardDidHideNotification object:nil];
    
    -(void) keyboardDidShow: (NSNotification *)notif
        {
            CGSize keyboardSize = [[[notif userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
            UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize.height+[self getTableView].tableFooterView.frame.size.height, 0.0);
    
            [self getTableView].contentInset = contentInsets;
            [self getTableView].scrollIndicatorInsets = contentInsets;
    
            CGRect rect = self.frame; rect.size.height -= keyboardSize.height;
            if (!CGRectContainsPoint(rect, self.frame.origin))
            {
                CGPoint scrollPoint = CGPointMake(0.0, self.frame.origin.y - (keyboardSize.height - self.frame.size.height));
                [[self getTableView] setContentOffset:scrollPoint animated:YES];
            }
        }
    
    -(void) keyboardDidHide: (NSNotification *)notif
    {
        UIEdgeInsets contentInsets = UIEdgeInsetsZero;
        [self getTableView].contentInset = contentInsets;
        [self getTableView].scrollIndicatorInsets = contentInsets;
    }
    
    0 讨论(0)
提交回复
热议问题