微信号:programmer_club

介绍:程序员第一自媒体,与你探讨码农人生路上遇到的各类泛技术话题,定期为你推荐码农人生思考、感悟以及启迪!

Android 自定义控件 - 仿支付宝数字键盘

2018-09-23 22:00 程序员之家
简介

在一些带有支付功能的 App 中,输入的密码一般只能是纯数字,虽然我们可以指定 EditText 输入框只能输入数字,但是为了提供用户的使用体验,我们往往更倾向于使用自定义的纯数字键盘。

本文效果:

实现步骤:

集成系统的 KeyBoardView 类,在初始化时初始化键盘布局,设置 KeyBoard 对象。

实现 OnKeyboardActionListener 接口,处理按键交互事件。

根据需求绘制按键背景和按键图标。

设置监听器,将输入的内容回调给调用方。

键盘布局

在 res/xml/ 目录下创建 xml 文件:key_password_number.xml

<?xml version="1.0" encoding="utf-8"?>
<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
     */

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        List<Keyboard.Key> 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);
        }
    }


    @Override
    public void onPress(int primaryCode) {

    }

    @Override
    public void onRelease(int primaryCode) {

    }

    /**
    * 处理按键的点击事件
    */

    @Override
    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));
            }
        }


    }

    @Override
    public void onText(CharSequence charSequence) {

    }

    @Override
    public void swipeLeft() {

    }

    @Override
    public void swipeRight() {

    }

    @Override
    public void swipeDown() {

    }

    @Override
    public void swipeUp() {

    }

    public interface OnKeyListener {
        // 输入回调
        void onInput(String text);
       // 删除回调
        void onDelete();
    }

    private OnKeyListener listener;

    public void setOnKeyListener(OnKeyListener listener) {
        this.listener = listener;
    }

}

使用 PwdKeyboardView

<com.xing.pwdkeyboardview.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" />      <!-- shadowRadius = 0 ,防止按键数字显示模糊 --->

显示结果为:

完整代码:https://github.com/xing16/PwdKeyboardView

本文转载自【Android开发中文站】


公众号内回复“1”带你进粉丝群

 
程序员之家 更多文章 开发者玩起情怀来,H5也烧脑 崩溃了!程序员大战陈安之!! 苹果新品发布会,我们整理了外国人的各种评论、吐槽和斗图... 分享图片 除了公司和家,程序员最喜欢去星巴克,是这样吗?
猜您喜欢 ThinkPHP V5.0.2版本发布——程序员节的祝福 Python掌上论坛来啦 !!! Libvirt/KVM 中的网络模式 ❲起航2016❳大型网站架构之分布式消息队列 荐!12招轻松搞定用户深度访谈