ios --键盘监听JYKeyBoardListener

Posted 有棱角的圆

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ios --键盘监听JYKeyBoardListener相关的知识,希望对你有一定的参考价值。

 

没有前言,就是一个简单的键盘监听,自动调整输入框的位置不被键盘遮挡

 


 

.h

//
//  JYKeyBoardListener.h
//
//  Created by JianF.Sun on 17/9/26.
//  Copyright ? 2017年 sjf. All rights reserved.
//
/*
 功能:
 1、输入框被键盘遮挡时,整个view上移(此时输入框在键盘上方)
 2、键盘弹出时,添加一个按钮负责隐藏键盘
 3、禁止某控制器使用JYKeyBoardListener
 使用:
 1、引入JYKeyBoardListener.h
 2、程序启动时:[JYKeyBoardListener useJYKeyboardListener];
 3、某些控制器不想使用时:[JYKeyBoardListener unUsedIn:vc];
 处理:
 1、监听键盘 显示,隐藏,退到后台,进入前台;
 2、获取当前顶层控制器;
 3、获取当前编辑的输入框在self.view中的frame;
 4、键盘显示隐藏时动画;
 5、隐藏键盘的按钮添加
 6、处理push、present时键盘的显示隐藏问题(切记push之前,代码endEditing,因为push操作系统不会自动退出键盘)
 7、处理self.view比屏幕小的问题(即self.view没有伸缩到导航栏底部)
 8、处理输入框显示在屏幕中不完整的情况
 
 */
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface JYKeyBoardListener : NSObject
//程序启动时调用
+ (void)useJYKeyboardListener;
//在viewcontroller中禁止使用JYKeyBoardListener
+ (void)unUsedIn:(UIViewController*)viewController;
@end

.m

//
//  JYKeyBoardListener.m
//
//  Created by JianF.Sun on 17/9/26.
//  Copyright ? 2017年 sjf. All rights reserved.
//

#import "JYKeyBoardListener.h"

#define KBL_Screen_Height [UIScreen mainScreen].bounds.size.height

NSString * const JYKeyboard_Unused_Key= @"JYKeyboard_Unused_Key";

@interface JYKeyBoardListener ()
@property (nonatomic,strong) UIView *inputView;
@property (nonatomic,strong) UIButton *resignBtn;
@property (nonatomic,strong) UIView *lastView;//记录之前一个需要处理的view,解决push,present操作时,键盘的隐藏问题
//@property (nonatomic,strong) UIViewController *unUsedVC;

@end
@implementation JYKeyBoardListener

#pragma mark - 接口方法,直接调用即可
+ (void)useJYKeyboardListener{
    
    [JYKeyBoardListener shareJYKeyBoardListener];
}
+ (void)unUsedIn:(UIViewController*)viewController{
    
    JYKeyBoardListener *manager = [JYKeyBoardListener shareJYKeyBoardListener];
    [[NSUserDefaults standardUserDefaults] setValue:[manager getMemory:viewController] forKey:JYKeyboard_Unused_Key];
}

#pragma mark - 单例

