最近产品经理提出使用系统的软键盘一直点击切换可能会出现系统崩溃,因为是定制的安卓设备所以很容易出现此类问题,就研究了一下自定义软键盘,记录一下研究结果。
1 . KeyBoard的键盘按钮配置
首先在res下创建xml文件夹,在文件夹中分别创建字母,数字,标点键盘按钮配置的xml文件,可以根据自己的样式来布局,只要把key对应的code和keyLabel属性对应就行。这个样式是根据我的硬件设备写的,键盘配置布局得自己调节。
说明:Keyboard标签下的keyWidth和keyHeight属性为每个按钮的宽高,可以为准确数值,也可以为百分比值(例:10%p,父集的百分之10长度);horizontalGap和verticalGap为每个按钮中间的横竖间距;keyIcon为图片路径。
1.1 . 字母键盘配置:
<?xml version="1.0" encoding="utf-8"?>
<Keyboard
xmlns:android="http://schemas.android.com/apk/res/android"
android:keyHeight="10%p"
android:keyWidth="168dp"
android:horizontalGap="17dp"
android:verticalGap="20px">
<Row>
<Key android:codes="113" android:keyLabel="q" android:keyEdgeFlags="left" />
<Key android:codes="119" android:keyLabel="w" />
<Key android:codes="101" android:keyLabel="e" />
<Key android:codes="114" android:keyLabel="r" />
<Key android:codes="116" android:keyLabel="t" />
<Key android:codes="121" android:keyLabel="y" />
<Key android:codes="117" android:keyLabel="u" />
<Key android:codes="105" android:keyLabel="i" />
<Key android:codes="111" android:keyLabel="o" />
<Key android:codes="112" android:keyLabel="p" android:keyEdgeFlags="right" />
</Row>
<Row>
<Key android:horizontalGap="70dp" android:codes="97"
android:keyEdgeFlags="left" android:keyLabel="a" />
<Key android:codes="115" android:keyLabel="s" />
<Key android:codes="100" android:keyLabel="d" />
<Key android:codes="102" android:keyLabel="f" />
<Key android:codes="103" android:keyLabel="g" />
<Key android:codes="104" android:keyLabel="h" />
<Key android:codes="106" android:keyLabel="j" />
<Key android:codes="107" android:keyLabel="k" />
<Key android:codes="108" android:keyEdgeFlags="right"
android:keyLabel="l" />
</Row>
<Row>
<Key android:keyWidth="252dp" android:codes="-1"
android:keyEdgeFlags="left" android:isModifier="true"
android:isSticky="true" android:keyIcon="@drawable/sym_keyboard_shift" />
<Key android:codes="122" android:keyLabel="z" />
<Key android:codes="120" android:keyLabel="x" />
<Key android:codes="99" android:keyLabel="c" />
<Key android:codes="118" android:keyLabel="v" />
<Key android:codes="98" android:keyLabel="b" />
<Key android:codes="110" android:keyLabel="n" />
<Key android:codes="109" android:keyLabel="m" />
<Key android:keyWidth="252dp" android:codes="-5"
android:keyEdgeFlags="right" android:isRepeatable="true"
android:keyIcon="@drawable/sym_keyboard_delete" />
</Row>
<Row android:rowEdgeFlags="bottom">
<Key android:keyWidth="252dp" android:codes="-2"
android:keyLabel="\?123" />
<Key android:codes="64" android:keyLabel="\@" />
<Key android:keyWidth="725dp" android:codes="32"
android:isRepeatable="true" android:keyIcon="@drawable/sym_keyboard_space" />
<Key android:codes="44"
android:keyLabel="," />
<Key android:codes="46"
android:keyLabel="." />
<Key android:keyWidth="252dp" android:codes="-4"
android:keyEdgeFlags="right" android:keyLabel="完成" />
</Row>
</Keyboard>
1.2 . 数字键盘配置:
<?xml version="1.0" encoding="utf-8"?>
<Keyboard
xmlns:android="http://schemas.android.com/apk/res/android"
android:keyWidth="450dp"
android:keyHeight="10%p"
android:horizontalGap="30px"
android:verticalGap="20px">
<Row >
<Key android:codes="57419" android:keyLabel="←" />
<Key android:codes="49" android:keyLabel="1" />
<Key android:codes="50" android:keyLabel="2"/>
<Key android:codes="51" android:keyLabel="3" />
<Key android:codes="-5" android:keyIcon="@drawable/sym_keyboard_delete"
android:isRepeatable="true" />
</Row>
<Row>
<Key android:codes="57421" android:keyLabel="→" />
<Key android:codes="52" android:keyLabel="4" />
<Key android:codes="53" android:keyLabel="5" />
<Key android:codes="54" android:keyLabel="6" />
<Key android:codes="-4" android:isRepeatable="true" android:keyLabel="完成" />
</Row>
<Row >
<Key android:codes="-7" android:isRepeatable="true"
android:keyLabel="\#+=" />
<Key android:codes="55" android:keyLabel="7" />
<Key android:codes="56" android:keyLabel="8" />
<Key android:codes="57" android:keyLabel="9" />
<Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space" />
</Row>
<Row >
<Key android:codes="-2" android:keyLabel="ABC" />
<Key android:codes="44" android:keyLabel="," />
<Key android:codes="48" android:keyLabel="0" />
<Key android:codes="46" android:keyLabel="." />
<Key android:codes="-3" android:isRepeatable="true" android:keyIcon="@drawable/sym_keyboard_cancle" />
</Row>
</Keyboard>
1.3 . 标点键盘配置:
<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
android:keyHeight="10%p"
android:keyWidth="168dp"
android:horizontalGap="17dp"
android:verticalGap="20px">
<Row>
<Key
android:codes="126" android:keyLabel="~" />
<Key
android:codes="33" android:keyLabel="!" />
<Key
android:codes="64" android:keyLabel="\@" />
<Key
android:codes="35" android:keyLabel="#" />
<Key
android:codes="36" android:keyLabel="$" />
<Key
android:codes="37" android:keyLabel="%" />
<Key
android:codes="94" android:keyLabel="^" />
<Key
android:codes="38" android:keyLabel="&" />
<Key
android:codes="42" android:keyLabel="*" />
<Key
android:codes="40" android:keyLabel="(" />
</Row>
<Row>
<Key
android:horizontalGap="70dp" android:codes="96"
android:keyLabel="`" />
<Key
android:codes="45" android:keyLabel="-" />
<Key
android:codes="43" android:keyLabel="+" />
<Key
android:codes="61" android:keyLabel="=" />
<Key
android:codes="91" android:keyLabel="[" />
<Key
android:codes="93" android:keyLabel="]" />
<Key
android:codes="123" android:keyLabel="{" />
<Key
android:codes="125" android:keyLabel="}" />
<Key
android:codes="41" android:keyLabel=")" />
</Row>
<Row>
<Key
android:codes="-7"
android:isModifier="true"
android:isSticky="true"
android:keyEdgeFlags="left"
android:keyLabel="\?123"
android:keyWidth="252dp" />
<Key
android:codes="95" android:keyLabel="_" />
<Key
android:codes="58" android:keyLabel=":" />
<Key
android:codes="59" android:keyLabel=";" />
<Key
android:codes="39" android:keyLabel="'" />
<Key
android:codes="34" android:keyLabel=""" />
<Key
android:codes="92" android:keyLabel="\\" />
<Key
android:codes="124" android:keyLabel="|" />
<Key
android:codes="-5"
android:isRepeatable="true"
android:keyEdgeFlags="right"
android:keyIcon="@drawable/sym_keyboard_delete"
android:keyWidth="252dp" />
</Row>
<Row android:rowEdgeFlags="bottom">
<Key
android:codes="-2" android:keyLabel="ABC"
android:keyWidth="252dp" />
<Key
android:codes="60" android:keyLabel="<" />
<Key
android:codes="62" android:keyLabel=">" />
<Key
android:codes="44" android:keyLabel="," />
<Key
android:codes="32"
android:isRepeatable="true"
android:rowEdgeFlags="bottom"
android:keyIcon="@drawable/sym_keyboard_space" />
<Key
android:codes="46" android:keyLabel="." />
<Key
android:codes="63" android:keyLabel="\?" />
<Key
android:codes="47" android:keyLabel="/" />
<Key
android:codes="-4"
android:keyEdgeFlags="right"
android:keyLabel="完成"
android:keyWidth="252dp" />
</Row>
</Keyboard>
2 . 封装一个工具类,用于实例调用自定义软键盘
import android.content.Context;
import android.inputmethodservice.Keyboard;
import android.inputmethodservice.KeyboardView;
import android.text.Editable;
import android.view.View;
import android.widget.EditText;
import com.lh.tcamera.R;
import java.util.List;
public class KeyboardUtil {
private Context mContext;
private KeyboardView mKeyboardView;
private Keyboard mNumberKeyboard; // 数字键盘
private Keyboard mLetterKeyboard; // 字母键盘
private Keyboard mPunctuateKeyboard; // 标点键盘
private boolean isNumber = false; // 是否数字键盘
private boolean isUpper = false; // 是否大写
private boolean isPun = false; // 是否标点
private EditText mEditText;
public final int KEYCODE_PUN = -7;
public final int NUMBERDECIMAL = 0x00002002;//只显示数字键盘
public int inputType ; // 0:字母键盘,1:数字键盘,2:字符键盘
private OnClickDone onClickDone;
public interface OnClickDone{
void onDone();
}
public KeyboardUtil(Context context, KeyboardView view, int inputType) {
this.inputType = inputType;
this.mContext = context;
this.isNumber = inputType == 1;
mNumberKeyboard = new Keyboard(mContext, R.xml.keyboard_numbers);
mLetterKeyboard = new Keyboard(mContext, R.xml.keyboard_qwerty);
mPunctuateKeyboard = new Keyboard(mContext, R.xml.keyboard_punctuate);
mKeyboardView = view;
List<Keyboard.Key> mNumberKeyList = mNumberKeyboard.getKeys();
for (Keyboard.Key key : mNumberKeyList) {
if(key!=null ){
if( key.codes[0] == -2 || key.codes[0] == -3|| key.codes[0] == -4
||key.codes[0] == -5 || key.codes[0] == -7||key.codes[0] == 32
||key.codes[0] == 46||key.codes[0] == 57419||key.codes[0] == 57421
||key.codes[0] == 44) {
key.onPressed();
}
}
}
List<Keyboard.Key> mLetterKeyList = mLetterKeyboard.getKeys();
for (Keyboard.Key key : mLetterKeyList) {
if(key!=null ){
if(key.codes[0] == -1 || key.codes[0] == -2 || key.codes[0] == -4||key.codes[0] == -5){
key.onPressed();
}
}
}
List<Keyboard.Key> mPunctuateKeyList = mPunctuateKeyboard.getKeys();
for (Keyboard.Key key : mPunctuateKeyList) {
if(key!=null ){
if( key.codes[0] == -2 || key.codes[0] == -4||key.codes[0] == -5 || key.codes[0] == -7) {
key.onPressed();
}
}
}
switch (inputType){
case 0:
mKeyboardView.setKeyboard(mLetterKeyboard);
break;
case 1:
mKeyboardView.setKeyboard(mNumberKeyboard);
break;
case 2:
mKeyboardView.setKeyboard(mPunctuateKeyboard);
break;
default:
mKeyboardView.setKeyboard(mLetterKeyboard);
break;
}
mKeyboardView.setEnabled(true);
mKeyboardView.setPreviewEnabled(false);
mKeyboardView.setOnKeyboardActionListener(listener);
}
private KeyboardView.OnKeyboardActionListener listener = new KeyboardView.OnKeyboardActionListener() {
@Override
public void onPress(int primaryCode) {}
@Override
public void onRelease(int primaryCode) {}
@Override
public void onKey(int primaryCode, int[] keyCodes) {
Editable editable = mEditText.getText();
int start = mEditText.getSelectionStart();
if (primaryCode == Keyboard.KEYCODE_CANCEL) { // cancel
hideKeyboard();
} else if (primaryCode == Keyboard.KEYCODE_DONE) { // done
if(onClickDone!=null){
onClickDone.onDone();
}
} else if (primaryCode == Keyboard.KEYCODE_DELETE) { // 回退
if (editable != null && editable.length() > 0) {
if (start > 0) {
editable.delete(start - 1, start);
}
}
} else if (primaryCode == Keyboard.KEYCODE_SHIFT) { // 大小写切换
changeKeyboart();
mKeyboardView.setKeyboard(mLetterKeyboard);
} else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE) { // 数字键盘切换
if (isNumber) {
if(mEditText.getInputType() == NUMBERDECIMAL){
return;
}
isNumber = false;
mKeyboardView.setKeyboard(mLetterKeyboard);
} else {
if(isPun){
isPun = false;
mKeyboardView.setKeyboard(mLetterKeyboard);
}else{
isNumber = true;
mKeyboardView.setKeyboard(mNumberKeyboard);
}
}
}else if(primaryCode== KEYCODE_PUN){
if(mEditText.getInputType() == NUMBERDECIMAL){
return;
}
if(isPun){
isPun = false;
isNumber =true;
mKeyboardView.setKeyboard(mNumberKeyboard);
}else {
isPun = true;
isNumber = false;
mKeyboardView.setKeyboard(mPunctuateKeyboard);
}
}else if (primaryCode == 57419) { // 左移
if (start > 0) {
mEditText.setSelection(start - 1);
}
} else if (primaryCode == 57421) { // 右移
if (start < mEditText.length()) {
mEditText.setSelection(start + 1);
}
} else { // 输入键盘值
editable.insert(start, Character.toString((char) primaryCode));
}
}
@Override
public void onText(CharSequence text) {}
@Override
public void swipeLeft() {}
@Override
public void swipeRight() {}
@Override
public void swipeDown() {}
@Override
public void swipeUp() {}
};
private void changeKeyboart() {
List<Keyboard.Key> keyList = mLetterKeyboard.getKeys();
if (isUpper) { // 大写切换小写
isUpper = false;
for (Keyboard.Key key : keyList) {
if(key.codes[0] == -1){
key.onPressed();
}
if (key.label != null && isLetter(key.label.toString())) {
key.label = key.label.toString().toLowerCase();
key.codes[0] = key.codes[0] + 32;
}
}
} else { // 小写切换成大写
isUpper = true;
for (Keyboard.Key key : keyList) {
if(key.codes[0] == -1){
key.onPressed();
}
if (key.label != null && isLetter(key.label.toString())) {
key.label = key.label.toString().toUpperCase();
key.codes[0] = key.codes[0] - 32;
}
}
}
}
/**
* 判断是否是字母
*/
private boolean isLetter(String str) {
String wordStr = "abcdefghijklmnopqrstuvwxyz";
return wordStr.contains(str.toLowerCase());
}
public void hideKeyboard() {//隐藏软键盘
int visibility = mKeyboardView.getVisibility();
if (visibility == View.VISIBLE) {
mKeyboardView.setVisibility(View.INVISIBLE);
}
}
public void showKeyboard(EditText editText, OnClickDone onClickDone) {//显示软键盘
mEditText = editText;
this.onClickDone = onClickDone;
int visibility = mKeyboardView.getVisibility();
if (visibility == View.GONE || visibility == View.INVISIBLE) {
mKeyboardView.setVisibility(View.VISIBLE);
}
}
}
3 . layout布局文件
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/keyboard_btn_test"
android:layout_width="220dp"
android:layout_height="60dp"
android:layout_gravity="center|top"
android:gravity="center"
android:paddingTop="10dp"
android:text="测试按钮,点击弹出自定义软键盘"
android:textSize="28sp"
android:textColor="@color/btn_gray"/>
<!-- 自定义软键盘布局 -->
<FrameLayout
android:id="@+id/keyboard_bg_key"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00ffffff">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:paddingTop="15dp"
android:paddingBottom="30dp"
android:paddingLeft="30dp"
android:paddingRight="30dp"
android:background="#D6D9DE"
android:orientation="vertical"
android:visibility="visible">
<EditText
android:id="@+id/keyboard_et_content"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center|left"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:background="@drawable/rounded_10_white_fill"
android:text="hahaha"
android:textColor="@color/btn_black"
android:textSize="28sp"
android:maxLines="1"/>
<android.inputmethodservice.KeyboardView
android:id="@+id/keyboard_kv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:paddingTop="15dp"
android:background="#D6D9DE"
android:focusable="false"
android:focusableInTouchMode="true"
android:keyPreviewLayout="@layout/key_preview_layout"
android:shadowRadius="0.0"
android:keyBackground="@drawable/btn_keyboard_key"
android:keyTextColor="#747474"
android:keyTextSize="36dp"
android:labelTextSize="48dp"
android:visibility="visible"/>
</LinearLayout>
</FrameLayout>
</FrameLayout>
4 . 在Activity中调用:
import android.app.Activity;
import android.inputmethodservice.KeyboardView;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import com.lh.tcamera.R;
/**
* 自定义软键盘
*/
public class KeyBoardActivity extends Activity implements KeyboardUtil.OnClickDone{
private TextView keyboard_btn_test;
private KeyboardView keyboardView;
private View keyboard_bg_key;
private EditText keyboard_et_content;
private KeyboardUtil keyboardUtil;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_keyboard);
//initview
keyboard_btn_test = (TextView) findViewById(R.id.keyboard_btn_test);
keyboardView = (KeyboardView) findViewById(R.id.keyboard_kv);
keyboard_bg_key = findViewById(R.id.keyboard_bg_key);
keyboard_et_content = (EditText) findViewById(R.id.keyboard_et_content);
//添加监听
keyboard_btn_test.setOnClickListener(clickListener);
//EditText 获得焦点时不弹出软键盘
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
keyboard_et_content.setShowSoftInputOnFocus(false);
}
keyboardUtil = new KeyboardUtil(this, keyboardView, 0);
}
@Override
public void onDone(){
//完成按钮处理接口
}
//点击
private void clickETTest() {
keyboard_et_content.setText(keyboard_btn_test.getText().toString().trim());
keyboardUtil.showKeyboard(keyboard_et_content, this);
keyboard_bg_key.setVisibility(View.VISIBLE);
}
private View.OnClickListener clickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.keyboard_btn_test:
{
clickETTest();
break;
}
}
}
};
}
5 . 备注:
5.1 注意将系统键盘禁用掉:
一是在AndroidManifest.xml权限文件中,在你想禁用的Activity中隐藏掉系统键盘:
<activity android:name=".KeyBoard.KeyBoardActivity" android:windowSoftInputMode="stateHidden"/>
二是在在Activity类中设置不失去焦点并隐藏系统键盘:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
keyboard_et_content.setShowSoftInputOnFocus(false);
}
5.2 注意将系统键盘禁用掉:
键盘配置布局可以根据自己的需求去设计,我的仅供参考。