IQKeyboardManager 簡(jiǎn)單使用

IQKeyboardManager是一個(gè)自動(dòng)處理鍵盤(pán)彈出、隱藏的三方庫(kù),使用非常方便,只需要將庫(kù)引入工程即可使用,不需要做任何多余的設(shè)置,我們?cè)陧?xiàng)目中也不需要再單獨(dú)去監(jiān)聽(tīng)鍵盤(pán)的willShow和willHide了。

IQKeyboardManager類(lèi).png

IQKeyboardManager發(fā)展到今天已經(jīng)很成熟了,常見(jiàn)的Bug基本已經(jīng)解決了。我們今天就簡(jiǎn)單的記錄下IQKeyboardManager的使用和實(shí)現(xiàn)原理。

IQKeyboardManager屬性含義記錄

首先我們先簡(jiǎn)單記錄下常用的屬性設(shè)置含義,方便以后查詢(xún)

// 設(shè)置鍵盤(pán)自動(dòng)彈起
[self setEnable:YES];
// 設(shè)置鍵盤(pán)和輸入框之間的距離
[self setKeyboardDistanceFromTextField:10.0];
// 當(dāng)鍵盤(pán)彈起時(shí),點(diǎn)擊背景,鍵盤(pán)就會(huì)收回
[self setShouldResignOnTouchOutside:YES];
// 是否添加鍵盤(pán)上的toolBar
[self setEnableAutoToolbar:YES];
// 是否在toolBar顯示輸入框中的placeHoder
[self setShouldShowTextFieldPlaceholder:YES];
// 有多個(gè)輸入框時(shí),可以通過(guò)點(diǎn)擊Toolbar 上的“前一個(gè)”“后一個(gè)”按鈕來(lái)實(shí)現(xiàn)移動(dòng)到不同的輸入框
 [self setToolbarManageBehaviour:IQAutoToolbarBySubviews];
// 設(shè)置toolBar上的顏色文字顏色是否用戶(hù)自定義
[self setShouldToolbarUsesTextFieldTintColor:NO];

如果在整個(gè)項(xiàng)目中引入了IQKeyboardManager,而某一個(gè)UIViewController內(nèi)不使用IQKeyboardManager,可以如下設(shè)置:

 - (void) viewWillAppear: (BOOL)animated 
{
        //打開(kāi)鍵盤(pán)事件相應(yīng)
        [IQKeyboardManager sharedManager].enable = NO;
}
- (void) viewWillDisappear: (BOOL)animated
{
       //關(guān)閉鍵盤(pán)事件相應(yīng)
       [IQKeyboardManager sharedManager].enable = YES;
}

這樣我們就可以在這個(gè)UIViewController中自己添加代碼監(jiān)聽(tīng)系統(tǒng)的鍵盤(pán)通知。

如果在某個(gè)頁(yè)面,有多個(gè)TextField,而只有某一個(gè)TextField不需要IQ鍵盤(pán)上面的toolBar時(shí),只需要設(shè)置下其inputAccessoryView

// 如果需要針對(duì)某個(gè)textField,不需要鍵盤(pán)上的toolBar 可以單獨(dú)設(shè)置
textField.inputAccessoryView = [[UIView alloc] init];

IQKeyboardManager實(shí)現(xiàn)原理

我們先觀察下IQKeyboardManager的類(lèi)文件,就會(huì)發(fā)現(xiàn)核心代碼都在IQKeyboardManager.m這個(gè)類(lèi)中,其他的類(lèi)文件,基本是輔助類(lèi)。

在IQKeyboardManager.m的init方法中,我們看到它添加了鍵盤(pán)的彈出和消失通知,并且注冊(cè)了textField和textView的開(kāi)始編輯和結(jié)束編輯的通知

// 鍵盤(pán)將要彈出的通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
// 鍵盤(pán)將要隱藏的通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
// UITextField開(kāi)始編輯和結(jié)束編輯的通知
[self registerTextFieldViewClass:[UITextField class]
didBeginEditingNotificationName:UITextFieldTextDidBeginEditingNotification didEndEditingNotificationName:UITextFieldTextDidEndEditingNotification];
// UITextView開(kāi)始編輯和結(jié)束編輯的通知
[self registerTextFieldViewClass:[UITextView class]           didBeginEditingNotificationName:UITextViewTextDidBeginEditingNotification         didEndEditingNotificationName:UITextViewTextDidEndEditingNotification];

正是添加了這4個(gè)方法,IQKeyboardManager監(jiān)聽(tīng)到了一系列通知,并能在-(void)textFieldViewDidBeginEditing:(NSNotification*)notification方法中記錄下是哪個(gè)控件要開(kāi)始編輯,并需要鍵盤(pán)彈起
記錄輸入源.png

通過(guò)記錄下這個(gè)_textFieldView,IQKeyboardManager知道了輸入源原來(lái)的坐標(biāo)值,PlaceHolder等值并一一記錄下來(lái),方便在鍵盤(pán)發(fā)出willShow通知時(shí)去調(diào)整控件的坐標(biāo)。

也正是由于知道了這個(gè)輸入源_textFieldView,IQKeyboardManager才能在-(void)keyboardWillShow:(NSNotification*)aNotification方法中,

  1. _textFieldView 直接被添加到UIViewController中

借用響應(yīng)鏈原理的具體應(yīng)用[_textFieldView viewController]方法找到_textFieldView被添加進(jìn)了哪個(gè)UIViewController中

