Android开发实例详解之IMF

来源:互联网 发布:人工智能与人类对抗 编辑:程序博客网 时间:2024/05/04 22:40

一、IMF 简介
       一个IMF结构中包含三个主要的部分:

       input method manager:管理各部分的交互。它是一个客户端API,存在于各个应用程序的context中,用来沟通管理所有进程间交互的全局系统服务。

       input method(IME):实现一个允许用户生成文本的独立交互模块。系统绑定一个当前的输入法。使其创建和生成,决定输入法何时隐藏或者显示它的UI。同一时间只能有一个IME运行。
       client application:通过输入法管理器控制输入焦点和IME的状态。一次只能有一个客户端使用IME。

      1 、InputManager
       由UI控件(View,TextView,EditText等)调用,用来操作输入法。比如,打开,关闭,切换输入法等。
       它是整个输入法框架(IMF)结构的核心API,处理应用程序和当前输入法的交互。可以通过Context.getSystemService()来获取一个InputMethodManager的实例。
        在开发过程中,最基础最重要的就是养成阅读API的习惯。优秀的程序员要养成把自己关在小黑屋里,断绝与外界的联网和联系,仅仅靠自己电脑中的开发环境和 API文档,以及漂亮女仆送来的每天三顿饭,写出优秀的程序。这个在武侠小说中叫闭关,在软件开发中叫Clean Room,哈哈。

       Android的API文档在:%SDK_ROOM%/docs/reference/index.html,
       InputManager类的位置:%SDK_ROOM%/docs/reference/android/view/inputmethod/InputMethodManager.html
由于,该类跟本次要讲的Sample关系不大,这里就不详细分析,请各位自行阅读API doc吧。

       2 、InputMethodService
       包括输入法内部逻辑,键盘布局,选词等,最终把选出的字符通过commitText提交出来。实现输入法的基础就是名为 InputMethodService的类,比如你要实现一个谷歌输入法,就是要extends本类。我们接下来要学习的SoftKeyboard Sample也是extends本类。InputMethodService类的位置在:%SDK_ROOM%/docs/reference /android/inputmethodservice/InputMethodService.html
InputMethodService是InputMethod的一个完整实现,你可以再在其基础上扩展和定制。它的主要方法如下:

    * onInitializeInterface() 顾名思义,它在初始化界面的时候被调用,而一般是由于配置文件的更改导致该函数的执行
    * onBinndInput() 它在另外的客户端和该输入法连接时调用
    * onStartInput() 非常重要的一个回调,它在编辑框中用户已经开始输入的时候调用。比如,当点击一个输入框,我们需要根据这个输入框的信息,设置输入法的一些特性,这个在Sample中很有体会。
    * onCreateInputView() 返回一个层次性的输入视图,而且只是在这个视图第一次显示的时候被调用
    * onCreateCandidatesView() 同onCreateInputView(),只不过创建的是候选框的视图。
    * onCreateExtractTextView() 比较特殊,是在全屏模式下的一个视图。
    * onStartInputView() 在输入视图被显示并且在一个新的输入框中输入已经开始的时候调用。

       基本上输入法的定制,都是围绕在这个类来实现的,它主要提供的是一个基本的用户界面框架(包括输入视图,候选词视图和全屏模式),但是这些都是要实现者自己去定制的。这里的实现是让所有的元素都放置在了一个单一的由InputMethodService来管理的窗口中。它提供了很多的回调API,需要我们自己去实现。一些默认的设置包括:
* 软键盘输入视图,它通常都是被放置在屏幕的下方。
    * 候选词视图,它通常是放置在输入视图的上面。
    * 当我们输入的时候,需要改变应用程序的界面来适应这些视图的放置规则。比如在Android上面输入,编辑框会自动变形腾出一个软键盘的位置来。

       两个非常重要的视图:

       1. 软输入视图。
