【iOS开发】 键盘遮挡解决方案

10.28
实际使用中出现了很多意外的情况,并不像自己想像的那么简单,已经放弃这种方法的使用。建议使用:TPKeyboardAvoiding

一、历程

键盘遮挡这个问题在每个应用中几乎都会遇到。在解决这个问题的时候,大致经过了两个阶段:
<1> 人工配置,如果测试中发现被遮挡,就通过notification的方法把对视图做一下调整。 这个方法很低效,效果也一般。
<2> 我想到去找一下其他人的解决方案,发现基本有下面种方案:
(1) 和第一种一样,人式配置,然后学到的一点改进是可以不必添加UIKeyboardWillShowNotificationUIKeyboardWillHideNotification两个通知,而只要添加UIKeyboardWillChangeFrame 这个通知来调整视图。
(2) 通过自定义视图的方法来避免这种情况,即是这个git上项目的方法(star数挺高的,应该比较靠谱):TPKeyboardAvoiding,它给出的方案中给出了四个自定义的view:TPKeyboardAvoidingScrollView,TPKeyboardAvoidingTableView,TPKeyboardAvoidingTextField,TPKeyboardAvoidingTextView,只要继承自他的view,这个视图就会自动去避免遮挡视图。
这个方法我没有进行仔细的研究,因为我看了他的demo,感觉效果并不是很好,主要是因为自己一直有个想法,想用自己的方法来解决这个问题。所以对他的方法没有仔细研究,下面说说自己的想法和实现。

二、自己的实现

  1. 思路

我的思路其实想起来还是比较简单的.首先,现在大部分人开发的时候都会有一个BaseViewController 来对一些常用的属性进行设置,所以,我就想通过判断firstResponder,即输入时的UItextField 或者 UITextView 会不会被键盘遮挡来调整viewcontroller的view的位置,如果被遮挡,就让其向上偏移,再加上其他一些细节的调整,应该就可以实现传说中的零代码实现避免键盘遮挡(呵呵).

  1. 实现
    <1>首先中找到当前的firstResponder ,我是通知递归的方式来找到在当前viewcontroller的view上的第一响应者。另外有种比较简单的方式:
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];UIView *firstResponder = [keyWindow performSelector:@selector(firstResponder)];  

但是这个方法是私有方法,审核是通不过的。下面是递归的方法:

- (UIView *)findFirstResponderForView:(UIView *)view
{
    if (view.isFirstResponder) {
        return view;
    }
    if (view.subviews.count > 0) {

        for (UIView *obj in view.subviews) {
            UIView *firstResponder = [self findFirstResponderForView:obj];
            if (firstResponder != nil) {
                return firstResponder;
            }
        }
    }
    
    return nil;
}

<2> 然后是willShow的方法

- (void)keyboardWillShowHandle:(NSNotification *)notify
{
    CGFloat kbHeight = [[notify.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;//获取键盘高度
    double duration = [[notify.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];//键盘动画时长

    UIView *firstResponder = [self findFirstResponderForView:self.view];//第一响应者
    UIView *superView = firstResponder.superview;
    
    CGPoint fixedOrigin = [superView convertPoint:firstResponder.frame.origin toView:self.view];
    float viewBottom = fixedOrigin.y + firstResponder.height;
    
    //若键盘没有遮挡住视图则不进行整个视图上移,  但是如果已经有偏移就把它移下来
//    duration = duration * _delta/kbHeight;
    [UIView animateWithDuration:duration animations:^{
        self.view.top = 0.0; //self.view.top 是UIVIew 的扩展,即self.view.frame.origin.x
    }];
     if (viewBottom + kbHeight < self.view.bottom) return;
    
     float offset = viewBottom + kbHeight - self.view.bottom + 30;
    
    /*这里将self.view向上偏移用了三种方法
     <1> 通过transform ,但是不行,整个view都不见了,偏移量也检查过是100多,不知道为什么.
     <2> 通过self.view.alignmentRectInsets,还是不行,这个属性是只读的
     <3> 通过frame来设置,目前来看没有什么问题
    */
    //当直接切换(键盘没有落下)第二个响应者,刚偏移的量会叠加
    if (self.view.top == 0) {
        _delta = offset;
    }else{
        _delta = _delta - offset;
    }
    
//    duration = duration * _delta/kbHeight;
    [UIView animateWithDuration:duration animations:^void(void){
        self.view.top -= _delta;
    }];
}

<3> willHide 的方法

- (void)keyboardWillHideHandle:(NSNotification *)notify
{
    double duration = [[notify.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    [UIView animateWithDuration:duration animations:^void(void){
        self.view.top += _delta;//_delta 是全局变量,方便回到原来位置,这里直接把self.view.top 设置为0也可以。
    }];
    _delta = 0.0;
}

<4> 上面是主要的代码:下面谈谈其他细节。
(1) 什么时候添加通知,什么时候移除通知
`通知会占用系统资源,所以为每个viewcontroller都添加这样的通知没有必要,所以我给BaseViewController添加了两个方法,一个添加通知,一个移除通知的方法。在某个viewcontroller需要避免遮挡的时候就给其添加通知,然后在-(void)dealloc方法中移除通知,其他情况对其没有影响。

三、总结
我觉得第二种方案也是一种比较好的方法,毕竟有那么多人用,问题可能都解决的差不多了。我这种方法我目前没发现什么问题,而且也比较方便。如果有什么问题,欢迎大家指正!

你可能感兴趣的:(【iOS开发】 键盘遮挡解决方案)