iOS 键盘遮挡问题 (自动上移UI)

分享一个写好的类。解决键盘出现 遮挡住界面的问题。现在让UI自动上移一些,能更好显示

1.  .H文件

#import <Foundation/Foundation.h>

#import <UIKit/UIKit.h>

typedef enum {

    KeyboardActionDefault,

    KeyboardActionShow,

    KeyboardActionHide

}KeyboardAction

@protocol KeyboardUtilProtocol- (void)adaptiveViewHandleWithAdaptiveView:(UIView *)adaptiveView, ...NS_REQUIRES_NIL_TERMINATION;

- (void)adaptiveViewHandleWithController:(UIViewController *)viewController adaptiveView:(UIView *)adaptiveView, ...NS_REQUIRES_NIL_TERMINATION;

@end

#pragma mark - KeyboardInfo(model)

@interface KeyboardInfo : NSObject

@property (assign, nonatomic) CGFloat animationDuration;

@property (assign, nonatomic) CGRect frameBegin;

@property (assign, nonatomic) CGRect frameEnd;

@property (assign, nonatomic) CGFloat heightIncrement;

@property (assign, nonatomic) KeyboardAction action;

@property (assign, nonatomic) BOOL isSameAction;

- (void)fillKeyboardInfoWithDuration:(CGFloat)duration frameBegin:(CGRect)frameBegin frameEnd:(CGRect)frameEnd heightIncrement:(CGFloat)heightIncrement action:(KeyboardAction)action isSameAction:(BOOL)isSameAction;

@end

#pragma mark - ZYKeyboardUtil

@interface ZYKeyboardUtil : NSObject

typedef void (^animateWhenKeyboardAppearBlock)(int appearPostIndex, CGRect keyboardRect, CGFloat keyboardHeight, CGFloat keyboardHeightIncrement);

typedef void (^animateWhenKeyboardDisappearBlock)(CGFloat keyboardHeight);

typedef void (^printKeyboardInfoBlock)(ZYKeyboardUtil *keyboardUtil, KeyboardInfo *keyboardInfo);

typedef void (^animateWhenKeyboardAppearAutomaticAnimBlock)(ZYKeyboardUtil *keyboardUtil);

- (void)setAnimateWhenKeyboardAppearBlock:(animateWhenKeyboardAppearBlock)animateWhenKeyboardAppearBlock;

- (void)setAnimateWhenKeyboardAppearAutomaticAnimBlock:(animateWhenKeyboardAppearAutomaticAnimBlock)animateWhenKeyboardAppearAutomaticAnimBlock;

- (void)setAnimateWhenKeyboardDisappearBlock:(animateWhenKeyboardDisappearBlock)animateWhenKeyboardDisappearBlock;

- (void)setPrintKeyboardInfoBlock:(printKeyboardInfoBlock)printKeyboardInfoBlock;

@end

#pragma mark - UIView+Utils

@interface UIView (Utils)

- (void)findControllerWithResultController:(UIViewController **)resultController;

@end

2.  .M文件

#import "ZYKeyboardUtil.h"

#define MARGIN_KEYBOARD_DEFAULT 10

#define TEXTVIEW_NO_ANIM_BEGIN if ([_adaptiveView isKindOfClass:[UITextView class]]) {\

                                [CATransaction begin];\

                                [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];\

                                }

#define TEXTVIEW_NO_ANIM_END if ([_adaptiveView isKindOfClass:[UITextView class]]) {\

                                [CATransaction commit];\

                                }

@interface ZYKeyboardUtil()

@property (assign, nonatomic) BOOL keyboardObserveEnabled;

@property (assign, nonatomic) int appearPostIndex;

@property (strong, nonatomic) KeyboardInfo *keyboardInfo;

@property (assign, nonatomic) BOOL haveRegisterObserver;

@property (weak, nonatomic) UIViewController *adaptiveController;

@property (weak, nonatomic) UIView *adaptiveView;

@property (strong, nonatomic) NSValue *prepareRectValue;

@property (copy, nonatomic) animateWhenKeyboardAppearBlock animateWhenKeyboardAppearBlock;

@property (copy, nonatomic) animateWhenKeyboardAppearAutomaticAnimBlock animateWhenKeyboardAppearAutomaticAnimBlock;

@property (copy, nonatomic) animateWhenKeyboardDisappearBlock animateWhenKeyboardDisappearBlock;

