该项目实现了一个完整的输入法程序,该输入法包含了小写字母软键盘和数字软键盘,会根据EditText控件相应属性值自动切换到小写字母或数字软键盘。
通过小写字母软键盘也可手动切换到数字软键盘和大写字母软键盘。
1.输入法的初始化工作
输入法程序必须有一个服务类,该类必须继承自InputMethodService,该类的配置代码如下:
<service android:name="net.csdn.leigo.input.method.SoftKeyboard" android:permission="android.permission.BIND_INPUT_METHOD" > <intent-filter > <action android:name="android.view.InputMethod"/> </intent-filter> <meta-data android:name="android.view.im" android:resource="@xml/method"/> </service>
在res目录下新建xml/method.xml:
<?xml version="1.0" encoding="UTF-8"?> <input-method xmlns:android="http://schemas.android.com/apk/res/android" />
输入法服务类的核心方法是onCreateInputView,该方法返回一个View对象,该对象实际上就是软键盘的界面。
package net.csdn.leigo.input.method; import net.csdn.leigo.input.R; import android.inputmethodservice.InputMethodService; import android.inputmethodservice.KeyboardView; import android.view.View; public class SoftKeyboard extends InputMethodService { private KeyboardView mInputView; @Override public View onCreateInputView() { // 装载软键盘布局文件 mInputView = (KeyboardView) getLayoutInflater().inflate(R.layout.input, null); return mInputView; } }
在onCreateInputView方法中通过装载一个布局文件(input.xml)来创建一个View对象,这个布局文件就是软键盘的界面。
<?xml version="1.0" encoding="utf-8"?> <net.csdn.leigo.input.method.LatinKeyboardView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/keyboard" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" />
上面的代码只定义了一个控件:LatinKeyboardView,该控件用于显示软键盘的界面,
package net.csdn.leigo.input.method; import android.content.Context; import android.inputmethodservice.KeyboardView; import android.util.AttributeSet; public class LatinKeyboardView extends KeyboardView { static final int KEYCODE_OPTIONS = -100; public LatinKeyboardView(Context context, AttributeSet attrs) { super(context, attrs); } public LatinKeyboardView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } }
LatinKeyboardView类并没有实际的代码,只是一个继承自KeyboardView的类。KeyboardView是一个拥有标准键盘的类,如果只想显示标准的软键盘,直接从KeyboardView
类继承即可。
2.响应键盘操作
软键盘有两种类型的按键:输入按键(用于输入数字、符号和字母)和功能按键,要想处理这两种按键的动作,输入法服务类需要实现KeyboardView.OnKeyboardActionListener接口。处理按键的方法是onKey,
public void onKey(int primaryCode, int[] keyCodes) { if (isWordSeparator(primaryCode)) { // 处理符号键盘 if (mComposing.length() > 0) { commitTyped(getCurrentInputConnection()); } sendKey(primaryCode); updateShiftKeyState(getCurrentInputEditorInfo()); } else if (primaryCode == Keyboard.KEYCODE_DELETE) { // 处理删除按键 handleBackspace(); } else if (primaryCode == Keyboard.KEYCODE_SHIFT) {//处理Shift按键 handleShift(); } else if (primaryCode == Keyboard.KEYCODE_CANCEL) { //处理Cancel按键 handleClose(); return; } else if (primaryCode == LatinKeyboardView.KEYCODE_OPTIONS) { } else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE && mInputView != null) { Keyboard current = mInputView.getKeyboard(); if (current == mSymbolsKeyboard || current == mSymbolsShiftedKeyboard) { current = mQwertyKeyboard; } else { current = mSymbolsKeyboard; } mInputView.setKeyboard(current); if (current == mSymbolsKeyboard) { current.setShifted(false); } } else { handleCharacter(primaryCode, keyCodes); } }
上面代码中涉及到一些处理功能按键的方法,例如,handleBackspace(处理退格动作),handleShift(处理Shift键),handleClose(用于关闭软键盘)
private void handleBackspace() { final int length = mComposing.length(); if (length > 1) { mComposing.delete(length - 1, length); getCurrentInputConnection().setComposingText(mComposing, 1); updateCandidates(); } else if (length > 0) { mComposing.setLength(0); getCurrentInputConnection().commitText("", 0); updateCandidates(); } else { keyDownUp(KeyEvent.KEYCODE_DEL); } updateShiftKeyState(getCurrentInputEditorInfo()); } private void handleShift() { if (mInputView == null) { return; } Keyboard currentKeyboard = mInputView.getKeyboard(); if (mQwertyKeyboard == currentKeyboard) { //切换到字母键盘 checkToggleCapsLock(); mInputView.setShifted(mCapsLock || !mInputView.isShifted()); } else if (currentKeyboard == mSymbolsKeyboard) { //切换到符号键盘 mSymbolsKeyboard.setShifted(true); mInputView.setKeyboard(mSymbolsShiftedKeyboard); mSymbolsShiftedKeyboard.setShifted(true); } else if (currentKeyboard == mSymbolsShiftedKeyboard) { mSymbolsShiftedKeyboard.setShifted(false); mInputView.setKeyboard(mSymbolsKeyboard); mSymbolsKeyboard.setShifted(false); } } private void handleCharacter(int primaryCode, int[] keyCodes) { if (isInputViewShown()) { if (mInputView.isShifted()) { primaryCode = Character.toUpperCase(primaryCode); } } if (isAlphabet(primaryCode) && mPredictionOn) { mComposing.append((char) primaryCode); getCurrentInputConnection().setComposingText(mComposing, 1); updateShiftKeyState(getCurrentInputEditorInfo()); updateCandidates(); } else { getCurrentInputConnection().commitText( String.valueOf((char) primaryCode), 1); } } private void handleClose() { commitTyped(getCurrentInputConnection()); requestHideSelf(0); //关闭软键盘 mInputView.closing(); }
3.根据EditText控件的属性显示不同的软键盘
如果将<EditText>标签的android:inputType属性设为'number",当EditText控件处于焦点时,会显示数字键盘;否则会显示输入字母的键盘。当EditText控件获得焦点时,会调用
输入法服务类的onStartInput方法,在该方法中会根据当前文本输入框的输入条件显示不同的软键盘。
@Override public void onStartInput(EditorInfo attribute, boolean restarting) { super.onStartInput(attribute, restarting); //清空输入缓冲区 mComposing.setLength(0); updateCandidates(); if (!restarting) { //清空Shift状态 mMetaState = 0; } mPredictionOn = false; mCompletionOn = false; mCompletions = null; switch (attribute.inputType & EditorInfo.TYPE_MASK_CLASS) { case EditorInfo.TYPE_CLASS_NUMBER: case EditorInfo.TYPE_CLASS_DATETIME: //当文本输入框要求输入数字或日期时,显示数字软键盘 mCurKeyboard = mSymbolsKeyboard; break; case EditorInfo.TYPE_CLASS_PHONE: //显示符号软键盘 mCurKeyboard = mSymbolsKeyboard; break; case EditorInfo.TYPE_CLASS_TEXT: //显示输入字母的软键盘 mCurKeyboard = mQwertyKeyboard; mPredictionOn = true; int variation = attribute.inputType & EditorInfo.TYPE_MASK_VARIATION; if (variation == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD || variation == EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) { mPredictionOn = false; } if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS || variation == EditorInfo.TYPE_TEXT_VARIATION_URI || variation == EditorInfo.TYPE_TEXT_VARIATION_FILTER) { mPredictionOn = false; } if ((attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) { mPredictionOn = false; mCompletionOn = isFullscreenMode(); } //更新Shift状态 updateShiftKeyState(attribute); break; default: //对于所有未知类型,显示字母输入键盘 mCurKeyboard = mQwertyKeyboard; updateShiftKeyState(attribute); } mCurKeyboard.setImeOptions(getResources(), attribute.imeOptions); }