Android 开发 自定义身份证键盘

前言

自定义 身份证键盘 Activity 版 其余未做兼容

一、IdCardUtil 工具类

java 复制代码
/**
 * 自定义身份证键盘工具类
 */
public class IdCardUtil {
    private final Context context;
    private final EditText editText;
    private final PopupWindow popupWindow;
    private final View keyboardView;
    private static final int MAX_LENGTH = 18;

    public IdCardUtil(Context context, EditText editText) {
        this.context = context;
        this.editText = editText;

        // 彻底禁用系统键盘
        editText.setShowSoftInputOnFocus(false);
        editText.setInputType(InputType.TYPE_CLASS_TEXT);
        editText.setLongClickable(false);
        editText.setCursorVisible(false);

        keyboardView = View.inflate(context, R.layout.view_id_card_keyboard, null);
        popupWindow = new PopupWindow(
                keyboardView,
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT
        );
        popupWindow.setFocusable(false);
        popupWindow.setBackgroundDrawable(null);
        popupWindow.setOutsideTouchable(true);
        popupWindow.setTouchable(true);

        // 返回键关闭
        keyboardView.setOnKeyListener((v, keyCode, event) -> {
            if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
                hideKeyboard();
                return true;
            }
            return false;
        });

        initListener();
        initButtons();
    }

    private void initListener() {
        // 触摸移动光标 → 键盘不消失
        editText.setOnTouchListener((v, event) -> {
            editText.setCursorVisible(true);
            if (!popupWindow.isShowing()) {
                closeAllOtherKeyboards();
                showAtBottom();
            }
            return false;
        });

        // 焦点切换
        editText.setOnFocusChangeListener((v, hasFocus) -> {
            if (hasFocus) {
                closeAllOtherKeyboards();
                editText.setCursorVisible(true);
                if (!popupWindow.isShowing()) {
                    showAtBottom();
                }
            } else {
                hideKeyboard();
                editText.setCursorVisible(false);
            }
        });
    }

    // 关闭其他所有键盘
    private void closeAllOtherKeyboards() {
        try {
            InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);

            View decorView = ((android.app.Activity) context).getWindow().getDecorView();
            clearFocus(decorView);
        } catch (Exception ignored) {
        }
    }

    private void clearFocus(View view) {
        if (view instanceof ViewGroup) {
            for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
                clearFocus(((ViewGroup) view).getChildAt(i));
            }
        } else if (view instanceof EditText && view != editText) {
            view.clearFocus();
        }
    }

    private void initButtons() {
        int[] ids = {
                R.id.btn_0, R.id.btn_1, R.id.btn_2, R.id.btn_3,
                R.id.btn_4, R.id.btn_5, R.id.btn_6, R.id.btn_7,
                R.id.btn_8, R.id.btn_9
        };
        for (int id : ids) {
            keyboardView.findViewById(id).setOnClickListener(v -> {
                String num = ((Button) v).getText().toString();
                input(num);
            });
        }

        keyboardView.findViewById(R.id.btn_x).setOnClickListener(v -> input("X"));
        keyboardView.findViewById(R.id.btn_delete).setOnClickListener(v -> delete());
    }

    private void input(String text) {
        String current = editText.getText().toString();
        if (current.length() >= MAX_LENGTH) return;
        if ("X".equals(text) && current.length() != 17) return;

        int start = editText.getSelectionStart();
        editText.getText().insert(start, text);
    }

    private void delete() {
        Editable ed = editText.getText();
        int start = editText.getSelectionStart();
        if (start > 0) {
            ed.delete(start - 1, start);
        }
    }

    //不遮挡输入框
    public void showAtBottom() {
        View decorView = ((android.app.Activity) context).getWindow().getDecorView();
        FrameLayout contentView = ((android.app.Activity) context).findViewById(android.R.id.content);
        View rootView = contentView.getChildAt(0);

        int[] location = new int[2];
        editText.getLocationInWindow(location);
        int screenHeight = context.getResources().getDisplayMetrics().heightPixels;
        int keyboardHeight = dp2px(220);

        // 自动滚动界面,保证输入框完全露出,不被键盘遮挡
        int scrollY = rootView.getScrollY();
        int needScroll = (location[1] + editText.getHeight() + keyboardHeight + dp2px(20)) - screenHeight;
        if (needScroll > 0) {
            rootView.scrollTo(0, scrollY + needScroll);
        }

        popupWindow.showAtLocation(decorView, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0);
    }

    public void hideKeyboard() {
        if (popupWindow.isShowing()) {
            popupWindow.dismiss();
        }
        // 关闭时页面回滚
        try {
            FrameLayout contentView = ((android.app.Activity) context).findViewById(android.R.id.content);
            View rootView = contentView.getChildAt(0);
            rootView.scrollTo(0, 0);
        } catch (Exception ignored) {
        }
    }

    public boolean isShowing() {
        return popupWindow.isShowing();
    }

    private int dp2px(float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }
}

二、布局文件

view_id_card_keyboard

