iOS自定义数字键盘适配

来自产品经理的"简单"需求一则

需求:在输入身份证号码的时候,弹出来的键盘是能够切换到字母的九宫格数字键盘。(左边原生系统,右边需求)

iOS自定义数字键盘适配_第1张图片

步骤一:添加键盘监控

       系统提供了notification监听键盘的出现和消失。Notification不仅可以监听键盘的状态变化,还携带一些其它信息,键盘的位置,大小信息,动画类型等。

步骤二:处理监听事件

在回调函数我们首先需要找到的是当前键盘所在在window

[[UIApplication sharedApplication] windows]能够获取当前界面windows的数组。

    系统键盘是在一个系统新建的级别最高的UIWindow上,我们只需要找到这个UIWindow 就可以,在这个window 上添加button,因此我们要的keyboard所在的UIWindow的名称是UITextEffectsWindow。找到我们所需要的window之后,直接添加我们的button。在调试的过程中发现,当前设置只在iOS9以下的系统起作用,在iOS9系统中添加的button会被keyboard所在的window覆盖掉。这是为什么呢,再打印当前的windows发现,当前的界面windows的结构已经与之前不一样了。

      对比结构发现在iOS9的系统中多了一个UIRemoteKeyboardWindow,也就是现在最高级别的UIWindow是UIRemoteKeyboardWindow。因此keyboard所在的UIWindow也由之前的UITextEffectsWindow转变为UIRemoteKeyboardWindow。

iOS自定义数字键盘适配_第2张图片

步骤三:处理第三方键盘

      除了要适配iOS9的系统的情况下,还存在另外一个问题。苹果在iOS8及以上的系统支持第三方输入法(搜狗输入法),现在很多人都下载使用了第三方的输入法 ,会出现什么问题。

iOS自定义数字键盘适配_第3张图片

     自定义的控件出现在不该出现的位置,这个不是直接设置button的hidden属性为YES呢,不就解决问题了?所以关键问题如何判断当前输入法是否带有第三方扩展输入法?解决的办法有几种:

禁用第三方输入法

无论有没有使用第三方输入法,在APP中有关键盘的场景都禁用。一了百了,简单粗暴。

查找第三方输入法

      第一种方法有点不太友好。我们需要的是有第三方输入法符合要求就使用第三方,没有的就用采用自定义的。 如何判断当前用户是否使用了第三方输入法,如果使用了第三方输入法 就设置button的hidden属性为YES。UITextInputMode:能够得到当前系统的所有输入法。[UITextInputModeactiveInputModes]得到其中的一个NSArray的数组。对比下在有第三方输入法和没有情况下数组的成员:

iOS自定义数字键盘适配_第4张图片


iOS自定义数字键盘适配_第5张图片


iOS自定义数字键盘适配_第6张图片


iOS自定义数字键盘适配_第7张图片

      通过对比发现在有使用第三方输入法扩展的时候就多了一个UIKeyboardExtensionInputMode,通过这个mode来判断是否使用了输入法扩展。这个mode包含的第三方输入法的其它信息,版本号,或者通过keyValue来读取输入法名称。

iOS自定义数字键盘适配_第8张图片


iOS自定义数字键盘适配_第9张图片

当然我们只需要判断当前是否有引进第三方输入法。如果有需要也可以通过条件过滤获取当前第三方输入法。

私有API

也有通过私有APP来获取第三方输入法的信息,但是现在苹果对使用私有API审核很严格,还是不建议了。


2016.7.11 更新

    项目上线之后,有用户反馈贴上的“ABC”这个按钮不会出现。随机概率事件,不是必先的bug无法找到路径,再review了代码之后并没有找到解决方法。猜测是iOS系统在绘制键盘的时候会将这个"ABC"按钮覆盖了。然而你并不能告诉产品经理说,bug无法解决。她会告诉你是bug就肯定能找到解决方法的。你只能绞尽脑汁寻找解决办法的。最终在平衡利弊之后采用的解决方案是用其他方式来替换当前"黏贴"方法。这里就需要提及UITextField的两个属性成员变量:inputView 和 inputAccessoryView,怎么理解这两个成员变量呢?

iOS自定义数字键盘适配_第10张图片

      从上面那张图,我们可以将键盘看成有两部分组成(当然,键盘还会有其他的部分组成),一个下面键盘部署,一个内容框。相对应的属性就是上半部分是inputView,下半部分是inputAccessoryView。

    我们调用的系统默认键盘的时候,我们看到的键盘view部分就是这个inputView + inputAccessoryView组成。所以如果设置 textField.inputView = nil ,点击textField是不会弹出键盘的,因为这个时候inputView = nil。所以可以通过设置inputView和inputAccessoryView来自定义我们所需要显示的视图。

自定义键盘

自定义键盘就是键盘全部由客户端代码生成,工作量巨大,下面是招行APP的例子:

UIView * keyboardView = /**/

textField.inputView =keyboardView;//输入我们自定义的键盘

textField.inputAccessoryView = nil;


iOS自定义数字键盘适配_第11张图片
iOS自定义数字键盘适配_第12张图片

系统键盘+自定义

第一种方法能很好的解决问题,但是这个实现成本有点大,选择一个较为轻量的方法:数字键盘还是使用系统的空间,不改变textField.inputView ,通过设置inputAccessoryView在键盘的顶部添加我们想要的视图。

UIView * keyboardView = /**/

textField.inputAccessoryView =keyboardView;

iOS自定义数字键盘适配_第13张图片

      这个inputAccessoryView是和键盘一起出现的,不会再出现用户切换不了输入法的问题。如果用户有安装第三方键盘,这个inputAccessoryView也是会出现在键盘顶部。这个时候要注意隐藏。

iOS自定义数字键盘适配_第14张图片

      有时候会发现设置了inputAccessoryView = nil并没有起作用,因为设置的时机不对,除了在textFieldShouldBeginEditing函数中设置以外,如果要确保为nil的话,可以用方法[textField reloadInputViews] ,该方法会重新绘制一遍键盘,inputAccessoryView 就为空了。

你可能感兴趣的:(iOS自定义数字键盘适配)