iOS 键盘遮挡输入框万能解决方案(多个输入框)

效果图如下:

效果图.gif

思路分析:

当我们有很多输入框时,有时候键盘弹出来会遮挡着输入框。我们需要获取输入框和键盘相对于最外层视图的位置来判断是否遮挡,如果遮挡了计算出遮挡的高度,然后设置最外层视图的frame,往上移动到大于等于遮挡遮住的高度即可。当键盘隐藏是在讲最外层视图的frame还原回来。

代码:

Main.storyboard如下所示:
UITextFiled相对于最外层view有四层.png
设置代理

#import "ViewController.h"
@interface ViewController ()
@property(nonatomic ,strong) UITextField * firstResponderTextF;//记录将要编辑的输入框
@end
@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    //监听键盘展示和隐藏的通知
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)dealloc{
    //移除键盘通知监听者
    [[NSNotificationCenter defaultCenter]removeObserver:self name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter]removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    if ([self.firstResponderTextF isFirstResponder])[self.firstResponderTextF resignFirstResponder];
}
#pragma maek UITextFieldDelegate
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
    self.firstResponderTextF = textField;//当将要开始编辑的时候,获取当前的textField
    return YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
    [textField resignFirstResponder];
    return YES;
}
#pragma mark : UIKeyboardWillShowNotification/UIKeyboardWillHideNotification
- (void)keyboardWillShow:(NSNotification *)notification{
    CGRect rect = [self.firstResponderTextF.superview convertRect:self.firstResponderTextF.frame toView:self.view];//获取相对于self.view的位置
    NSDictionary *userInfo = [notification userInfo];
    NSValue* aValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];//获取弹出键盘的fame的value值
    CGRect keyboardRect = [aValue CGRectValue];
    keyboardRect = [self.view convertRect:keyboardRect fromView:self.view.window];//获取键盘相对于self.view的frame ,传window和传nil是一样的
    CGFloat keyboardTop = keyboardRect.origin.y;
    NSNumber * animationDurationValue = [userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];//获取键盘弹出动画时间值
    NSTimeInterval animationDuration = [animationDurationValue doubleValue];
    if (keyboardTop < CGRectGetMaxY(rect)) {//如果键盘盖住了输入框
        CGFloat gap = keyboardTop - CGRectGetMaxY(rect) - 10;//计算需要网上移动的偏移量(输入框底部离键盘顶部为10的间距)
        __weak typeof(self)weakSelf = self;
        [UIView animateWithDuration:animationDuration animations:^{
            weakSelf.view.frame = CGRectMake(weakSelf.view.frame.origin.x, gap, weakSelf.view.frame.size.width, weakSelf.view.frame.size.height);
        }];
    }
}
- (void)keyboardWillHide:(NSNotification *)notification{
    NSDictionary *userInfo = [notification userInfo];
    NSNumber * animationDurationValue = [userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];//获取键盘隐藏动画时间值
    NSTimeInterval animationDuration = [animationDurationValue doubleValue];
    if (self.view.frame.origin.y < 0) {//如果有偏移,当影藏键盘的时候就复原
        __weak typeof(self)weakSelf = self;
        [UIView animateWithDuration:animationDuration animations:^{
            weakSelf.view.frame = CGRectMake(weakSelf.view.frame.origin.x, 0, weakSelf.view.frame.size.width, weakSelf.view.frame.size.height);//注意如果带有导航则view的y值就不说0了而是状态栏高度加导航栏的高度
        }];
    }
}
@end

知识点:

1.当输入框将要编辑时会调- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField代理方法(本为用的都是UITextField),此时用一个全局变量firstResponderTextF来记录将要编辑的输入框。(好处就是如果很多输入框是局部变量一个个获取会比较麻烦,用一个全局变量来记录就会简单方便的多);
2. 键盘展示和隐藏的通知:UIKeyboardWillShowNotification,UIKeyboardWillHideNotification;可以获得键盘的frame和动画时长;通过计算键盘和输入框相对于最外层是视图的外置来判断是否被哲哲,如果遮住则间整体视图网上移动大于等于遮住的高度,当键盘隐藏的时候则还原来的位置;
获取键盘将要展示时获取的信息.png
获取键盘将要隐藏时获取的信息.png

对应的key:UIKeyboardFrameEndUserInfoKey键盘frame,UIKeyboardAnimationDurationUserInfoKey展示和影藏的动画时长;
3.相对于摸个视图位置的api(UIView):

- (CGPoint)convertPoint:(CGPoint)point toView:(nullable UIView *)view;//获取当前视图的点坐标相对于view上的点坐标
- (CGPoint)convertPoint:(CGPoint)point fromView:(nullable UIView *)view;//获取view上的点坐标相对于当前视图的点坐标
- (CGRect)convertRect:(CGRect)rect toView:(nullable UIView *)view;//获取当前视图的frame相对于view上的frame
- (CGRect)convertRect:(CGRect)rect fromView:(nullable UIView *)view;//获取view上的frame相对于当前视图的frame

问题:

如文中获取将要编辑的输入框相对于最外层视图的fameCGRect rect = [self.firstResponderTextF.superview convertRect:self.firstResponderTextF.frame toView:self.view];(这里其实应该算两次:要先获得输入框在父视图(红色或蓝色的view)中的位置来获得相对父视图的俯视图(黄色的view)的位置;然后才能获得输入框相对于最外层视图(白色的view),但文我直接用输入框在父视图(红色或蓝色的view)中的位置获得到了相对于最外层view(白色的view)的位置,并且结果正确,所以有些困惑,有理解的大神烦请指点一二);
原码:iOS 键盘遮挡输入框万能解决方案(多个输入框)

猜你喜欢

转载自blog.csdn.net/Bolted_snail/article/details/80138471