@property (copy, nonatomic) printKeyboardInfoBlock printKeyboardInfoBlock;

@end

@implementation ZYKeyboardUtil

- (void)dealloc {

    [[NSNotificationCenter defaultCenter] removeObserver:self];

}

#pragma mark - lazy注册观察者

- (void)registerObserver {

    if (_haveRegisterObserver == YES) {

        return;

    }

    self.haveRegisterObserver = YES;

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];

}

- (void)adaptiveViewHandleWithController:(UIViewController *)viewController adaptiveView:(UIView *)adaptiveView, ...NS_REQUIRES_NIL_TERMINATION {

    NSMutableArray *adaptiveViewList = [NSMutableArray array];

    [adaptiveViewList addObject:adaptiveView];


    va_list var_list;

    va_start(var_list, adaptiveView);

    UIView *view;

    while ((view = va_arg(var_list, UIView *))) {

        [adaptiveViewList addObject:view];

    }

    va_end(var_list);


    self.adaptiveController = viewController;

    for (UIView *adaptiveViews in adaptiveViewList) {

        UIView *firstResponder = nil;

        [self recursionTraverseFindFirstResponderIn:adaptiveViews responder:&firstResponder];

        if (nil != firstResponder) {

            self.adaptiveView = firstResponder;

            [self fitKeyboardAutomatically:firstResponder controllerView:viewController.view keyboardRect:_keyboardInfo.frameEnd];

            break;

        }

    }

}

- (void)adaptiveViewHandleWithAdaptiveView:(UIView *)adaptiveView, ...NS_REQUIRES_NIL_TERMINATION {

    NSMutableArray *adaptiveViewList = [NSMutableArray array];

    [adaptiveViewList addObject:adaptiveView];


    va_list var_list;

    va_start(var_list, adaptiveView);

    UIView *view;

    while ((view = va_arg(var_list, UIView *))) {

        [adaptiveViewList addObject:view];

    }

    va_end(var_list);


    UIViewController *adaptiveController;

    [adaptiveView findControllerWithResultController:&adaptiveController];

    if (adaptiveController) {

        self.adaptiveController = adaptiveController;

    } else {

        LOG(@"\nERROR: Can not find adaptiveView`s Controller");

        return;

    }

    for (UIView *adaptiveViews in adaptiveViewList) {

        UIView *firstResponder = nil;

        [self recursionTraverseFindFirstResponderIn:adaptiveViews responder:&firstResponder];

        if (nil != firstResponder) {

            self.adaptiveView = firstResponder;

            [self fitKeyboardAutomatically:firstResponder controllerView:adaptiveController.view keyboardRect:_keyboardInfo.frameEnd];

            break;

        }

    }

}

- (void)recursionTraverseFindFirstResponderIn:(UIView *)view responder:(UIView **)responder {

    if ([view isFirstResponder]) {

        *responder = view;

    } else {

        for (UIView *subView in view.subviews) {

            if ([subView isFirstResponder]) {

                *responder = subView;

                return;

            }

            [self recursionTraverseFindFirstResponderIn:subView responder:responder];

        }

    }

    return;

}

- (void)fitKeyboardAutomatically:(UIView *)adaptiveView controllerView:(UIView *)controllerView keyboardRect:(CGRect)keyboardRect {

    UIWindow *window = [[UIApplication sharedApplication] keyWindow];

    CGRect convertRect = [adaptiveView.superview convertRect:adaptiveView.frame toView:window];

    if (CGRectGetMinY(keyboardRect) - MARGIN_KEYBOARD_DEFAULT < CGRectGetMaxY(convertRect)) {

        //记住originFrame

        self.prepareRectValue = [NSValue valueWithCGRect:controllerView.frame];

        CGFloat signedDiff = CGRectGetMinY(keyboardRect) - CGRectGetMaxY(convertRect) - MARGIN_KEYBOARD_DEFAULT;

        //updateOriginY

        CGFloat newOriginY = CGRectGetMinY(controllerView.frame) + signedDiff;

        controllerView.frame = CGRectMake(controllerView.frame.origin.x, newOriginY, controllerView.frame.size.width, controllerView.frame.size.height);

    }

}

- (void)restoreKeyboardAutomatically {

    [self textViewHandle];

    if (_prepareRectValue) {

        self.adaptiveController.view.frame = [_prepareRectValue CGRectValue];

        _prepareRectValue = nil;

    }

}

