第一 开始
对于一个从来没有接触输入法的开发人员来说,如果你想自己开发输入法,那么下面的这些步骤是值得你一看的。至少这是我自己的开发经历,我想会对你有很大的帮助。 首先我想说的就是,如果你在别人项目的基础上开发自己的项目,那么有几点是必须做好的。 1、不要盲目的翻来翻去的看代码,这样的收获会很小很小,因为这个时候你甚至还不知道别人定义的字段都是代表什么,又谈何能看懂代码呢? 2、查看manifest文件,找到项目的入口处,这个很关键。 3、在看代码的过程中不要每一条语句都去深究,对于方法来说,掌握整理作用即可。
第二 准备
谷歌拼音输入法最主要的一个类是PinyinIME,这个类继InputMethodService。 原版的输入法是以这个类为基础,其他的一些类都是自定义键盘,候选框,popupwindow等,所以这些类我们都不需要了解,而且最终都用不到,因为我们要自己定义键盘。如果我们做的键盘需要用上下左右键来控制输入,那么普通的button是行不通的,因为下面的键盘获取不到焦点,所以键盘的button只能点击。所以这也就是说,如果你想实现一个用上下左右键来控制键盘输入的话,那么必须用view或者surfaceview来画键盘,这样才能用方向键控制输入。本人习惯用surfaceView,因为它更高级,更好用。 先看下面的一张图,这是原版输入法的键盘 file:///C:/DOCUME~1/小木桩/LOCALS~1/Temp/ksohtml/wps_clip_image-132.png 接下来介绍PinyinIME类当中的各个字段都具体代表什么东西,只要清楚的知道它们是什么以后,我们才能看懂代码。 (1)EnglishInputProcessor mImEn; 这个字段是英文处理的一个类(无继承),当当前输入状态为英文输入时则调用这个类处理。 (2)InputModeSwitcher mInputModeSwitcher; 用于切换输入法的一个类,可以中文输入和英文输入两种切换 (3)SkbContainer mSkbConTainer; 这个类继承了view,实现了很多监听方法,其实它就是下面的软键盘布局,此布局是画出来的,所以它无法获取焦点,而我们看到它获取焦点其实只是画出来的焦点。 file:///C:/DOCUME~1/小木桩/LOCALS~1/Temp/ksohtml/wps_clip_image-18409.png (4) LinearLayout mFloatingContainer; 在中文输入状态下,这个布局存放的是用户输入的拼音,如下图 file:///C:/DOCUME~1/小木桩/LOCALS~1/Temp/ksohtml/wps_clip_image-19679.png 上面的thjjh的布局就是LinearLayout。 (5) ComposingView mComposingView; 它代表的是上面thjjh的第一个,在代码中有一条这样的语句 mComposingView = (ComposingView) mFloatingContainer.getChildAt(0); 说明它代表的是mFloatingContainer中的第一个view。 (6) PopupWindow mFloatintWindow; 前面我们已经谈到有这样一个viewfile:///C:/DOCUME~1/小木桩/LOCALS~1/Temp/ksohtml/wps_clip_image-20221.png 那它又是通过什么方式显示出来的呢, 你猜对了。mFloatingContainer这个view就是放在mFloatintWindow,然后通过popupWindow的方式弹出来,给用户一个提示作用,它是否可见有代码控制 (7) PopupTimer PopHander= new PopupTimer(); 它是一个自定义继承Handler的类,里面含有一个线程,它的主要作用就是控制popupwindow的出现和消失。 原版输入法中一共存在三种pupupwindow,如下图所示 file:///C:/DOCUME~1/小木桩/LOCALS~1/Temp/ksohtml/wps_clip_image-28247.png (一)白色背景g file:///C:/DOCUME~1/小木桩/LOCALS~1/Temp/ksohtml/wps_clip_image-21785.png (二)白色背景弹出的 开始 file:///C:/DOCUME~1/小木桩/LOCALS~1/Temp/ksohtml/wps_clip_image-28814.png (三)白色背景的 thjjh 英文 (8)CandidatesContainer mCandidatesContainer; 它是一个自定义继承RalativeLayout 的布局,也可以说是一个view。它就是显示中文候选框的一个重要布局,如下图所示 file:///C:/DOCUME~1/小木桩/LOCALS~1/Temp/ksohtml/wps_clip_image-5233.png 这也是中文输入法中的重要布局 (9)BalloonHint mCandidatesBalloon; 它是一个自定义继承popupwindow的类,由名字可以看出,“气球暗示”,它代表的就是上面提到的三个popupwindow中的第二个 “开始” file:///C:/DOCUME~1/小木桩/LOCALS~1/Temp/ksohtml/wps_clip_image-21943.png (10)ChoiceNotifier mChoiceNotifier; 它是一个自定义继承Handler并实现一个监听接口的类。 在代码中我也暂时没有确切的了解它为何用,(待续……) (11)OnGestureListener mGestureListenerSkb; 监听软键盘手势动作的一个(手势)监听器 (12)OnGestureListener mGestureListenerCandidates; 监听候选框手势动作的一个(手势)监听器 (13)GestureDetector mGestureDetectorCandiadates; 候选框的手势传感器 (14)GestureDetector mGestureDetectorSkb; 软键盘的手势传感器 (15)AlerDialog mOptionDialog; 当长按键盘上面的“中文”时,便会弹出这个对话框,它是一个设置Dialog,如下图 file:///C:/DOCUME~1/小木桩/LOCALS~1/Temp/ksohtml/wps_clip_image-7174.png (16)PinyinDecoderSerViceConnection mPinyinDecoderSerViceConnection; 用于启动拼音解码服务的一个回调连接 (17)ImeState mImeState=ImeState.STATE_IDLE; 这是一个枚举,记录着当前为何种输入状态,如空闲状态,预测状态等等。。。拼音解码服务会根据当前的状态来搜索相对应联想出来的中文。、 (18)DecodingInfo mDecInfo=new DecondingInfo(); 这是中文输入下最重要的一个类,用它来解析拼音,它的解析规则是这样的,用户输入一个拼音的字符串,然后DecodingInfo类根据这个pinyin字符串去词库当中搜索中文,然后返回很多很多中文存放在一个容器当中,然后我们可以从容器当中拿出这些解析好的中文,它返回的是一个list。
第三 看代码
(1) onCreate() 拼音输入法服务第一次运行起来的时候会执行这个方法(由系统调用),只会执行一次。所以可以在这个方法里面指定一些初始化的动作。 (2) Public View onCreateInputView() 创建软键盘的view,然后在这里面设置监听等等,各种初始化动作,此方法由系统调用也只执行一次。 创建好了软件盘view之后,就 return view;返回,之后view就有系统调用它是否弹出来。 (3) public View onCreateCandidatesView() 此方法是创建候选框的view,由系统调用,当然我们也可以将中文的候选框view直接嵌入到然键盘view当中去,因为我就是这么做的。那么这里就可以返回null。这样一来,我们就省得自己反复控制候选框view是否可见了。当然,软键盘也就会更复杂了一点。 上面上个步骤是很重要的,一切监听做好了之后,输入法就由系统控制运行了。每一次运行输入法的时候会执行如下方法 onStartInputView(EditorInfo editorInfo,boolean restarting) 此方法里面有一个重要的参数editorInfo,因为文本输入框可能有多重形式,如果只运行数字输入的edittext(电话号码), 喊隐藏字符的 密码输入框,URL地址输入框等等,我们可以根据这是信息来对我们的软键盘进行相应的设置。 (4)onFinishInputView() 每一次输入法结束输入之后都会调用这个方法,我们可以让我们的键盘进行重置设置,比如记录一些数据也可以,具体需要做什么由我们自己而定 ——————有了上面的四点之后,我们就可以大体的知道输入法的运行流程了, 接下来将介绍一些细节的方法,也是重要的方法 (1)、默认情况下,输入法是否为全屏是由系统控制的,然后如果我们要认为的控制它为全屏或者不为全屏的话。可以修改下面这个方法 Public boolean onEvaluateFullScreenMode() 当我们返回true的话,则为全屏,返回false的话则不为全屏。如果自己不想控制,则返回super.onEvaluateFullScreenMode(); (2)、在全屏模式下,上面的会有一个由系统定义的输入框,如下图 file:///C:/DOCUME~1/小木桩/LOCALS~1/Temp/ksohtml/wps_clip_image-14308.png 如果我们想自己定义上面的系统输入框,那么有以下几点是要遵行的。 改写public View onCreateExtractTextView()方法,返回自己定义的输入框布局。 在我们自定义的输入框布局中必须有这样一个控件 ExtractEditText,而且它的id必须为@android:id/inputExtractEditText 接下来包含多少其它的控件都由自己设计,想有多花哨都行。 (3)、如果将字符串提交到输入框当中,如何删除输入框当中的字符串呢?方法如下: 提交字符串: InputConnect ic =this.getCurrentInputConnection(); If(ic!=null){ ic.commitText(“你好”,1); } 这样便可以将你好提交到输入框,当前光标的后面去,1就是光标的位置。 如果你想提交回车键的话,用这种方法是提交不了的,那么用下面这条语句吧,它可以助我们提交一些转义字符 this.sendKeyChar(char c); c就是我们要提交的转义字符 删除输入框的一个字符 InputConnect ic =this.getCurrentInputConnection(); If(ic!=null){ ic.deleteSurroundingText(1,0); } 第一个参数是删除光标左边字符的个数 第二个参数是删除光标右边的字符个数 这里我们填1,0是最好的方法,也即是普通的删除一样 (4)下面介绍中文解析类DecodingInfo,在源码中,此类已经被完全完全的融合到了它的候选框view当中,所以直接看它的这个类会特别的吃力,因为涉及了很多很多东西,所以下面我谈到的将以我改好的,通用的DecodingInfo类为例来进行说明,绝对的通用 重要方法如下 正常情况下解析,即传入拼音字符串,然后解析出中文、 DecodingInfo decoding=new DecodingInfo (); decoding.setStateInfo(Constant.NORMAL_SEARCH); //设置解析方式为普通解析中文 decoding.setStringPinyin(“nihao”); //设置要解析的拼音字符串 decoding.chooseDecodingCandidate(-1); //开始解析 ArrayList<String> list=decoding.listCandidates; //拿数据 这样list当中只拿到了10个数据,那么如果要请求下一页的话,则执行 decoding.preparePage(4); 里面的整数4为你想要拿到的页码数据,但是在拿数据之前你要先判断一下到底还有没有数据,方法如下: decoding.pageForwardable(4); 如果它返回true,那么代表第4页还有数据。 接下来执行:decoding.preparePage(4); List.addAll(decoding.listCandidates); //这样便将下一页的数据添加进来了。 预测状态下解析: 如当你点击“你好”之后,那么可以由你好这两个词进行一次解析得到相应的联想数据,方法如下: decoding.setStateInfo(Constant.PREDICT_SEARCH); //设置解析类型 decoding.preparePredicts(“你好”); //设置中文,并进行解析 ArrayList<String> list=decoding.listCandidates; //拿数据 后面的下一页怎么拿数据都和之前的一样。 —————以上的介绍只是一部分,真正软键盘的定义由你自己而定,所有的控制也由自己控制。该有的方法上面已经统统概括。
|