來自產(chǎn)品經(jīng)理的"簡單"需求一則
需求:在輸入身份證號碼的時候色解,彈出來的鍵盤是能夠切換到字母的九宮格數(shù)字鍵盤。(左邊原生系統(tǒng)晤锥,右邊需求)
步驟一:添加鍵盤監(jiān)控
? ? ? ?系統(tǒng)提供了notification監(jiān)聽鍵盤的出現(xiàn)和消失。Notification不僅可以監(jiān)聽鍵盤的狀態(tài)變化,還攜帶一些其它信息浑厚,鍵盤的位置股耽,大小信息,動畫類型等钳幅。
步驟二:處理監(jiān)聽事件
在回調(diào)函數(shù)我們首先需要找到的是當前鍵盤所在在window
[[UIApplication?sharedApplication]?windows]能夠獲取當前界面windows的數(shù)組物蝙。
? ? 系統(tǒng)鍵盤是在一個系統(tǒng)新建的級別最高的UIWindow上,我們只需要找到這個UIWindow 就可以敢艰,在這個window 上添加button,因此我們要的keyboard所在的UIWindow的名稱是UITextEffectsWindow诬乞。找到我們所需要的window之后糙箍,直接添加我們的button痰憎。在調(diào)試的過程中發(fā)現(xiàn),當前設(shè)置只在iOS9以下的系統(tǒng)起作用刹帕,在iOS9系統(tǒng)中添加的button會被keyboard所在的window覆蓋掉牡属。這是為什么呢票堵,再打印當前的windows發(fā)現(xiàn),當前的界面windows的結(jié)構(gòu)已經(jīng)與之前不一樣了湃望。
? ? ? 對比結(jié)構(gòu)發(fā)現(xiàn)在iOS9的系統(tǒng)中多了一個UIRemoteKeyboardWindow换衬,也就是現(xiàn)在最高級別的UIWindow是UIRemoteKeyboardWindow。因此keyboard所在的UIWindow也由之前的UITextEffectsWindow轉(zhuǎn)變?yōu)閁IRemoteKeyboardWindow证芭。
步驟三:處理第三方鍵盤
? ? ? 除了要適配iOS9的系統(tǒng)的情況下瞳浦,還存在另外一個問題。蘋果在iOS8及以上的系統(tǒng)支持第三方輸入法(搜狗輸入法)废士,現(xiàn)在很多人都下載使用了第三方的輸入法 叫潦,會出現(xiàn)什么問題。
? ? ?自定義的控件出現(xiàn)在不該出現(xiàn)的位置官硝,這個不是直接設(shè)置button的hidden屬性為YES呢矗蕊,不就解決問題了?所以關(guān)鍵問題如何判斷當前輸入法是否帶有第三方擴展輸入法氢架?解決的辦法有幾種:
禁用第三方輸入法
無論有沒有使用第三方輸入法傻咖,在APP中有關(guān)鍵盤的場景都禁用。一了百了岖研,簡單粗暴卿操。
查找第三方輸入法
? ? ? 第一種方法有點不太友好。我們需要的是有第三方輸入法符合要求就使用第三方孙援,沒有的就用采用自定義的害淤。 如何判斷當前用戶是否使用了第三方輸入法,如果使用了第三方輸入法 就設(shè)置button的hidden屬性為YES拓售。UITextInputMode:能夠得到當前系統(tǒng)的所有輸入法窥摄。[UITextInputModeactiveInputModes]得到其中的一個NSArray的數(shù)組。對比下在有第三方輸入法和沒有情況下數(shù)組的成員:
? ? ? 通過對比發(fā)現(xiàn)在有使用第三方輸入法擴展的時候就多了一個UIKeyboardExtensionInputMode础淤,通過這個mode來判斷是否使用了輸入法擴展崭放。這個mode包含的第三方輸入法的其它信息哨苛,版本號,或者通過keyValue來讀取輸入法名稱莹菱。
當然我們只需要判斷當前是否有引進第三方輸入法移国。如果有需要也可以通過條件過濾獲取當前第三方輸入法。
私有API
也有通過私有APP來獲取第三方輸入法的信息道伟,但是現(xiàn)在蘋果對使用私有API審核很嚴格迹缀,還是不建議了。
2016.7.11 更新
? ? 項目上線之后蜜徽,有用戶反饋貼上的“ABC”這個按鈕不會出現(xiàn)祝懂。隨機概率事件,不是必先的bug無法找到路徑拘鞋,再review了代碼之后并沒有找到解決方法砚蓬。猜測是iOS系統(tǒng)在繪制鍵盤的時候會將這個"ABC"按鈕覆蓋了。然而你并不能告訴產(chǎn)品經(jīng)理說盆色,bug無法解決灰蛙。她會告訴你是bug就肯定能找到解決方法的。你只能絞盡腦汁尋找解決辦法的隔躲。最終在平衡利弊之后采用的解決方案是用其他方式來替換當前"黏貼"方法摩梧。這里就需要提及UITextField的兩個屬性成員變量:inputView 和 inputAccessoryView,怎么理解這兩個成員變量呢宣旱?
? ? ? 從上面那張圖仅父,我們可以將鍵盤看成有兩部分組成(當然,鍵盤還會有其他的部分組成)浑吟,一個下面鍵盤部署笙纤,一個內(nèi)容框。相對應(yīng)的屬性就是上半部分是inputView组力,下半部分是inputAccessoryView省容。
? ? 我們調(diào)用的系統(tǒng)默認鍵盤的時候,我們看到的鍵盤view部分就是這個inputView + inputAccessoryView組成燎字。所以如果設(shè)置 textField.inputView = nil 腥椒,點擊textField是不會彈出鍵盤的,因為這個時候inputView = nil轩触。所以可以通過設(shè)置inputView和inputAccessoryView來自定義我們所需要顯示的視圖。
自定義鍵盤
自定義鍵盤就是鍵盤全部由客戶端代碼生成家夺,工作量巨大脱柱,下面是招行APP的例子:
UIView * keyboardView = /**/
textField.inputView =keyboardView;//輸入我們自定義的鍵盤
textField.inputAccessoryView = nil;
系統(tǒng)鍵盤+自定義
第一種方法能很好的解決問題,但是這個實現(xiàn)成本有點大拉馋,選擇一個較為輕量的方法:數(shù)字鍵盤還是使用系統(tǒng)的空間榨为,不改變textField.inputView 惨好,通過設(shè)置inputAccessoryView在鍵盤的頂部添加我們想要的視圖。
UIView * keyboardView = /**/
textField.inputAccessoryView =keyboardView;
? ? ? 這個inputAccessoryView是和鍵盤一起出現(xiàn)的随闺,不會再出現(xiàn)用戶切換不了輸入法的問題日川。如果用戶有安裝第三方鍵盤,這個inputAccessoryView也是會出現(xiàn)在鍵盤頂部矩乐。這個時候要注意隱藏龄句。
? ? ? 有時候會發(fā)現(xiàn)設(shè)置了inputAccessoryView = nil并沒有起作用,因為設(shè)置的時機不對散罕,除了在textFieldShouldBeginEditing函數(shù)中設(shè)置以外分歇,如果要確保為nil的話,可以用方法[textField reloadInputViews] 欧漱,該方法會重新繪制一遍鍵盤职抡,inputAccessoryView 就為空了。