Android自定义软键盘

为了解决系统软键盘切换可能导致的崩溃问题,本文详细介绍了如何在定制的Android设备上自定义软键盘。包括创建XML文件配置键盘按钮,封装键盘工具类,布局设计以及在Activity中的调用方法。同时提到了在AndroidManifest.xml中禁用系统键盘的步骤,以及在Activity中处理焦点和键盘显示的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近产品经理提出使用系统的软键盘一直点击切换可能会出现系统崩溃,因为是定制的安卓设备所以很容易出现此类问题,就研究了一下自定义软键盘,记录一下研究结果。

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="&#038;" />
        <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="&quot;" />
        <Key
            android:codes="92" android:keyLabel="&#92;&#92;" />
        <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="&lt;" />
        <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 注意将系统键盘禁用掉:
键盘配置布局可以根据自己的需求去设计,我的仅供参考。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值