Android 自定义输入支付密码的软键盘实例代码
android 自定义输入支付密码的软键盘
有项目需求需要做一个密码锁功能,还有自己的软键盘,类似与支付宝那种,这里是整理的资料,大家可以看下,如有错误,欢迎留言指正
需求:要实现类似支付宝的输入支付密码的功能,效果图如下:
软键盘效果图
使用 android.inputmethodservice.keyboardview 这个类自定义软键盘
软键盘的实现
1. 自定义只输入数字的软键盘 passwordkeyboardview 类,继承自 android.inputmethodservice.keyboardview
/** * 输入数字密码的键盘布局控件。 */ public class passwordkeyboardview extends keyboardview implements android.inputmethodservice.keyboardview.onkeyboardactionlistener { // 用于区分左下角空白的按键 private static final int keycode_empty = -10; private int mdeletebackgroundcolor; private rect mdeletedrawrect; private drawable mdeletedrawable; private ionkeyboardlistener monkeyboardlistener; public passwordkeyboardview(context context, attributeset attrs) { super(context, attrs); init(context, attrs, 0); } public passwordkeyboardview(context context, attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); init(context, attrs, defstyleattr); } private void init(context context, attributeset attrs, int defstyleattr) { typedarray a = context.obtainstyledattributes(attrs, r.styleable.passwordkeyboardview, defstyleattr, 0); mdeletedrawable = a.getdrawable( r.styleable.passwordkeyboardview_pkvdeletedrawable); mdeletebackgroundcolor = a.getcolor( r.styleable.passwordkeyboardview_pkvdeletebackgroundcolor, color.transparent); a.recycle(); // 设置软键盘按键的布局 keyboard keyboard = new keyboard(context, r.xml.keyboard_number_password); setkeyboard(keyboard); setenabled(true); setpreviewenabled(false); setonkeyboardactionlistener(this); } @override public void ondraw(canvas canvas) { super.ondraw(canvas); // 遍历所有的按键 list<keyboard.key> keys = getkeyboard().getkeys(); for (keyboard.key key : keys) { // 如果是左下角空白的按键,重画按键的背景 if (key.codes[0] == keycode_empty) { drawkeybackground(key, canvas, mdeletebackgroundcolor); } // 如果是右下角的删除按键,重画背景,并且绘制删除的图标 else if (key.codes[0] == keyboard.keycode_delete) { drawkeybackground(key, canvas, mdeletebackgroundcolor); drawdeletebutton(key, canvas); } } } // 绘制按键的背景 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); } // 绘制删除按键 private void drawdeletebutton(keyboard.key key, canvas canvas) { if (mdeletedrawable == null) return; // 计算删除图标绘制的坐标 if (mdeletedrawrect == null || mdeletedrawrect.isempty()) { int intrinsicwidth = mdeletedrawable.getintrinsicwidth(); int intrinsicheight = mdeletedrawable.getintrinsicheight(); int drawwidth = intrinsicwidth; int drawheight = intrinsicheight; // 限制图标的大小,防止图标超出按键 if (drawwidth > key.width) { drawwidth = key.width; drawheight = drawwidth * intrinsicheight / intrinsicwidth; } if (drawheight > key.height) { drawheight = key.height; drawwidth = drawheight * intrinsicwidth / intrinsicheight; } // 获取删除图标绘制的坐标 int left = key.x + (key.width - drawwidth) / 2; int top = key.y + (key.height - drawheight) / 2; mdeletedrawrect = new rect(left, top, left + drawwidth, top + drawheight); } // 绘制删除的图标 if (mdeletedrawrect != null && !mdeletedrawrect.isempty()) { mdeletedrawable.setbounds(mdeletedrawrect.left, mdeletedrawrect.top, mdeletedrawrect.right, mdeletedrawrect.bottom); mdeletedrawable.draw(canvas); } } @override public void onkey(int primarycode, int[] keycodes) { // 处理按键的点击事件 // 点击删除按键 if (primarycode == keyboard.keycode_delete) { if (monkeyboardlistener != null) { monkeyboardlistener.ondeletekeyevent(); } } // 点击了非左下角按键的其他按键 else if (primarycode != keycode_empty) { if (monkeyboardlistener != null) { monkeyboardlistener.oninsertkeyevent( character.tostring((char) primarycode)); } } } @override public void onpress(int primarycode) { } @override public void onrelease(int primarycode) { } @override public void ontext(charsequence text) { } @override public void swipeleft() { } @override public void swiperight() { } @override public void swipedown() { } @override public void swipeup() { } /** * 设置键盘的监听事件。 * * @param listener * 监听事件 */ public void setionkeyboardlistener(ionkeyboardlistener listener) { this.monkeyboardlistener = listener; } public interface ionkeyboardlistener { void oninsertkeyevent(string text); void ondeletekeyevent(); } }
2. 自定义属性:
values/attrs.xml
<declare-styleable name="passwordkeyboardview"> <attr name="pkvdeletedrawable" format="reference"/> <attr name="pkvdeletebackgroundcolor" format="color|reference"/> </declare-styleable>
3. 软键盘按键的布局文件 res/xml/keyboard_number_password:
说明:
- android:keywidth="33.33333%p":指定按键的宽度,保证键盘的每一列宽度一致
- android:keyheight="8%p":设置键盘的高度
- android:horizontalgap="1dp":实现键盘每一列之间的分割线
- android:verticalgap="1dp":实现键盘每一行之间的分割线
<?xml version="1.0" encoding="utf-8"?> <keyboard xmlns:android="http://schemas.android.com/apk/res/android" android:keywidth="33.33333%p" android:keyheight="8%p" android:horizontalgap="1dp" 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:keyicon="@mipmap/keyboard_backspace"/> </row> </keyboard>
3. 在布局中引用软键盘控件:
<[包名].passwordkeyboardview android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#b0b0b0" android:focusable="true" android:focusableintouchmode="true" android:keybackground="#ffffff" android:keytextcolor="#000000" android:shadowcolor="#00000000" android:shadowradius="0" app:pkvdeletebackgroundcolor="#d2d2d2" app:pkvdeletedrawable="@drawable/keyboard_backspace" />
随机数字键盘的实现
目前能想到的有两种实现方式:
1. 在 ondraw 方法里重新绘制键盘上的文字,覆盖掉原来的键盘,这种实现方式相对比较麻烦。
2. 调用 keyboardview.setkeyboard() 方法重新设置键盘,实现的代码如下:
// 0-9 的数字 private final list<character> keycodes = arrays.aslist( '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); /** * 随机打乱数字键盘上显示的数字顺序。 */ public void shufflekeyboard() { keyboard keyboard = getkeyboard(); if (keyboard != null && keyboard.getkeys() != null && keyboard.getkeys().size() > 0) { // 随机排序数字 collections.shuffle(keycodes); // 遍历所有的按键 list<keyboard.key> keys = getkeyboard().getkeys(); int index = 0; for (keyboard.key key : keys) { // 如果按键是数字 if (key.codes[0] != keycode_empty && key.codes[0] != keyboard.keycode_delete) { char code = keycodes.get(index++); key.codes[0] = code; key.label = character.tostring(code); } } // 更新键盘 setkeyboard(keyboard); } }
调用 shufflekeyboard 即可生成随机的键盘。
最终实现的效果如下:
随机键盘
踩坑
1. 点击按键的放大镜效果提示
软键盘默认点击按键时会显示放大镜效果的提示,如果不需要可以使用 setpreviewenabled(false) 设置不显示提示。
可以在布局中使用 android:keypreviewlayout 指定提示文字的布局。
2. 按键文字不清晰
软键盘按键默认带有阴影效果,会导致文字不清楚,可以使用下面方式去掉阴影:
<[包名].passwordkeyboardview android:shadowcolor="@color/transparent" android:shadowradius="0" ... />
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
下一篇: Java采用循环链表结构求解约瑟夫问题