+ (instancetype)shareJYKeyBoardListener {
    
    static JYKeyBoardListener *jyKeyBoardListener = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        jyKeyBoardListener = [[JYKeyBoardListener alloc] init];
        // 监听键盘

        [[NSNotificationCenter defaultCenter] addObserver:jyKeyBoardListener selector:@selector(keyboardWillShowAction:) name:UIKeyboardWillShowNotification object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:jyKeyBoardListener selector:@selector(keyboardWillHideAction:) name:UIKeyboardWillHideNotification object:nil];
        
        [[NSNotificationCenter defaultCenter] addObserver:jyKeyBoardListener selector:@selector(enterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:jyKeyBoardListener selector:@selector(enterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
    });
    
    return jyKeyBoardListener;
}


#pragma mark - 键盘显示和隐藏的监听方法
/**
 *  键盘即将弹出
 */
- (void)keyboardWillShowAction:(NSNotification *)note{
    
    if ([self currentMemory]!=nil&&[[self currentMemory] isEqualToString:[self getMemory:[self topViewController]]]) {
        [self addResignBtn:[self topViewController].view];
        return;
    }else{
        [[NSUserDefaults standardUserDefaults] setValue:nil forKey:JYKeyboard_Unused_Key];
    }
    
    //结束时键盘的frame
    CGRect endF = [note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    //键盘高度
    CGFloat keyboardH = endF.size.height;
    //键盘弹出需要的时间
    CGFloat duration = [note.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    //当前的view
    UIView *firstRspView = [self findFirstResponsderView];
    
    if (firstRspView==nil) {
        //        NSLog(@"为空");
        return ;
    }
    //找到输入框
    [self findSubView:firstRspView];

    //获取输入框相对于当前展示的最底层的那个view的frame
    CGRect inputFrame = [self getAbsoluteFrame:self.inputView];
    //
    CGFloat difH = CGRectGetMaxY(inputFrame)-(KBL_Screen_Height-keyboardH);
    // 2.动画
    [UIView animateWithDuration:duration animations:^{
        
        if (difH>0) {
            
            firstRspView.transform = CGAffineTransformMakeTranslation(0,-difH);
            
        }else{
            firstRspView.transform = CGAffineTransformIdentity;
            
        }
        _lastView = firstRspView;
    }completion:^(BOOL finished) {
        [self addResignBtn:firstRspView];

    } ];
}
/**
 *  键盘即将隐藏
 */
- (void)keyboardWillHideAction:(NSNotification *)note{
    
    //判断当前控制器是否被禁用
    if ([self currentMemory]!=nil&&[[self currentMemory] isEqualToString:[self getMemory:[self topViewController]]]) {
        
        return;
    }else{
        [[NSUserDefaults standardUserDefaults] setValue:nil forKey:JYKeyboard_Unused_Key];
    }
    // 1.键盘弹出需要的时间
    CGFloat duration = [note.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    UIView *firstRspView = [self findFirstResponsderView];

    if(firstRspView==nil){
        return;
    }
    if (_lastView&&_lastView!=firstRspView) {//处理跳转时恢复之前的,push之前必须

        _lastView.transform = CGAffineTransformIdentity;
        _lastView = nil;
        return;
    }
    // 2.动画
    [UIView animateWithDuration:duration animations:^{
        firstRspView.transform = CGAffineTransformIdentity;
        
    }completion:^(BOOL finished) {

    }];

}


#pragma mark - 前台后台切换处理
- (void)enterBackground:(NSNotification*)note{
    [[self findFirstResponsderView] endEditing:YES];
}
- (void)enterForeground:(NSNotification*)note{
    
}
#pragma mark - 隐藏键盘按钮
- (void)addResignBtn:(UIView*)firstRspView{
    if (self.resignBtn) {
        [self.resignBtn removeFromSuperview];
    }
    self.resignBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    self.resignBtn.backgroundColor = [UIColor clearColor];
    [self.resignBtn addTarget:self action:@selector(hideKeyboard) forControlEvents:UIControlEventTouchUpInside];
    self.resignBtn.frame = firstRspView.bounds;
    [firstRspView addSubview:self.resignBtn];
    [firstRspView sendSubviewToBack:self.resignBtn];
}
- (void)hideKeyboard{
    [[self findFirstResponsderView] endEditing:YES];
    dispatch_async(dispatch_get_main_queue(), ^{
        [self.resignBtn removeFromSuperview];

    });
}
#pragma mark - 其他辅助性方法
/**
 查找根控制器的view

 @return return FirstResponsderView
 */
- (UIView*)findFirstResponsderView{
    
    UIViewController *returnVC;
    
    //查找当前的根控制器
    returnVC = [self topViewController];
    if (returnVC) {
        return returnVC.view;
    }else{
        return nil;
    }
}
// 获取当前屏幕显示的ViewController
- (UIViewController *)topViewController {
    UIViewController *resultVC;
    resultVC = [self _topViewController:[[UIApplication sharedApplication].keyWindow rootViewController]];
    while (resultVC.presentedViewController) {
        resultVC = [self _topViewController:resultVC.presentedViewController];
    }
    return resultVC;
}

- (UIViewController *)_topViewController:(UIViewController *)vc {
    if ([vc isKindOfClass:[UINavigationController class]]) {
        return [self _topViewController:[(UINavigationController *)vc topViewController]];
    } else if ([vc isKindOfClass:[UITabBarController class]]) {
        return [self _topViewController:[(UITabBarController *)vc selectedViewController]];
    } else {
        return vc;
    }
    return nil;
}


/*
 获取输入框的相对于根控制器view的frame
 */
- (CGRect)getAbsoluteFrame:(UIView*)view{
    
    UIView *mainView = [self findFirstResponsderView];
    UIWindow *window = [UIApplication sharedApplication].keyWindow;
    CGRect rect=[view convertRect: view.bounds toView:mainView];
    //处理导航栏问题
    if (CGRectGetHeight(mainView.bounds)<CGRectGetHeight(window.bounds)) {
        rect.origin.y += CGRectGetHeight(window.bounds)-CGRectGetHeight(mainView.bounds);
    }
    //滚动视图返回的frame去掉scrollView.contentOffset.y
    if ([mainView isKindOfClass:[UIScrollView class]]||[mainView isKindOfClass:[UITableView class]]||[mainView isKindOfClass:[UIWebView class]]) {
        UIScrollView *scrollView = (UIScrollView*)mainView;
        rect.origin.y -=scrollView.contentOffset.y;
        if (CGRectGetMaxY(rect)>KBL_Screen_Height) {//输入框没有完全显示出来
            
            //去掉屏幕外的高度值
            rect.origin.y-=CGRectGetMaxY(rect)-KBL_Screen_Height;
        }
    }
    
    return rect;
}

/*
 递归法
 找到输入框
 */
- (void)findSubView:(UIView*)view{
    
    for (UIView *subView in view.subviews){

        if ([subView isFirstResponder]) {
//            NSLog(@"找到输入框");
            self.inputView = subView;
        }else{
            [self findSubView:subView];
        }
    }
}


- (NSString*)getMemory:(UIViewController*)vc{
    //控制器名称+内容的内存地址+view的内容地址
    return [NSString stringWithFormat:@"jykeyboard%@%p%p",NSStringFromClass([vc class]),vc,vc.view];
}
- (NSString*)currentMemory{
    return [[NSUserDefaults standardUserDefaults] valueForKey:JYKeyboard_Unused_Key];
}
@end

 

以上是关于ios --键盘监听JYKeyBoardListener的主要内容,如果未能解决你的问题,请参考以下文章

四种IO模型‘阻塞IO/非阻塞IO/信号驱动IO/异步IO‘

5种IO模型阻塞IO和非阻塞IO同步IO和异步IO

网络IO模型:同步IO和异步IO,阻塞IO和非阻塞IO

同步IO异步IO阻塞IO非阻塞IO之间的联系与区别

同步IO异步IO阻塞IO非阻塞IO之间的联系与区别

iOS 自动布局 ios 7 与 ios 8