首先,目前只是记录一些开发输入法时遇过的坑。
一、关于中文输入法
1.Android中文输入法资料实在是少的可怜,唯一能用的开源中文输入法就是谷歌中文输入法,但那也是很旧的版本了,只有26键并且词库也比较过时。
2.项目初期曾以此为基础开发26键中文键盘,其实感觉效果还算理想。
a.在GitHub中下载谷歌拼音输入法源码,然后跑通后开始研究源码。
b.界面是键盘模板布局SkbTemplate写的,没有可视化界面,定制化也不高,所以建议还是layout自定义布局。
c.其中候选词和联想词也是用的键盘模块(候选词视图会在界面最上层),可弃用,使用layout自定义布局。
d.此源码有一个BUG,拼音输入“NSS”会崩溃,原因在输入法框架的cpp中,暂未找到修复方法,只能输入时优化此问题。
3.中文9键和词库记忆等功能,如果愿意花大量心思去研究也是可以搞出来的
4.后来使用的是第三方的收费SDK,就不再研究具体输入法的核心代码了。
2.生命周期
image.png
切换本输入法时(显示键盘前):onCreate->onBindInput->onStartInput
显示键盘过程:onEvaluateInputViewShown(调用2次) -> onCreateInputView-> onCreateCandidatesView ->
onStartInputView -> onWindowShown -> onComputeInsets(调用2次)
关闭键盘过程:->onFinishInputView-> onWindowHidden -> onComputeInsets
切换其他输入法:onDestroy - > onFinishInput
方法简介:
onCreate()
输入法创建过程时首先调用该方法.由于常驻在进程当中,在没有OnDestory之前只会调用该方法一次
onInitializeInterface()
紧随着onCreate()方法后调用,用于界面初始化以及用于service运行过程中配置信息发生改变的情况(横竖屏转换等,会触发onConfigurationChanged()方法)
onBindInput
用于发现客户端的变化,当新的客户端绑定到输入法时,该方法会被调用,在输入法第一次启动时,会马上调用onStartInput方法获取编辑框数据,否则,先调用onFinishInput方法,而后调用onStartInput方法
onStartInput
走完onBindInput(),会调用该方法.用于处理客户端发起的输入会话,输入法可以获取到相对应的编辑框的信息,用于决定展示什么类型的键盘.在输入法周期中会频繁的调用.
onEvaluateInputViewShown()
此方法在显示键盘时,首次打开会在onCreateInputView()之前调用,因此需要注意初始化过程中的顺序问题,避免空指针。
onCreateInputView()
在该生命周期中主要用于初始化跟input area区域相关的类和变量.
onCreateCandidateView()
在该生命周期中主要用于初始化跟candidate area区域相关的类和变量.
onCreateExtractTextView
在输入法全屏模式下会调用,用于创建并返回用于显示(extracted text)文本信息的区域视图,返回的视图必须包含ExtractEditText,且ID值为inputExtractEditText,默认情况下横屏模式时,输入法为全屏效果。
onConfigureWindow()
通常在窗口发生改变时候调用,比如在获取到输入视图时调用和失去输入视图时.
onStartInputView()
输入视图正在显示并且编辑框输入已经获取焦点时回调该方法用于创建并返回(input area)输入区域的层次视图,该方法只被调用一次(输入区域第一次显示时),该方法可以返回null,此时输入法不存在输入区域,InputMethodService的默认方法实现返回值为空,想要改变已经创建的输入区域视图,我们可以调用setInputView(View)方法,想要控制何时显示输入视图,我们可以实现onEvaluateInputViewShown方法,该方法用来判断输入区域是否应该显示,在updateInputViewShown方法中会调用onEvaluateInputViewShown方法来判断是否显示输入区域.
onStartInputView()
输入视图正在显示并且编辑框输入已经获取焦点时回调该方法,onStartInputView方法总会在onStartInput,onConfigureWindow()方法之后被调用.一般情况下普通的设置可以在onStartInput方法中进行,在onStartInputView方法中进行视图相关的设置,开发者应该保证onCreateInputView方法在该方法被调用之前调用.
onStartCandidiateView()
候选视图正在显示时回调该方法,必须确保候选区域的资源已经初始化过了.一般情况普通的设置可以在onStartInput方法中进行,在onStartCandidatesView方法中进行视图相关的设置,开发者应该保证onCreateCandidatesView方法在该方法被调用之前调用。
onWindowShown()
在onstartinputview方法之后调用,调用该方法时,表示整个输入法是可见的.
hideWindow()
当输入法window失去焦点时调用该方法.
onWindowHidden()
当视图有可见转换为不可见时,调用该方法.一般跟onWindowShown配合使用。
onFinishCandidatesView()
当候选词视图即将被隐藏或者切换到另外的编辑框时调用该方法,finishingInput为true,onFinishInput方法会接着被调用.
onFinishInputView()
当候选词视图即将被隐藏或者切换到另外的编辑框时调用该方法,finishingInput为true,onFinishInput方法会接着被调用.
onFinishInput()
往往在onFinishInputView之后调用,后续可能会接着调用onStartInput方法,或者处于闲置状态,在使用输入法过程中会频繁的调用.
onUnbindInput()
与绑定的客户端失去联系时,会调用该方法.
onDestory()
输入法服务结束时调用.只调用一次.再次方法中做好资源释放的工作
三、关于输入法界面
1.首先输入法是否为全屏状态,通常是非全屏状态,会自动置底。因此要注意输入法界面的高度,尽可能统一,否则会出现跳动的情况。(直接setVisibility在高度变低时,导致界面掉下来的效果,暂未找到解决方法,其他输入法已解决)
2.界面可完全自定义,因为不是activity所以不能使用fragment,因此界面需要包含在一个layout中,建议使用include和MVP模式。
可以使用PopupWindow,但注意窗口的高度会被限制为输入法的高度上限。
四、关于坑的记录
1.回车键和搜索键的判断
需要通过EditorInfo来获取编辑框的信息,以imeOptions的值判断是否为搜索框;
APP有几种不同的值,但不同浏览器几乎都不一致,所以需要测试匹配主流APP和浏览器。
不要使用KeyEvent.KEYCODE_ENTER,因为有的APP并没有匹配搜索框的setOnKeyListener;
直接使用service的sendDefaultEditorAction(true)即可。
2.横竖屏切换问题
横竖屏切换会导致数据错乱,在onConfigurationChanged可监听到横竖屏切换,将键盘关闭即可
3.关于删除
1.长按删除,监听删除按钮的OnTouchListener,按下时连续删除,弹起则结束
2.删除文字:ic.deleteSurroundingText(1, 0) 但此方法不能删除非字符内容,如QQ的引用回复。
因此应该是以KeyEvent.KEYCODE_DEL为准
4.后台弹出应用权限获取
AndroidQ(部分厂家更早版本也禁止了)之后系统已经禁止了后台弹出应用,所以需要提示用户手动开启此功能。