欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android 自定义输入支付密码的软键盘实例代码

程序员文章站 2024-03-03 21:10:16
android 自定义输入支付密码的软键盘           &...

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:

说明:

  1. android:keywidth="33.33333%p":指定按键的宽度,保证键盘的每一列宽度一致
  2. android:keyheight="8%p":设置键盘的高度
  3. android:horizontalgap="1dp":实现键盘每一列之间的分割线
  4. 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 即可生成随机的键盘。

最终实现的效果如下:

Android 自定义输入支付密码的软键盘实例代码

随机键盘

踩坑

1. 点击按键的放大镜效果提示

软键盘默认点击按键时会显示放大镜效果的提示,如果不需要可以使用 setpreviewenabled(false) 设置不显示提示。
可以在布局中使用 android:keypreviewlayout 指定提示文字的布局。

2. 按键文字不清晰

软键盘按键默认带有阴影效果,会导致文字不清楚,可以使用下面方式去掉阴影:

<[包名].passwordkeyboardview
  android:shadowcolor="@color/transparent"
  android:shadowradius="0"
  ...
  />

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!