是与用户交互的主要发生地:按键,画图或者其他的方式。通常的实现就是简单的用一个视图来处理所有的工作,并且在调用 onCreateInputView()的时候返回一个新的实例。通过调用系统的onEvaluateInputViewShow()来测试是否需要显示输入视图,它是系统根据当前的上下文环境来实现的。当输入法状态改变的时候,需要调用updateInputViewShown()来重新估计一下。

       2. 候选词视图。当用户输入一些字符之后,输入法可能需要提供给用户一些可用的候选词的列表。这个视图的管理和输入视图不大一样,因为这个视图是非常的短暂的,它只是在有候选词的时候才会被显示。可以用setCandidatesViewShow()来设置是否需要显示这个视图。正是因为这个显示的频繁性,所以它一般不会被销毁,而且不会改变当前应用程序的视图。

       最后,关于文本的产生,这是一个IME的最终目的。它通过 InputConnection来链接IME和应用程序的:能够直接产生想要的按键信息,甚至直接在候选和提交的文本中编辑。当用户在不同的输入目标之间切换的时候,IME会不断的调用onFinishInput() 和 onStartInput()。在这两个函数中,需要反复做的就是复位状态,并且应对新的输入框的信息。

       以上是一个输入法的最基本的介绍,下面将根据Sample中的SoftKeyboard来说明这些问题。

       (一)概述

       从InputMethodServiceSample项目可以看出实现一个输入法至少需要CandidateView, LatinKeyboard, LatinKeyboardView,SoftKeyboard这四个文件:

      * CandidateView负责显示软键盘上面的那个候选区域。
      * LatinKeyboard负责解析并保存键盘布局,并提供选词算法,供程序运行当中使用。其中键盘布局是以XML文件存放在资源当中的。比如我们在汉字输入法下,按下b、a两个字母。LatinKeyboard就负责把这两个字母变成爸、把、巴等显示在CandidateView上。
      * LatinKeyboardView负责显示,就是我们看到的按键。它与CandidateView合起来,组成了InputView,就是我们看到的软键盘。
      * SoftKeyboard继承了InputMethodService,启动一个输入法,其实就是启动一个InputMethodService,当SoftKeyboard输入法被使用时,启动就会启动SoftKeyboard这个Service。

      (二)LatinKeyboard.java

       软键盘类,直接继承了Keyboard类,并定义一个xml格式的Keyboard的布局,来实现一个输入拉丁文的键盘。这里只是创建一个键盘对象,并不对具体的布局给出手段。

       为了更好的理解LatinKeyboard类,这里简单介绍一下Keyboard类。Keyboard可以载入一个用来显示键盘布局的xml来初始化自己,并且可以保存这些键盘的键的属性。他有三个构造函数:

    * Keyboard(Context context, int xmlLayoutResId),用语境和xml资源id索引xml文件来创建。
    * Keyboard(Context context, int xmlLayoutResId, int modeId),这个和上面差不多,只不过多了一个modeld。
    * Keyboard(Context context, int layoutTemplateResId, CharSequence characters, int columns, int horizontalPadding),这个比较复杂,用一个空xml布局模板创建一个键盘,然后用指定的characters按照从左往右,从上往下的方式填满这个模板。

       这里因为重写了Keyboard类的createKeyFromXml(Resources res, Row parent, int x, int y, XmlResourceParser parser),为了要返回一个Key对象,干脆直接创建LatinKey对象好了。从这里我们能看出面向对象和使用框架的要求。

       接着,本文件重载了一个createKeyFromXml的函数,这是一个回调函数,它在键盘描绘键的时候调用,从一个xml资源文件中载入一个键,并且放置在 (x,y)坐标处。它还判断了该键是否是回车键,并保存起来。在这里,为了要返回一个Key对象,于是直接创建内部类的LatinKey对象。从这里我们能看出面向对象和使用框架的要求。

