这是我根据谷歌拼音改版的输入法.
在Android的这个平台下,有很多源码是值得我们学习的。(由于本人能力有限,有不足的地方还请大家多多指出,互相学习吧)
PinyinIME 代码相对于其它完整的输入法来说,代码量已经算很少了.
我自己开始的时候做了一些笔记,比较乱(http://note.youdao.com/share/?id=d8dfced1c7ad9718091f7aa9fe38590e&type=note)
源码下载地址,我在github上搜索的(https://github.com/yuanyelele/PinyinIME/)
目录结构:
jni/ - Java Native Interface, 用C/C++实现拼音输入法的功能,供上层Java代码调用的底层代码。
lib/ - 用AIDL文件给上层JAVA应用定义了jni可用的接口集IPinyinDecoderService。AIDL请参考
res/ - Android项目的资源目录(系统静态字典数据文件dict_pinyin.dat也放在这个目录下的raw子目录里)
res/目录下,我们更关心xml目录.
你打开任何一个XML都会使你迷茫的。(下图的XML是我改过的布局)
不过不要急,慢慢往下看,我会给你一一分析.
src/ - Android java 输入法服务,还有软键盘,候选框绘制,读取键盘XML等等.
我们分析的代码主要集中在 src/ 目录下.
首先大致来了解一下简单的过程.
其实上图就是最简单的过程了.
然后我们就可以思考,它是如何加载布局的,输入法是如何切换布局的,是如何点击软键盘界面获取键值的等等,然而这一切的源头 要从 InputMethodService 说起.
先来简单了解 InputMethodService 的启动流程:
==========================================================
onCreateInputView
@Override public View onCreateInputView() { if (mEnvironment.needDebug()) { Log.d(TAG, "onCreateInputView."); } LayoutInflater inflater = getLayoutInflater(); mSkbContainer = (SkbContainer) inflater.inflate(R.layout.skb_container, null); mSkbContainer.setService(this); mSkbContainer.setInputModeSwitcher(mInputModeSwitcher); mSkbContainer.setGestureDetector(mGestureDetectorSkb); return mSkbContainer; }
onCreateCandidatesView
/** * 创建候选窗口布局. */ @Override public View onCreateCandidatesView() { if (mEnvironment.needDebug()) { Log.d(TAG, "onCreateCandidatesView."); } LayoutInflater inflater = getLayoutInflater(); // Inflate the floating container view mFloatingContainer = (LinearLayout) inflater.inflate( R.layout.floating_container, null); // 候选窗口,字符提示(比如,qw,e...) // The first child is the composing view. mComposingView = (ComposingView) mFloatingContainer.getChildAt(0); mCandidatesContainer = (CandidatesContainer) inflater.inflate( R.layout.candidates_container, null); // 候选框窗口布局. // Create balloon hint for candidates view. mCandidatesBalloon = new BalloonHint(this, mCandidatesContainer, MeasureSpec.UNSPECIFIED); mCandidatesBalloon.setBalloonBackground(getResources().getDrawable( R.drawable.candidate_balloon_bg)); mCandidatesContainer.initialize(mChoiceNotifier, mCandidatesBalloon, mGestureDetectorCandidates); // The floating window if (null != mFloatingWindow && mFloatingWindow.isShowing()) { mFloatingWindowTimer.cancelShowing(); mFloatingWindow.dismiss(); } mFloatingWindow = new PopupWindow(this); mFloatingWindow.setClippingEnabled(false); mFloatingWindow.setBackgroundDrawable(null); mFloatingWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED); mFloatingWindow.setContentView(mFloatingContainer); setCandidatesViewShown(true); // 显示 CandidateView return mCandidatesContainer; }