UIWebview讓editable html切換鍵盤不失焦

最近在做app時(shí),需要內(nèi)置一個(gè)富文本編輯器,調(diào)研之后采用webView +editable html方案,寫demo時(shí)看起來挺簡(jiǎn)單,毫不猶豫得開始搞,卻發(fā)現(xiàn)在真正集成進(jìn)app時(shí)卻踩坑不少,真是啪啪打臉~

需求如下:在鍵盤上方,點(diǎn)擊按鈕時(shí)可以隨意切換到各種選擇區(qū),并保證webView不失焦,如下圖所示:

調(diào)研過程:

1. 最先想到得方案便是,點(diǎn)擊按鈕,關(guān)閉鍵盤,然后彈出自定義試圖。

比如表情選擇器。這種方案當(dāng)然可行,但比較麻煩,當(dāng)選擇完一個(gè)表情,此時(shí)html已經(jīng)處于失焦?fàn)顟B(tài),是沒辦法直接輸入進(jìn)html的,當(dāng)然你可以記錄失焦前的位置,然后使用document.exeCommand方法硬插入,同時(shí)還有一個(gè)問題是,切換試圖效果并不流暢,會(huì)有鍵盤關(guān)閉得過程,本來直接就可以輸入的,就因?yàn)榍袚Q鍵盤不能輸了,忍痛舍棄。

2. 接下來的想法便是,如何能讓切換鍵盤時(shí)不失焦。查看官方文檔獲得如下知識(shí)

2.1 keboard實(shí)際上是一個(gè)inputView,作為UIResponder類的屬性,每一個(gè)子類都是可以定制它的,只要重新定義inputView property為讀寫屬性,并重寫getter方法即可,系統(tǒng)本身可定制的UITextField和UITextView就是這么干的

This property is typically used to provide a view to replace the system-supplied keyboard that is presented for UITextField and UITextView objects.

The value of this read-only property is nil. A responder object that requires a custom view to gather input from the user should redeclare this property as read-write and use it to manage its custom input view. When the receiver becomes the first responder, the responder infrastructure presents the specified input view automatically.

2.2 若當(dāng)前試圖為第一響應(yīng)者,可以調(diào)用UIResponder的 reloadInputViews方法,強(qiáng)制刷新inputView以及inputAccessView。

You can use this method to refresh the custom input view or input accessory view associated with the current object when it is the first responder. The views are replaced immediately—that is, without animating them into place. If the current object is not the first responder, this method has no effect.

2.3 有了如上知識(shí),思路就有了,那修改UIWebView的inputView就可以了,操作之后發(fā)現(xiàn),鍵盤是可以自由切換得,但是失焦了,那也就是說輸入狀態(tài),webView不是第一響應(yīng)者,那肯定是內(nèi)部得子試圖了,最終通過代碼打印第一響應(yīng)者,發(fā)現(xiàn)其是一個(gè)叫UIWebBrowser的東西,這貨是繼承于UIView的,但是是內(nèi)部私有類,怎么辦?browser信息如下


UIWebBrowser description
3. 是時(shí)候使用runtime了。

3.1 要么替換掉UIWebBrowser類為我們自定義類;要么替換該類的inputView getter方法,然后在切換切換鍵盤時(shí)修改inputView即可,我采用第一種方案,這也符合蘋果官方文檔的做法,核心代碼如下:

- (void)_hackWebBrowserClass{
    // 此處想法是暫存最開始的inputView,實(shí)際證明并不需要
   // if ([UIWebViewHackishlyViewManager sharedInstance].originalKeyboardView == nil){
  //      [UIWebViewHackishlyViewManager sharedInstance].originalKeyboardView = self.inputView;
 //   }
    
    UIView *browserView = [self browserView];
    Class hackClass = objc_getClass(hackishFixClassName);
    // 如果還未生成自定義class,則生成;就是說還沒替換
    if (!hackClass) {
        hackClass = [self _hackishSubclassExists];
    }
    if (![browserView isMemberOfClass:hackClass]){
        if (hackClass){
            object_setClass(browserView, hackClass);
        }
    }
}
// 生成自定義類,其繼承于UIWebBrowser類
- (Class)_hackishSubclassExists {
    if (objc_getClass(hackishFixClassName)) return objc_getClass(hackishFixClassName);
    Class newClass = objc_allocateClassPair([[self browserView] class], hackishFixClassName, 0);
    
// 添加兩個(gè)getter方法;使用replace應(yīng)該也是可以的,可以試試
    IMP accessoryViewImp = [self methodForSelector:@selector(changedInputAccessoryView)];
    class_addMethod(newClass, @selector(inputAccessoryView), accessoryViewImp, "@@:");
    
    IMP inputViewImp = [self methodForSelector:@selector(changedInputView)];
    class_addMethod(newClass, @selector(inputView), inputViewImp, "@@:");
    objc_registerClassPair(newClass);
    
    return newClass;
}

3.2 中間繞了一個(gè)彎。當(dāng)需要切換回系統(tǒng)鍵盤時(shí),本來想把UIWebBrowser的實(shí)現(xiàn)替換為系統(tǒng)本身得實(shí)現(xiàn),但是這么干的話,可惡的inputAccessryView也隨著鍵盤一塊兒出來了,所以不能把類替換回去,那怎么辦呢?最終采用保存原始的inputView方式,當(dāng)需要切換回系統(tǒng)鍵盤時(shí),替換回去 【后來證明不需要這么做,如下代碼多余了】

代碼如下:


- (UIView*)changedInputView{

    UIView *view = [UIWebViewHackishlyViewManager sharedInstance].inputView;

    if(view)returnview;
    
    return [UIWebViewHackishlyViewManager sharedInstance].originalKeyboardView;

}

完整demo待整理后發(fā)出

小總結(jié):

經(jīng)此一役,再次感受到runtime的強(qiáng)大之處,可隨意修改私有類,私有方法(當(dā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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • ——讀《人工智能的未來》后感 未來以來,值得期待。近幾十年來,人工智能經(jīng)歷著從爆發(fā)到寒冬再到野蠻生長(zhǎng)的歷程,隨著人...
    卓木鳥在思考閱讀 478評(píng)論 0 2
  • 今天,我很愉快。 一大早起床,第一件事就是把昨晚整理好的文章《望峨臺(tái)補(bǔ)記》在簡(jiǎn)書上發(fā)了,并投了幾個(gè)專題。我不再投《...
    無為而字閱讀 687評(píng)論 12 14
  • 從前,你說中了我的毒,只有我可解?,F(xiàn)在,你中了手機(jī)的毒,無藥可解。 1 周末出門吃飯,隔壁桌坐著一對(duì)小情侶,等菜間...
    浮笙留白閱讀 537評(píng)論 0 0
  • 對(duì)不起,鳳姐!如果那天真像你所說的那樣我就像兩個(gè)人那么我也不用這么說,因?yàn)槲抑苯诱f就可以了。 ... ...
    泣靈_162b閱讀 228評(píng)論 0 0

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