iOS开发专题我的收藏

自定义键盘系列之二键盘自适应响应者

2017-05-04  本文已影响171人  摸着石头过河_崖边树

首先解释一下标题,什么是键盘自适应响应者,理解为无论响应者在什么位置,键盘弹出都会在响应者的下面,使响应者控件可见。

demo效果


键盘自动适应响应者.gif
提出问题######

我们在做登录页面的时候假如有多个输入框,并且当输入框在屏幕底部的时候,我们直接弹出键盘就会挡住输入框,如图所示?(需要调整键盘)

自动适应键盘实例情况.png
分析问题######

当我们点击输入框时候,被点击的输入框成为FirstResponder,我们可以采用监听键盘通知方式,滚动输入框所在的父控件,从而实现键盘在FirstResponder的下面。

解决问题方案######

方案一:遇到这种要滚动的问题,我们可以把FirstResponder的控件增加到UIScroollView中,这样可以实现滚动。
优点:最容易想到的方案,简单易写;
缺点:为了实现键盘自适应响应者功能,增加额外的UIScroollView滚动控件。

方案二:我们可以监听键盘的时候,直接滚动当前响应者控件的父View,设置View的frame.origin.y就可以
优点:没有增加控件就可以实现功能

所以我最终采用方案二

具体实现####

我想这样的需求主要用在登录的时候,所以就打算写一个UIViewController分类,就可以实现(已经封装成工具类,项目可以直接使用),这样可以一行代码拥有这个功能

 #import "UIViewController+LZBKeyBoardObserver.h"  分类名称
    使用方法:一行代码控制器有这个功能
    [self lzb_addKeyBoardObserverAutoAdjustHeight];

1、在分类中增加键盘的监听

  - (void)lzb_addKeyBoardObserverAutoAdjustHeight
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}

有监听,必须有移除

- (void)lzb_removeKeyBoardObserver
 {
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
//键盘手势
[[NSNotificationCenter defaultCenter] removeObserver:_keyboardWillShowObser name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:_keyboardWillHideObser name:UIKeyboardWillHideNotification object:nil];
}

2、键盘显示的时候调用通知方法,代码中有实现的步骤

 - (void)keyboardWillShow:(NSNotification *)notification
{
//获取键盘的参数
CGFloat keyboardHeight = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
CGFloat keyboardAnimaitonDuration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] floatValue];
NSInteger option = [notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];
//移除之前的动画
[self.view.layer removeAllAnimations];
UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
//找出第一响应者
UIView *firstResponseView = [self findFirstResponderWithView:self.view];
CGRect rect = [keyWindow convertRect:firstResponseView.frame fromView:firstResponseView.superview];
//计算第一响应者与键盘弹出的差值,滚动距离
CGFloat firstResponseViewMaxY= CGRectGetMaxY(rect);
CGFloat keyBoardY = keyWindow.bounds.size.height - keyboardHeight;
CGFloat keyBoardResponseViewMargin = firstResponseViewMaxY - keyBoardY;
//如果响应者的最大Y值 > 键盘的Y值才滚动
_lzb_keyBoard_DefaultMargin = 0;
if(firstResponseViewMaxY > keyBoardY)
{
    //设置lzb_settingKeyBoard_DefaultMargin固定距离(就是滚动后的间距)
    _lzb_keyBoard_DefaultMargin = lzb_settingKeyBoard_DefaultMargin;
    _lzb_keyBoard_DefaultMargin +=keyBoardResponseViewMargin;
    //滚动动画
    __weak UIViewController *weakSelf = self;
    [UIView animateKeyframesWithDuration:keyboardAnimaitonDuration
                                   delay:0
                                 options:option
                              animations:^{
                                  CGRect frame = weakSelf.view.frame;
                                  frame.origin.y -= _lzb_keyBoard_DefaultMargin;
                                  weakSelf.view.frame = frame;
       } completion:nil];
  }
}

其中有个递归查找响应者的方法,比较简单,就不细说

 - (UIView *)findFirstResponderWithView:(UIView *)view
 {
  if(self.isFirstResponder)
   return self.view;
for (UIView *subView in view.subviews)
{
    if(subView.isFirstResponder)
        return subView;
    else
        continue;
}
return view;

}

3、键盘隐藏调用通知方法

  - (void)keyboardWillHide:(NSNotification *)notification
 {
 //获取键盘的参数
CGFloat keyboardAnimaitonDuration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] floatValue];
NSInteger option = [notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];
 __weak UIViewController *weakSelf = self;
//滚动动画
[UIView animateWithDuration:keyboardAnimaitonDuration
                      delay:0
                    options:option
                 animations:^{
                     CGRect frame = weakSelf.view.frame;
                     frame.origin.y += _lzb_keyBoard_DefaultMargin;
                     weakSelf.view.frame = frame;
                 }
                 completion:nil];
//注意:一定要清0,因为不知道下一次响应者是位置
 _lzb_keyBoard_DefaultMargin = 0;
}

4.额外小功能,点击任意地方取消键盘响应

 - (void)lzb_addKeyBoardTapAnyAutoDismissKeyBoard
{
UITapGestureRecognizer *lzbTap = [[UITapGestureRecognizer alloc] initWithTarget:self                                                                 action:@selector(tapAnywhereToDismissKeyboard:)];
NSOperationQueue *mainQuene =[NSOperationQueue mainQueue];
 __weak UIViewController *weakSelf = self;
_keyboardWillShowObser=[[NSNotificationCenter defaultCenter]
                       addObserverForName:UIKeyboardWillShowNotification
                                   object:nil
                                    queue:mainQuene
                               usingBlock:^(NSNotification * _Nonnull note) {
                            [weakSelf.view addGestureRecognizer:lzbTap];
                        }];  
  _keyboardWillHideObser = [[NSNotificationCenter defaultCenter]
                        addObserverForName:UIKeyboardWillHideNotification
                                    object:nil
                                     queue:mainQuene
                                usingBlock:^(NSNotification *note){
                       [weakSelf.view removeGestureRecognizer:lzbTap];
                      }];
     }
#pragma mark - handel
- (void)tapAnywhereToDismissKeyboard:(UIGestureRecognizer *)gestureRecognizer {
[self.view endEditing:YES];
 }

demo中还有其他功能,您的项目需要什么功能就用这么,本文中讲功能只要以下文件就好


本文功能文件.png

详情代码请直接下载demo查看:
自定义键盘-LZBKeyBoardView

最后赠言###

star 是对我们程序猿最大的鼓励!

上一篇 下一篇

猜你喜欢

热点阅读