Android 自定义控件 - 仿支付宝数字键盘
简介
在一些带有支付功能的 App 中,输入的密码一般只能是纯数字,虽然我们可以指定 EditText 输入框只能输入数字,但是为了提供用户的使用体验,我们往往更倾向于使用自定义的纯数字键盘。
本文效果:
实现步骤:
集成系统的 KeyBoardView 类,在初始化时初始化键盘布局,设置 KeyBoard 对象。
实现 OnKeyboardActionListener 接口,处理按键交互事件。
根据需求绘制按键背景和按键图标。
设置监听器,将输入的内容回调给调用方。
键盘布局
在 res/xml/ 目录下创建 xml 文件:key_password_number.xml
< Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
android:horizontalGap="1dp"
android:keyHeight="9%p"
android:keyWidth="33.3333%p"
android:verticalGap="1dp">
< Row>
< Key
android:codes="49"
android:keyLabel="1" />
< Key
android:codes="50"
android:keyLabel="2" />
< Key
android:codes="51"
android:keyLabel="3" />
Row>
< Row>
< Key
android:codes="52"
android:keyLabel="4" />
< Key
android:codes="53"
android:keyLabel="5" />
< Key
android:codes="54"
android:keyLabel="6" />
Row>
< Row>
< Key
android:codes="55"
android:keyLabel="7" />
< Key
android:codes="56"
android:keyLabel="8" />
< Key
android:codes="57"
android:keyLabel="9" />
Row>
< Row>
< Key
android:codes="-10"
android:keyLabel="" />
< Key
android:codes="48"
android:keyLabel="0" />
< Key
android:codes="-5"
android:keyLabel="" />
Row>
Keyboard>
继承 KeyBoardView
public class PwdKeyboardView extends KeyboardView implements KeyboardView.OnKeyboardActionListener {
private static final String TAG = "PwdKeyboardView";
private static final int KEY_EMPTY = -10;
private int delKeyBackgroundColor = 0xffcccccc;
private Rect keyIconRect;
public PwdKeyboardView(Context context, AttributeSet attrs) {
super(context, attrs);
Log.d(TAG, "PwdKeyboardView: two params");
init(context);
}
public PwdKeyboardView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
Log.d(TAG, "PwdKeyboardView: three params");
init(context);
}
private void init(Context context) {
Keyboard keyboard = new Keyboard(context, R.xml.key_password_number); // 初始化 keyboard
setKeyboard(keyboard);
setEnabled(true);
setFocusable(true);
setPreviewEnabled(false); // 设置点击按键不显示预览气泡
setOnKeyboardActionListener(this);
}
/**
* 重新绘制删除按键和空白键
*
* @param canvas
*/
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
List keys = getKeyboard().getKeys();
for (Keyboard.Key key : keys) {
if (key.codes[0] == KEY_EMPTY) {
// 绘制空白键背景
drawKeyBackground(key, canvas, delKeyBackgroundColor);
}
if (key.codes[0] == Keyboard.KEYCODE_DELETE) {
// 删除删除按键背景
drawKeyBackground(key, canvas, delKeyBackgroundColor);
// 绘制删除按键图标
drawKeyIcon(key, canvas, getResources().getDrawable(R.drawable.ic_delete));
}
}
}
/**
* 绘制按键的背景
*
* @param key
* @param canvas
* @param color
*/
private void drawKeyBackground(Keyboard.Key key, Canvas canvas, int color) {
ColorDrawable drawable = new ColorDrawable(color);
drawable.setBounds(key.x, key.y, key.x + key.width, key.y + key.height);
drawable.draw(canvas);
}
/**
* 绘制按键的 icon
*
* @param key
* @param canvas
* @param iconDrawable
*/
private void drawKeyIcon(Keyboard.Key key, Canvas canvas, Drawable iconDrawable) {
if (iconDrawable == null) {
return;
}
// 计算按键icon 的rect 范围
if (keyIconRect == null || keyIconRect.isEmpty()) {
// 得到 keyicon 的显示大小,因为图片放在不同的drawable-dpi目录下,显示大小也不一样
int intrinsicWidth = iconDrawable.getIntrinsicWidth();
int intrinsicHeight = iconDrawable.getIntrinsicHeight();
int drawWidth = intrinsicWidth;
int drawHeight = intrinsicHeight;
// 限制图片的大小,防止图片按键范围
if (drawWidth > key.width) {
drawWidth = key.width;
// 此时高就按照比例缩放
drawHeight = (int) (drawWidth * 1.0f / intrinsicWidth * intrinsicHeight);
} else if (drawHeight > key.height) {
drawHeight = key.height;
drawWidth = (int) (drawHeight * 1.0f / intrinsicHeight * intrinsicWidth);
}
// 获取图片的 x,y 坐标,图片在按键的正中间
int left = key.x + key.width / 2 - drawWidth / 2;
int top = key.y + key.height / 2 - drawHeight / 2;
keyIconRect = new Rect(left, top, left + drawWidth, top + drawHeight);
}
if (keyIconRect != null && !keyIconRect.isEmpty()) {
iconDrawable.setBounds(keyIconRect);
iconDrawable.draw(canvas);
}
}
public void onPress(int primaryCode) {
}
public void onRelease(int primaryCode) {
}
/**
* 处理按键的点击事件
*/
public void onKey(int primaryCode, int[] keyCodes) {
Log.d(TAG, "onKey: primaryCode = " + primaryCode + ", keyCodes = " + Arrays.toString(keyCodes));
if (primaryCode == KEY_EMPTY) {
return;
}
if (listener != null) {
if (primaryCode == Keyboard.KEYCODE_DELETE) {
listener.onDelete();
} else {
listener.onInput(String.valueOf((char) primaryCode));
}
}
}
public void onText(CharSequence charSequence) {
}
public void swipeLeft() {
}
public void swipeRight() {
}
public void swipeDown() {
}
public void swipeUp() {
}
public interface OnKeyListener {
// 输入回调
void onInput(String text);
// 删除回调
void onDelete();
}
private OnKeyListener listener;
public void setOnKeyListener(OnKeyListener listener) {
this.listener = listener;
}
}
使用 PwdKeyboardView
android:id="@+id/key_board"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#919191"
android:keepScreenOn="true"
android:keyBackground="@drawable/selector_key_board" < ! --设置按键的背景选择器 -->
android:keyTextColor="@android:color/black"
android:keyTextSize="26sp"
android:shadowRadius="0" />
显示结果为:
完整代码:https://github.com/xing16/PwdKeyboardView
本文转载自【Android开发中文站】
公众号内回复“1”带你进粉丝群
关注公众号:拾黑(shiheibook)了解更多
[广告]赞助链接:
四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

随时掌握互联网精彩
赞助链接
排名
热点
搜索指数
- 1 总书记的两会“关心事” 7964683
- 2 中方回应菲前总统杜特尔特携女访港 7910063
- 3 苦等丈夫80多年 103岁的她去世 7873054
- 4 三大通道聚焦这些“大事小情” 7771800
- 5 国家版减肥指南来了 7692163
- 6 26岁小伙做泰山陪爬年入30多万 7585413
- 7 00后用DeepSeek1天卖出3.3亿 7402363
- 8 首批小米SU7 Ultra车标被抠 7349195
- 9 老人29块网购电三轮 快递巴掌大 7216557
- 10 乡村如何吸引并留住年轻人 7159287