XML 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/shape_bg_dialog"
    android:orientation="vertical"
    android:padding="5dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:id="@+id/btn_1"
            android:layout_width="0dp"
            android:layout_height="50dp"
            android:layout_margin="@dimen/dimen_5"
            android:layout_weight="1"
            android:background="@drawable/shape_white_8"
            android:text="1"
            android:textSize="18sp" />

        <Button
            android:id="@+id/btn_2"
            android:layout_width="0dp"
            android:layout_height="50dp"
            android:layout_margin="@dimen/dimen_5"
            android:layout_weight="1"
            android:background="@drawable/shape_white_8"
            android:text="2"
            android:textSize="18sp" />

        <Button
            android:id="@+id/btn_3"
            android:layout_width="0dp"
            android:layout_height="50dp"
            android:layout_margin="@dimen/dimen_5"
            android:layout_weight="1"
            android:background="@drawable/shape_white_8"
            android:text="3"
            android:textSize="18sp" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:id="@+id/btn_4"
            android:layout_width="0dp"
            android:layout_height="50dp"
            android:layout_margin="@dimen/dimen_5"
            android:layout_weight="1"
            android:background="@drawable/shape_white_8"
            android:text="4"
            android:textSize="18sp" />

        <Button
            android:id="@+id/btn_5"
            android:layout_width="0dp"
            android:layout_height="50dp"
            android:layout_margin="@dimen/dimen_5"
            android:layout_weight="1"
            android:background="@drawable/shape_white_8"
            android:text="5"
            android:textSize="18sp" />

        <Button
            android:id="@+id/btn_6"
            android:layout_width="0dp"
            android:layout_height="50dp"
            android:layout_margin="@dimen/dimen_5"
            android:layout_weight="1"
            android:background="@drawable/shape_white_8"
            android:text="6"
            android:textSize="18sp" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:id="@+id/btn_7"
            android:layout_width="0dp"
            android:layout_height="50dp"
            android:layout_margin="@dimen/dimen_5"
            android:layout_weight="1"
            android:background="@drawable/shape_white_8"
            android:text="7"
            android:textSize="18sp" />

        <Button
            android:id="@+id/btn_8"
            android:layout_width="0dp"
            android:layout_height="50dp"
            android:layout_margin="@dimen/dimen_5"
            android:layout_weight="1"
            android:background="@drawable/shape_white_8"
            android:text="8"
            android:textSize="18sp" />

        <Button
            android:id="@+id/btn_9"
            android:layout_width="0dp"
            android:layout_height="50dp"
            android:layout_margin="@dimen/dimen_5"
            android:layout_weight="1"
            android:background="@drawable/shape_white_8"
            android:text="9"
            android:textSize="18sp" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:id="@+id/btn_x"
            android:layout_width="0dp"
            android:layout_height="50dp"
            android:layout_margin="@dimen/dimen_5"
            android:layout_weight="1"
            android:background="@drawable/shape_white_8"
            android:text="X"
            android:textSize="18sp" />

        <Button
            android:id="@+id/btn_0"
            android:layout_width="0dp"
            android:layout_height="50dp"
            android:layout_margin="@dimen/dimen_5"
            android:layout_weight="1"
            android:background="@drawable/shape_white_8"
            android:text="0"
            android:textSize="18sp" />

        <Button
            android:id="@+id/btn_delete"
            android:layout_width="0dp"
            android:layout_height="50dp"
            android:layout_margin="@dimen/dimen_5"
            android:layout_weight="1"
            android:background="@drawable/shape_white_8"
            android:text="删除"
            android:textSize="16sp" />
    </LinearLayout>

</LinearLayout>

圆角shape_white_8

XML 复制代码
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
	<solid android:color="@color/white" />
	<!-- 圆角 -->
	<corners
		android:radius="@dimen/dimen_8"/>
</shape>

半圆角 shape_bg_dialog

XML 复制代码
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- solid:实心,就是填充的意思  -->
	<solid android:color="@color/c_f5f6f7" />
	<!-- 圆角 -->
	<corners
		android:topLeftRadius="@dimen/dimen_10"
		android:topRightRadius="@dimen/dimen_10"/>
</shape>

三、使用步骤

java 复制代码
EditText zjHmEdt = findViewById(R.id.lq_zjhm_edt);
IdCardUtil idCardKeyboardManager = new IdCardUtil(this, zjHmEdt);
java 复制代码
    // 返回键优先关闭身份证键盘
    @Override
    public void onBackPressed() {
        if (idCardKeyboardManager != null && idCardKeyboardManager.isShowing()) {
            idCardKeyboardManager.hideKeyboard();
            return;
        }
        super.onBackPressed();
    }
相关推荐
深念Y2 小时前
乐播投屏电视广告逆向分析实录:从Activity追踪到放弃
android
雪芽蓝域zzs2 小时前
uniapp 真机上传图片提示打包未添加Camera模块
android·uni-app
LionelRay3 小时前
Composables 的生命周期
android
修炼者11 小时前
【进阶Android】HashMap 的并发“车祸”
android
冬奇Lab13 小时前
Android 15音频子系统(六):音频焦点管理机制深度解析
android·音视频开发·源码阅读
LionelRay15 小时前
Thinking in Compose
android
用户693717500138417 小时前
Google 推 AppFunctions:手机上的 AI 终于能自己干活了
android·前端·人工智能
用户693717500138417 小时前
AI让编码变简单,真正拉开差距的是UI设计和产品思考
android·前端·人工智能