美文网首页React NativeReactNativeReactNative开发
使用React Native自定义安全键盘(iOS和Androi

使用React Native自定义安全键盘(iOS和Androi

作者: 羽纱 | 来源:发表于2017-05-04 09:14 被阅读2901次

自定义键盘的实现效果如下:

iOS端:

ios-keyboard.gif
Android端:
android-keyboard.gif

npm仓库地址

react-native-yusha-customkeyboard

yarn add react-native-yusha-customkeyboard
react-native link

实现功能(iOS和Android):

  • 输入框没有自定义,直接使用RN的TextInput
  • 点击完成可以移除焦点
  • 长按回退键可以删除光标前所有字符
  • 字母和字符键盘点击会显示Tip
  • 字母、字符、数字键盘可相互快速切换(为视图做了懒加载和缓存)
  • 使用AwareCusKeyBoardScrollView自适应键盘弹出避免遮住输入框。

大致思路

1、如何隐藏系统键盘
用RN为iOS和Android双平台共用一套自定义键盘,使用RN的TextInput作为输入框,这样TextInput该怎么使用就怎么使用,因此问题的关键就在于如何隐藏系统键盘。在iOS中使用inputView可以轻松实现自定义键盘,在Android中自定义键盘并非像iOS那么直接,需要手动隐藏系统键盘,然后监听输入框的焦点事件来控制自定义键盘的显示和隐藏。
可以看以下两个示例大致了解下:
iOS自定义键盘
Android 自定义键盘实现

Android中自定义键盘有一个让人容易误解的地方,就是KeyboardView。可以在Android 自定义键盘实现Demo中看到有hideSystemSoftKeyboard方法,用来把EditText的系统键盘给隐藏,然后再使用KeyboardView加入到视图的底部布局中,KeyboardView使用KeyboardView.OnKeyboardActionListener来监听键盘点击,使用Keyboard来给定键盘布局(使用XML描述布局),然后可以动态修改KeyboardKeyboardView.OnKeyboardActionListener来实现不同的自定义键盘。由此可见,使用RN做自定义键盘在hideSystemSoftKeyboard后就可以打止了,不需要使用KeyboardView,而是使用ReactRootView,然后在RN中绘制键盘。

2、自定义键盘与原生输入组件如何交互

  • RN -> Native
    • RN的TextInput要告知Native它需要什么类型的自定义键盘,因此需要把TextInput的ReactTag和键盘类型传给Native。
    • RN的键盘每次点击一个按钮需要通知Native,并且传入RN的Keyboard对应的TextInput组件(在Android中是EditText,在iOS中是TextFiled和TextView)的ReactTag,Native可以通过ReactTag来定位到具体的Native输入框,然后再根据RN中传来的命令来修改输入框的内容从而实现同步。
  • Native -> RN
    • iOS
      • Native需要创建一个RCTRootView,然后将一些初始化参数传入(如自定义键盘类型,TextView对应的ReactTag)
      • 将RCTRootView赋值给ReactTag对应的TextView的inputView。
    • Android
      • Native拿到ReactTag对应的EditText,禁止它的系统键盘弹出。
      • Native需要创建ReactRootView加入到Activity的底部布局中当做键盘使用。
      • 将ReactRootView加入到EditText的tag中,然后监听EditText的焦点改变来控制相对应的键盘的显示和隐藏。

时序图如下:

Paste_Image.png

RN中文网的自定义键盘的GitHub地址:https://github.com/reactnativecn/react-native-custom-keyboard
关于ReactTag的基本原理(iOS版):http://awhisper.github.io/2016/07/02/ReactNative%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%902/

绘制

将上面的流程和代码弄清后就只剩下RN的键盘界面问题了。

数字键盘的布局和绘制:
参考代码:https://github.com/beefe/react-native-keyboard

字母键盘的布局示意图:

image.png

字符键盘的布局示意图:

image.png

字母和符号键盘的Tip绘制:
最初想法:每个key都为一个单独的component,里面有个TouchableHighlight按钮和与按钮并级的Tip组件,在onPressIn和onPressOut之间控制Tip的显示与隐藏。

不可行:以上方案在Android端不可行,因为Android中RN不能使用overflow:visible属性,在0.41版本中可以使用FlatUIImplement实现overflow:visible属性,但是在0.42及以上版本使用会报错(不过现在解决了,我没试)。

曲线救国想法:使用measureLayout得到key相对keyboard的位置,然后在keyboard层级绘制Tip,而不在key组件中绘制Tip。这个方案基本可行,但是在Android端还是需要解决以下问题:
1、Tip可能会超过keyboard的边界,因此第一行还是会被截掉,所以需要把键盘的高度要加高一些以容纳第一行的Tip。
2、keyboard的背景色会遮挡下层视图,所以要对keyboard的背景做透明。
3、keyboard加高的部分会遮挡下层视图对手势的响应,所以对加高的部分要放弃事件响应。

解答参考了stackoverflow上的提问:Element overflow hidden in React-Native Android

绘制难点:
iOS端Tip外形的绘制:使用react-native-svg绘制,我的绘制代码
Android阴影的实现:使用以react-native-svg为基库做成的react-native-shadow

注:我并没有在Android中使用阴影样式,而是仿照f8app的写法在不同平台使用不同样式

性能优化

因为字母和字符键盘一次性绘制了30多个按钮在屏幕上,会导致在低端Android机能感觉到卡顿(调成Debug模式会很明显,在Dev下打开'Show Perf Monitor'会发现首屏渲染时JS线程掉帧很明显),我在这做了个测试:一次性渲染40个按钮,可以运行看一下卡顿情况。
因此渲染出的数字、字母和字符键盘的DOM分别要被缓存起来,这样才不会在频繁切换键盘时感觉到卡顿。
如果首屏出现的是数字键盘,那么字母键盘和字符键盘就不应该被放在渲染树中,做到用到特定键盘时再去加载这个键盘。

根据React 源码剖析系列 - 不可思议的 react diff,要做到高效的渲染尽量不能改变Dom树的结构,React并没有提供removeViewaddView之类的方法(当然你可以通过带 _ 的私有方法实现),Element(使用JSX或者React. createElement创建出来的)其实并不占多大空间,真正渲染的是DOM(可以通过ref获取),使用DisplayView可以控制DOM的隐藏和显示,让视图在第一次使用时才在DOM树创建,在隐藏和显示时不用改变DOM树的结构。

示例代码

customKeyboard

npm库

react-native-yusha-customKeyboard

安利两个工具

react-native-storybook
UI组件的开发工具,可以浏览组件库,查看各个组件的各个状态,以及开发和测试组件。

react-devtools

image.png

相关文章

网友评论

  • 546f2bc8cf52:你好,最近在做一个pda的项目,有一个需求是Textinput获取焦点的同时要隐藏软键盘,android系统,看您的这个里面也有隐藏掉系统键盘这个操作,请问您是怎么实现的呢?
    546f2bc8cf52:@羽纱 多谢提醒,我看了下源码,install(final int tag, final String type)这个里int类型的tag在react-native是怎么获取的没看太明白,(gs16671833717)这个是我的微信号,可以的话请加一下我的微信说下,非常感谢:pray: 当然这里回复我也行:smile:
    羽纱:@MrGao_4132 你可以去源码里面看 代码不多
  • 64afecc322f0:请问我想在原生键盘和自定义键盘之间切换,使用CustomKeyboard.CustomTextInput该怎么调起系统键盘呢?
    羽纱:@凉气的小小号 模块里有个switchSystemKeyboard方法,可以查阅下
  • 梦儿专属:当一个页面注册多个input框时,从任意一个唤起键盘后,点击其他的输入框后无法点击完成收起键盘,只能回到最初唤起键盘的输入框内点击完成按钮才能收起键盘,还望解决一下!
    a6523fc9cadd:iOS的不可以运行吧?rn的textinput并不是对应原生的textfield,这个怎么解决呢?
  • 妄自:能不能只显示数字键盘?博主
    羽纱:@妄自 https://github.com/lyxia/react-native-yusha-customKeyboard
    妄自:@羽纱 需要添加某个属性还是?谢谢博主了
    羽纱:@妄自 能
  • 慧惠:node_modules/react-native-yusha-customkeyboard/ios/CustomKeyboard/CustomKeyboard.m:4:9: 'RCTText/RCTTextInput.h' file not found 是缺少一个link吗
    羽纱:@boyrt 我写的库不支持哦 你看的demo是支持的 怪我懒:sweat:
    boyrt:请问作者君,低于0.50版本不支持吗?我看你demo中rn版本是0.43.4 哦
    羽纱:1、RN一一定要0.50及以上版本。
    2、升级了react-native-yusha-customKeyboard 到0.0.7,可以
    ```
    react-native init MyApp
    yarn add react-native-yusha-customkeyboard
    react-native link react-native-yusha-customkeyboard
    react-native link react-native-svg
    ```
    直接运行没有报错了 可以试试
  • f98fcca78f7e:好厉害哦

本文标题:使用React Native自定义安全键盘(iOS和Androi

本文链接:https://www.haomeiwen.com/subject/kpdozttx.html