- (void)textViewHandle {

    //还原时 textView可能会出现offset错乱现象

    if ([_adaptiveView isKindOfClass:[UITextView class]]) {

        [(UITextView *)_adaptiveView setContentOffset:CGPointMake(0, 0)];

    }

}

#pragma mark - 重写KeyboardInfo set方法,调用animationBlock

- (void)setKeyboardInfo:(KeyboardInfo *)keyboardInfo {

    //home键使应用进入后台也会有某些通知

    if([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {

        return;

    }

    _keyboardInfo = keyboardInfo;

    if(!keyboardInfo.isSameAction || (keyboardInfo.heightIncrement != 0)) {


        [UIView animateWithDuration:keyboardInfo.animationDuration animations:^{

            switch (keyboardInfo.action) {

                case KeyboardActionShow:

                    if(self.animateWhenKeyboardAppearBlock != nil) {

                        self.animateWhenKeyboardAppearBlock(++self.appearPostIndex, keyboardInfo.frameEnd, keyboardInfo.frameEnd.size.height, keyboardInfo.heightIncrement);

                    } else if (self.animateWhenKeyboardAppearAutomaticAnimBlock != nil) {

                        self.animateWhenKeyboardAppearAutomaticAnimBlock(self);

                    }

                    break;

                case KeyboardActionHide:

                    if(self.animateWhenKeyboardDisappearBlock != nil) {

                        self.animateWhenKeyboardDisappearBlock(keyboardInfo.frameEnd.size.height);

                        self.appearPostIndex = 0;

                    } else {

                        //auto restore

                        [self restoreKeyboardAutomatically];

                    }

                    break;

                default:

                    break;

            }

            [CATransaction commit];

        }completion:^(BOOL finished) {

            if(self.printKeyboardInfoBlock != nil && self.keyboardInfo != nil) {

                self.printKeyboardInfoBlock(self, keyboardInfo);

            }

        }];

    }

}

- (void)triggerAction {

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

        self.keyboardInfo = _keyboardInfo;

    });

}

#pragma mark - 重写Block set方法,懒加载方式注册观察者

/**

* @brief handle the covering event youself when keyboard Appear, Animation automatically.

*

* use animateWhenKeyboardAppearBlock, animateWhenKeyboardAppearAutomaticAnimBlock will be invalid.

*/

- (void)setAnimateWhenKeyboardAppearBlock:(animateWhenKeyboardAppearBlock)animateWhenKeyboardAppearBlock {

    _animateWhenKeyboardAppearBlock = animateWhenKeyboardAppearBlock;

    [self registerObserver];

}

/**

* @brief handle the covering automatically, you must invoke the method adaptiveViewHandleWithController:adaptiveView: by the param keyboardUtil.

*

* use animateWhenKeyboardAppearAutomaticAnimBlock, animateWhenKeyboardAppearBlock must be nil.

*/

- (void)setAnimateWhenKeyboardAppearAutomaticAnimBlock:(animateWhenKeyboardAppearAutomaticAnimBlock)animateWhenKeyboardAppearAutomaticAnimBlock {

    _animateWhenKeyboardAppearAutomaticAnimBlock = animateWhenKeyboardAppearAutomaticAnimBlock;

    [self registerObserver];

}

/**

* @brief restore the UI youself when keyboard disappear.

*

* if not configure this Block, automatically itself.

*/

- (void)setAnimateWhenKeyboardDisappearBlock:(animateWhenKeyboardDisappearBlock)animateWhenKeyboardDisappearBlock {

    _animateWhenKeyboardDisappearBlock = animateWhenKeyboardDisappearBlock;

    [self registerObserver];

}

- (void)setPrintKeyboardInfoBlock:(printKeyboardInfoBlock)printKeyboardInfoBlock {

    _printKeyboardInfoBlock = printKeyboardInfoBlock;

    [self registerObserver];

}

- (void)setPrepareRectValue:(NSValue *)prepareRectValue {

    //为nil时才设置

    if (!_prepareRectValue) {

        _prepareRectValue = prepareRectValue;

    }

}

#pragma mark 响应selector

- (void)keyboardWillShow:(NSNotification *)notification {

    [self handleKeyboard:notification keyboardAction:KeyboardActionShow];

}