// 確定_textFieldView的下一個(gè)UIResponder是否為UIViewController,如果是UIViewController類(lèi),則返回
-(UIViewController*)viewController
{
    UIResponder *nextResponder =  self;
    do
    {
        nextResponder = [nextResponder nextResponder];
        if ([nextResponder isKindOfClass:[UIViewController class]])
            return (UIViewController*)nextResponder;
    } while (nextResponder != nil);
    return nil;
}

并通過(guò)topMostController確定該UIViewController是否是真的為_(kāi)textFieldView的所在的VC 。

-(UIViewController *)topMostController
{
    NSMutableArray *controllersHierarchy = [[NSMutableArray alloc] init];
    
    UIViewController *topController = self.window.rootViewController;
    
    if (topController)
    {
        [controllersHierarchy addObject:topController];
    }
    
    while ([topController presentedViewController])
    {
        
        topController = [topController presentedViewController];
        [controllersHierarchy addObject:topController];
    }
    
    UIResponder *matchController = [self viewController];
    
    while (matchController != nil && [controllersHierarchy containsObject:matchController] == NO)
    {
        do
        {
            matchController = [matchController nextResponder];
            
        } while (matchController != nil && [matchController isKindOfClass:[UIViewController class]] == NO);
    }
    
    return (UIViewController*)matchController;
}

如果確定了_textFieldView 只是直接被添加到UIViewController上,則rootViewRect記錄下該UIViewController原始坐標(biāo),如果有需要?jiǎng)t改變r(jià)ootViewRect的坐標(biāo)值,并在鍵盤(pán)消失時(shí)恢復(fù)該UIViewController到原始坐標(biāo)。

{
            //  +Positive or zero.
            if (move>=0)
            {
                rootViewRect.origin.y -= move;
                
                //  From now prevent keyboard manager to slide up the rootView to more than keyboard height. (Bug ID: #93)
                if (_preventShowingBottomBlankSpace == YES)
                {
                    rootViewRect.origin.y = MAX(rootViewRect.origin.y, MIN(0, -kbSize.height+keyboardDistanceFromTextField));
                }
                
                [self showLog:@"Moving Upward"];
                //  Setting adjusted rootViewRect
                [self setRootViewFrame:rootViewRect];
                _movedDistance = (_topViewBeginRect.origin.y-rootViewRect.origin.y);
            }
            //  -Negative
            else
            {
                CGFloat disturbDistance = CGRectGetMinY(rootViewRect)-CGRectGetMinY(_topViewBeginRect);
                
                //  disturbDistance Negative = frame disturbed. Pull Request #3
                //  disturbDistance positive = frame not disturbed.
                if(disturbDistance<0)
                {
                    rootViewRect.origin.y -= MAX(move, disturbDistance);
                    
                    [self showLog:@"Moving Downward"];
                    //  Setting adjusted rootViewRect
                    [self setRootViewFrame:rootViewRect];
                    _movedDistance = (_topViewBeginRect.origin.y-rootViewRect.origin.y);
                }
            }
        }

如果確定了_textFieldView 只是直接被添加到UIScrollView上,則
UIScrollView superView = (UIScrollView)[_textFieldView superviewOfClassType:[UIScrollView class]];記錄該UIScrollView為_(kāi)lastScrollView

else if(superScrollView)
    {
        _lastScrollView = superScrollView;
        _startingContentInsets = superScrollView.contentInset;
        _startingContentOffset = superScrollView.contentOffset;
        _startingScrollIndicatorInsets = superScrollView.scrollIndicatorInsets;
    }

利用UIScrollView的偏移量去主動(dòng)滑動(dòng)

superScrollView.contentOffset = CGPointMake(superScrollView.contentOffset.x, shouldOffsetY);

在鍵盤(pán)將要消失時(shí),由于我們已經(jīng)存儲(chǔ)的_lastScrollView就是添加_textFieldView的那個(gè)UIScrollView,所以就能恢復(fù)原始位置了,這樣就實(shí)現(xiàn)了_textFieldView隨鍵盤(pán)的彈出和消失而自動(dòng)調(diào)整了。

這里只是簡(jiǎn)單的分析了下輸入控件是UITextField,其被添加到UIScrollView 和 UIViewController中的場(chǎng)景,其他場(chǎng)景實(shí)現(xiàn)原理基本類(lèi)似,就不在寫(xiě)了。

如果你喜歡我的創(chuàng)作,請(qǐng)點(diǎn)贊! 你的贊是我繼續(xù)創(chuàng)作的動(dòng)力,謝謝!如果不喜歡,請(qǐng)留言,謝謝!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,036評(píng)論 4 61
  • [Configuration] [Pylon-Visual Studio-Windows] 配置:1.1. 項(xiàng)目屬...
    Iooooooo閱讀 767評(píng)論 0 1
  • 2017-9-03 周末 陰 箴言:你內(nèi)心所有的痛,源于你沒(méi)有釋?xiě)?以為自己故作堅(jiān)強(qiáng)可以無(wú)堅(jiān)不摧,沒(méi)想到是彈...
    挨餓的豬閱讀 803評(píng)論 2 1
  • 接連幾天就像個(gè)陀螺一樣連軸轉(zhuǎn),苦于找工作,苦于找自己。 保持內(nèi)心的堅(jiān)定,放低自己。 我反反復(fù)復(fù)勸誡自己:你是一個(gè)普...
    柳苑如生閱讀 227評(píng)論 0 0

友情鏈接更多精彩內(nèi)容