zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    [转] C# DataTable 导出 Excel 进阶 多行表头、合并单元格、中文文件名乱码
    【转】sql语句精选二
    【转】sqlserver游标概念与实例全面解说
    按多个关键字查询(sql)
    Asp.net使用repeater控件动态添加、删除一行
    SQL SERVER 导入、导出数据到Exce(使用OpenRowset,、OpenDataSource函数)以及访问远程数据库(openrowset/opendatasource/openquery)
    对 Dflying Chen 提到的Edit GridView Using CheckBoxes 进行一个小改造
    软件开发专业技术名词的解释
    (总结)如何为windows服务添加安装程序
    软件开发过程(RUP概述) 转
  • 原文地址:https://www.cnblogs.com/sunjianfei/p/7840317.html
Copyright © 2011-2022 走看看