- (void)keyboardWillChangeFrame:(NSNotification *)notification {

    if(self.keyboardInfo.action == KeyboardActionShow){

        //[self handleKeyboard:notification keyboardAction:KeyboardActionShow];

    }

}

- (void)keyboardWillHide:(NSNotification *)notification {

    [self handleKeyboard:notification keyboardAction:KeyboardActionHide];

}

- (void)keyboardDidHide:(NSNotification *)notification {

    //置空

    self.keyboardInfo = nil;

}

#pragma mark 处理键盘事件

- (void)handleKeyboard:(NSNotification *)notification keyboardAction:(KeyboardAction)keyboardAction {

    //进入后台触发某些通知,不响应

    if([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {

        return;

    }

    //解析通知

    NSDictionary *infoDict = [notification userInfo];

    CGRect frameBegin = [[infoDict objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];

    CGRect frameEnd = [[infoDict objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];


    CGFloat previousHeight;

    if(self.keyboardInfo.frameEnd.size.height > 0) {

        previousHeight = self.keyboardInfo.frameEnd.size.height;

    }else {

        previousHeight = 0;

    }


    CGFloat heightIncrement = frameEnd.size.height - previousHeight;

    BOOL isSameAction;

    if(self.keyboardInfo.action == keyboardAction) {

        isSameAction = YES;

    }else {

        isSameAction = NO;

    }

    KeyboardInfo *info = [[KeyboardInfo alloc] init];

    [info fillKeyboardInfoWithDuration:DURATION_ANIMATION frameBegin:frameBegin frameEnd:frameEnd heightIncrement:heightIncrement action:keyboardAction isSameAction:isSameAction];

    self.keyboardInfo = info;

}

- (void)fillKeyboardInfoWithKeyboardInfo:(KeyboardInfo *)keyboardInfo duration:(CGFloat)duration frameBegin:(CGRect)frameBegin frameEnd:(CGRect)frameEnd heightIncrement:(CGFloat)heightIncrement action:(KeyboardAction)action isSameAction:(BOOL)isSameAction {

    keyboardInfo.animationDuration = duration;

    keyboardInfo.frameBegin = frameBegin;

    keyboardInfo.frameEnd = frameEnd;

    keyboardInfo.heightIncrement = heightIncrement;

    keyboardInfo.action = action;

    keyboardInfo.isSameAction = isSameAction;

}

@end

#pragma mark - KeyboardInfo(model)

@interface KeyboardInfo()

- (void)fillKeyboardInfoWithDuration:(CGFloat)duration frameBegin:(CGRect)frameBegin frameEnd:(CGRect)frameEnd heightIncrement:(CGFloat)heightIncrement action:(KeyboardAction)action isSameAction:(BOOL)isSameAction;

@end

@implementation KeyboardInfo

- (void)fillKeyboardInfoWithDuration:(CGFloat)duration frameBegin:(CGRect)frameBegin frameEnd:(CGRect)frameEnd heightIncrement:(CGFloat)heightIncrement action:(KeyboardAction)action isSameAction:(BOOL)isSameAction {

    self.animationDuration = duration;

    self.frameBegin = frameBegin;

    self.frameEnd = frameEnd;

    self.heightIncrement = heightIncrement;

    self.action = action;

    self.isSameAction = isSameAction;

}

@end

#pragma mark - UIView+Utils

@implementation UIView (Utils)

- (void)findControllerWithResultController:(UIViewController **)resultController {

    UIResponder *responder = [self nextResponder];

    if (nil == responder) {

        return;

    }

    if ([responder isKindOfClass:[UIViewController class]]) {

        *resultController = (UIViewController *)responder;

    } else if ([responder isKindOfClass:[UIView class]]) {

        [(UIView *)responder findControllerWithResultController:resultController];

    }

}

@end


3. 如何使用

#pragma mark - ========== 键盘遮挡问题 ==========

#pragma mark 键盘弹出

- (void)configKeyBoardRespond

{

    self.keyboardUtil = [[ZYKeyboardUtil alloc] init];

    __weak JHmessageLoginVC *weakSelf = self;

    //增加需要避免遮挡的控件

    [_keyboardUtil setAnimateWhenKeyboardAppearAutomaticAnimBlock:^(ZYKeyboardUtil *keyboardUtil) {

        [keyboardUtil adaptiveViewHandleWithController:weakSelf adaptiveView:weakSelf.bgView,nil];

    }];

}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容