前言
自定义 身份证键盘 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();
}