1. 程式人生 > >學習筆記-自定義密碼輸入框和自定義數字密碼軟鍵盤

學習筆記-自定義密碼輸入框和自定義數字密碼軟鍵盤

      最近專案裡有一個支付功能,需要自定義鍵盤,於是我在網上搜了一下,發現這個和我需求很相符,等專案完工,打算分享給大家,卻找不到專案的博主了,這裡還是感謝博主,我就直接貼程式碼分享給大家了;
XNumberKeyboardView.java
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.inputmethodservice.Keyboard;
import android.inputmethodservice.KeyboardView;
import android.util.AttributeSet;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * 數字鍵盤。
 *
 * @author wuzhen
 */
public class XNumberKeyboardView extends KeyboardView implements KeyboardView.OnKeyboardActionListener {

    // 用於區分左下角空白的按鍵
    private static final int KEYCODE_EMPTY = -10;

    private int mDeleteWidth;
    private int mDeleteHeight;
    private int mDeleteBackgroundColor;
    private Drawable mDeleteDrawable;
    private Rect mDeleteDrawRect;

    private IOnKeyboardListener mOnKeyboardListener;

    public XNumberKeyboardView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs, 0);
    }

    public XNumberKeyboardView(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.XNumberKeyboardView,
                defStyleAttr, 0);
        mDeleteDrawable = a.getDrawable(R.styleable.XNumberKeyboardView_xnkv_deleteDrawable);
        mDeleteBackgroundColor = a.getColor(
                R.styleable.XNumberKeyboardView_xnkv_deleteBackgroundColor, Color.TRANSPARENT);
        mDeleteWidth = a.getDimensionPixelOffset(R.styleable.XNumberKeyboardView_xnkv_deleteWidth,
                -1);
        mDeleteHeight = a.getDimensionPixelOffset(R.styleable.XNumberKeyboardView_xnkv_deleteHeight,
                -1);
        a.recycle();

        // 設定軟鍵盤按鍵的佈局
        Keyboard keyboard = new Keyboard(context, R.xml.keyboard_number);
        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 drawWidth, drawHeight;
            int intrinsicWidth = mDeleteDrawable.getIntrinsicWidth();
            int intrinsicHeight = mDeleteDrawable.getIntrinsicHeight();

            if (mDeleteWidth > 0 && mDeleteHeight > 0) {
                drawWidth = mDeleteWidth;
                drawHeight = mDeleteHeight;
            } else if (mDeleteWidth > 0 && mDeleteHeight <= 0) {
                drawWidth = mDeleteWidth;
                drawHeight = drawWidth * intrinsicHeight / intrinsicWidth;
            } else if (mDeleteWidth <= 0 && mDeleteHeight > 0) {
                drawHeight = mDeleteHeight;
                drawWidth = drawHeight * intrinsicWidth / intrinsicHeight;
            } else {
                drawWidth = intrinsicWidth;
                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));
            }
        }
    }

    // 0-9 數字的 Character 值
    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);
        }
    }

    @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 {

        /**
         * 點選數字按鍵。
         *
         * @param text 輸入的數字
         */
        void onInsertKeyEvent(String text);

        /**
         * 點選了刪除按鍵。
         */
        void onDeleteKeyEvent();
    }
}
layout.xml
<com.shanlin.autostore.view.XNumberKeyboardView
        android:id="@+id/view_keyboard"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:background="#E1E1E1"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:keyBackground="@drawable/selector_key_bg"
        android:keyTextColor="#000000"
        android:shadowColor="@android:color/transparent"
        android:shadowRadius="0"
        app:xnkv_deleteBackgroundColor="#E0E0E0"
        app:xnkv_deleteDrawable="@mipmap/delete"
        app:xnkv_deleteWidth="22dp" />
自定義屬性檔案
<declare-styleable name="XNumberKeyboardView">

        <!-- 刪除按鍵的圖示 -->
        <attr name="xnkv_deleteDrawable" format="reference"/>

        <!-- 刪除按鍵圖示的寬度 -->
        <attr name="xnkv_deleteWidth" format="dimension|reference"/>

        <!-- 刪除按鍵圖示的高度 -->
        <attr name="xnkv_deleteHeight" format="dimension|reference"/>

        <!-- 刪除按鍵圖示的顏色 -->
        <attr name="xnkv_deleteBackgroundColor" format="color|reference"/>

    </declare-styleable>
在res 目錄下新建一個xml 資料夾,放軟鍵盤資原始檔 keyboard_num.xml
        <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="@android:color/transparent" />
    </Row>

</Keyboard>

程式碼裡面就是在鍵盤監聽下進行自己的操作就OK了;

然後是密碼輸入框控制元件GridPasswordView , 非常強大, Github地址;使用起來也很方便;

自定義屬性如下:
<declare-styleable name="gridPasswordView">

        <attr name="gpvTextColor" format="color|reference"/>
        <attr name="gpvTextSize" format="dimension"/>

        <attr name="gpvLineColor" format="color"/>
        <attr name="gpvGridColor" format="color"/>
        <attr name="gpvLineWidth" format="dimension"/>

        <attr name="gpvPasswordLength" format="integer"/>
        <attr name="gpvPasswordTransformation" format="string"/>

        <attr name="gpvPasswordType" format="enum">
            <enum name="numberPassword" value="0"/>
            <enum name="textPassword" value="1"/>
            <enum name="textVisiblePassword" value="2"/>
            <enum name="textWebPassword" value="3"/>
        </attr>

    </declare-styleable>