此外,还有一个函数是:setImeOptions,它是根据编辑框的当前信息,来为这个键盘的回车键设置适当的标签。输入框的不同,会产生不同的回车键的label或者icon。在这个函数中,有一个技巧是用了一些imeOption的位信息,比如IME_MASK_ACTION等等。主要是查看的 EditorInfo的Action信息,这里有:

        * IME_ACTION_GO: go操作,将用户带入到一个该输入框的目标的动作。确认键将不会有icon,只有label: GO
        * IME_ACTION_NEXT: next操作,将用户带入到该文本框的写一个输入框中。如: 编辑短消息的时候,内容就是收件人手机号码框的next文字域。它也只是一个NEXT label就行了。
        * IME_ACTION_SEARCH: search操作,默认动作就是搜索。如: 在URL框中输入的时候,默认的就是search操作,它提供了一个像放大镜一样的icon。
        * IME-ACTION_SEND: send操作,默认动作就是发送当前的内容。如: 短消息的内容框里面输入的时候,后面通常就是一个发送操作。它也是只提供一个Label:SEND
        * DEFAULT: 默认情况下表示文本框并没有什么特殊的要求,所以只需要设置return的icon即可。

       最后,它还定义了一个内部类——LatinKey,它直接继承了Key,来定义一个单独的键,它唯一重载的函数是isInside(int x , int y ),用来判断一个坐标是否在该键内。它重载为判断该键是否是CANCEL键,如果是则把Y坐标减少10px,按照他的解释是用来还原这个可以关掉键盘的键的目标区域。

       (三)LatinKeyboardView.java

       这里就是个View,自然也继承自View,因为前面创建的键盘只是一个概念,并不能实例出来一个UI,所以需要借助于一个VIEW类来进行绘制。这个类简单的继承了KeyboardView类,然后重载了一个动作方法,就是onLongPress

       它在有长时间按键事件的时候会调用,首先判断这个按键是否是CANCEL键,如果是的话就通过调用 KeyboardView被安置好的OnKeyboardActionListener对象,给键盘发送一个OPTIONS键被按下的事件。它是用来屏蔽CANCEL键,然后发送了一个未知的代码的键。

      (四)CandidateView.java

       CandidateView
是一个候选字显示view,它提供一个候选字选择的视图,直接继承于View类即可。在我们输入字符时,它应该能根据字符显示一定的提示,比如拼音同音字啊,联想的字啊之类的。

      1. 先看它定义了那些重要变量:

        * mService: candidateView的宿主类,即该view是为什么输入法服务的。
        * mSuggestions: 建议。比如说当我们输入一些字母之后输入法希望根据输入来进行联想建议。
        * mSelectedIndex: 用户选择的词的索引。
        * mSelectionHighlight: 描绘选择区域高亮的类。
        * mTypedWordValid: 键入的word是否合法正确。
        * mBgPadding: 背景填充区域。
        * mWordWidth: 每个候选词的宽度。
        * mWordX:每个候选词的X坐标。有了这两个变量,就能够在屏幕上准确的绘制出该候选键。
        * mColor*:定义了各种颜色。
        * mPaint: 一个绘图类,后面会用到
        * mVerticalPadding: 垂直填充区域。
        * mTargetScrollX: 目标滚动的横坐标,即要将目标滚动到何处。
        * mTotalWidth: 总的宽度
        * mGestureDetector: 声明一个手势监测器

       GestureDetector 对象似乎很少见,让我们了解一下android.view.GestureDetector。这是一个与动作事件相关的类,可以用来检测各种动作事件,这里称之为:手势监测器。它的回调函数是
GestureDetector.OnGestureListener,在动作发生时执行,而且只能在触摸时发出,用滚动球无效。要使用这个通常要先建立一个对象,如同代码里体现的,然后设置 GestureDetector.OnGestureListener 同时在 onTouchEvent(MotionEvent)中写入动作发生要执行的代码。

 

原创粉丝点击