自定義 密碼輸入框+數字鍵盤

来源:http://www.cnblogs.com/ganchuanpu/archive/2017/06/19/7050660.html
-Advertisement-
Play Games

實現了一個自定義的密碼輸入框和自定義數字鍵盤,用作用戶支付密碼設置界面。先上效果圖如下,方格樣式,以及點擊空白處隱藏軟鍵盤。 控制項實現清單: 1)集成於EditText的輸入框控制項:PasswordInputView.java 2)數字鍵盤工具類:NumKeyboardUtil.java 3)xml ...


實現了一個自定義的密碼輸入框和自定義數字鍵盤,用作用戶支付密碼設置界面。先上效果圖如下,方格樣式,以及點擊空白處隱藏軟鍵盤。
這裡寫圖片描述

控制項實現清單:
1)集成於EditText的輸入框控制項:PasswordInputView.java
2)數字鍵盤工具類:NumKeyboardUtil.java
3)xml文件:number.xml
4)attrs樣式
5)layout文件

具體內容:
PasswordInputView.java

public class PasswordInputView extends EditText{
    private int textLength;

    private int borderColor;
    private float borderWidth;
    private float borderRadius;

    private int passwordLength;
    private int passwordColor;
    private float passwordWidth;
    private float passwordRadius;

    private Paint passwordPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private Paint borderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

    private final int defaultSplitLineWidth = 1;

    public PasswordInputView(Context context, AttributeSet attrs) {
        super(context, attrs);
        final Resources res = getResources();

        final int defaultBorderColor = res.getColor(R.color.line_color);
        final float defaultBorderWidth = res.getDimension(R.dimen.dimen_1px);
        final float defaultBorderRadius = res.getDimension(R.dimen.dimen_6);

        final int defaultPasswordLength = 6;
        final int defaultPasswordColor = res.getColor(R.color.normal_text_color);
        final float defaultPasswordWidth = res.getDimension(R.dimen.dimen_6);
        final float defaultPasswordRadius = res.getDimension(R.dimen.dimen_6);

        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.PasswordInputView, 0, 0);
        try {
            borderColor = a.getColor(R.styleable.PasswordInputView_borderColor, defaultBorderColor);
            borderWidth = a.getDimension(R.styleable.PasswordInputView_borderWidth, defaultBorderWidth);
            borderRadius = a.getDimension(R.styleable.PasswordInputView_borderRadius, defaultBorderRadius);
            passwordLength = a.getInt(R.styleable.PasswordInputView_passwordLength, defaultPasswordLength);
            passwordColor = a.getColor(R.styleable.PasswordInputView_passwordColor, defaultPasswordColor);
            passwordWidth = a.getDimension(R.styleable.PasswordInputView_passwordWidth, defaultPasswordWidth);
            passwordRadius = a.getDimension(R.styleable.PasswordInputView_passwordRadius, defaultPasswordRadius);
        } finally {
            a.recycle();
        }

        borderPaint.setStrokeWidth(borderWidth);
        borderPaint.setColor(borderColor);
        passwordPaint.setStrokeWidth(passwordWidth);
        passwordPaint.setStyle(Paint.Style.FILL);
        passwordPaint.setColor(passwordColor);

        setSingleLine(true);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        int width = getWidth();
        int height = getHeight();

        // 分割線
        borderPaint.setColor(borderColor);
        borderPaint.setStrokeWidth(defaultSplitLineWidth);
        for (int i = 1; i < passwordLength; i++) {
            float x = width * i / passwordLength;
            canvas.drawLine(x, 0, x, height, borderPaint);
        }

        // 密碼
        float cx, cy = height/ 2;
        float half = width / passwordLength / 2;
        for(int i = 0; i < textLength; i++) {
            cx = width * i / passwordLength + half;
            canvas.drawCircle(cx, cy, passwordWidth, passwordPaint);
        }
    }

    @Override
    protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
        super.onTextChanged(text, start, lengthBefore, lengthAfter);
        this.textLength = text.toString().length();
        invalidate();
    }

    public int getBorderColor() {
        return borderColor;
    }

    public void setBorderColor(int borderColor) {
        this.borderColor = borderColor;
        borderPaint.setColor(borderColor);
        invalidate();
    }

    public float getBorderWidth() {
        return borderWidth;
    }

    public void setBorderWidth(float borderWidth) {
        this.borderWidth = borderWidth;
        borderPaint.setStrokeWidth(borderWidth);
        invalidate();
    }

    public float getBorderRadius() {
        return borderRadius;
    }

    public void setBorderRadius(float borderRadius) {
        this.borderRadius = borderRadius;
        invalidate();
    }

    public int getPasswordLength() {
        return passwordLength;
    }

    public void setPasswordLength(int passwordLength) {
        this.passwordLength = passwordLength;
        invalidate();
    }

    public int getPasswordColor() {
        return passwordColor;
    }

    public void setPasswordColor(int passwordColor) {
        this.passwordColor = passwordColor;
        passwordPaint.setColor(passwordColor);
        invalidate();
    }

    public float getPasswordWidth() {
        return passwordWidth;
    }

    public void setPasswordWidth(float passwordWidth) {
        this.passwordWidth = passwordWidth;
        passwordPaint.setStrokeWidth(passwordWidth);
        invalidate();
    }

    public float getPasswordRadius() {
        return passwordRadius;
    }

    public void setPasswordRadius(float passwordRadius) {
        this.passwordRadius = passwordRadius;
        invalidate();
    }
}

NumKeyboardUtil 數字軟鍵盤工具類

public class NumKeyboardUtil {
    private KeyboardView keyboardView;    
    private Keyboard k;// 數字鍵盤    
    private PasswordInputView ed;

    public NumKeyboardUtil(Activity act, Context ctx, PasswordInputView edit) {    
        this.ed = edit;  
        k = new Keyboard(ctx, R.xml.number);    
        keyboardView = (KeyboardView) act.findViewById(R.id.keyboard_view);    
        keyboardView.setKeyboard(k);    
        keyboardView.setEnabled(true);    
        keyboardView.setPreviewEnabled(true);  
        keyboardView.setOnKeyboardActionListener(listener);    
    }

    private OnKeyboardActionListener listener = new OnKeyboardActionListener() {    
        @Override    
        public void swipeUp() {    
        }    

        @Override    
        public void swipeRight() {    
        }    

        @Override    
        public void swipeLeft() {    
        }    

        @Override    
        public void swipeDown() {    
        }    

        @Override    
        public void onText(CharSequence text) {    
        }    

        @Override    
        public void onRelease(int primaryCode) {    
        }    

        @Override    
        public void onPress(int primaryCode) {    
        }    
        //一些特殊操作按鍵的codes是固定的比如完成、回退等  
        @Override    
        public void onKey(int primaryCode, int[] keyCodes) {    
                Editable editable = ed.getText();    
                int start = ed.getSelectionStart();    
                if (primaryCode == Keyboard.KEYCODE_DELETE) {// 回退    
                        if (editable != null && editable.length() > 0) {    
                                if (start > 0) {    
                                        editable.delete(start - 1, start);    
                                }    
                        }    
                }else if (primaryCode == Keyboard.KEYCODE_CANCEL) {// 完成 
                    hideKeyboard();
                } else { //將要輸入的數字現在編輯框中   
                        editable.insert(start, Character.toString((char) primaryCode));    
                }    
        }    
    };

    public void showKeyboard() {    
        keyboardView.setVisibility(View.VISIBLE);    
    }

    public void hideKeyboard() {
        keyboardView.setVisibility(View.GONE);
    }

    public int getKeyboardVisible() {
        return keyboardView.getVisibility();
    }
}

number.xml
註意該文件需要放在項目下的res目錄下的xml目錄(沒有就建個)裡面

<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:horizontalGap="0px"
    android:keyHeight="42dip"
    android:keyWidth="31%p"
    android:verticalGap="0px" >

    <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="-3"
            android:keyLabel="完成" />
        <Key
            android:codes="48"
            android:keyLabel="0" />
        <Key
            android:codes="-5"
            android:keyIcon="@drawable/sym_keyboard_delete" />
    </Row>

</Keyboard>

attrs.xml裡面的樣式:

<!-- 支付密碼輸入框 -->
    <declare-styleable name="PasswordInputView">
        <attr name="borderWidth" format="dimension"/>
        <attr name="borderColor" format="color"/>
        <attr name="borderRadius" format="dimension"/>
        <attr name="passwordLength" format="integer"/>
        <attr name="passwordWidth" format="dimension"/>
        <attr name="passwordColor" format="color"/>
        <attr name="passwordRadius" format="dimension"/>
    </declare-styleable>

佈局代碼:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/main_bg_color" >

    <include
        android:id="@+id/title_ll"
        layout="@layout/common_actionbar"/>

    <TextView
        android:id="@+id/trader_pwd_set_tips_textview"
        style="@style/normal_text_style"
        android:layout_below="@+id/title_ll"
        android:layout_marginTop="25dip"
        android:layout_centerHorizontal="true"
        android:text="@string/trade_pwd_set_tips_text" />

    <ImageView
        android:id="@+id/line1_imageview"
        style="@style/line_horizontal_style"
        android:layout_below="@+id/trader_pwd_set_tips_textview"
        android:layout_marginTop="26dip"
        android:contentDescription="@string/content_description" />

    <com.acoe.demo.widget.PasswordInputView
        android:id="@+id/trader_pwd_set_pwd_edittext"
        android:layout_width="match_parent"
        android:layout_height="41dip"
        android:layout_below="@+id/line1_imageview"
        android:maxLength="6"
        android:background="@android:color/white" />

    <ImageView
        android:id="@+id/line2_imageview"
        style="@style/line_horizontal_style"
        android:layout_below="@+id/trader_pwd_set_pwd_edittext"
        android:contentDescription="@string/content_description" />

    <Button
        android:id="@+id/trader_pwd_set_next_button"
        style="@style/main_button_style"
        android:layout_below="@+id/line2_imageview"
        android:layout_marginTop="25dip"
        android:text="@string/trade_pwd_set_next_text" />

    <android.inputmethodservice.KeyboardView
        android:id="@+id/keyboard_view"    
        android:layout_width="match_parent"    
        android:layout_height="240dip"
        android:layout_alignParentBottom="true"
        android:paddingTop="30dip"
        android:paddingLeft="13dip"
        android:paddingRight="13dip"
        android:focusable="true"    
        android:focusableInTouchMode="true"   
        android:visibility="invisible"/>

</RelativeLayout>

Activity代碼片段:

//=======在Activity成員變數中聲明部分代碼=======
/** 控制項 */
    private PasswordInputView edtPwd;

//=======在Activity實例化控制項部分代碼=======
// 初始化控制項
        edtPwd = (PasswordInputView) findViewById(R.id.trader_pwd_set_pwd_edittext);
        edtPwd.setInputType(InputType.TYPE_NULL); // 屏蔽系統軟鍵盤
// 自定義軟鍵盤
        if (keyboardUtil == null) keyboardUtil = new NumKeyboardUtil(this, this, edtPwd);
        edtPwd.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                keyboardUtil.showKeyboard();
                return false;
            }
        });

//=======在Activity中重寫onTouchEvent()方法,實現點擊空白處隱藏軟鍵盤=======
@Override
    public boolean onTouchEvent(MotionEvent event) {
        if(event.getAction() == MotionEvent.ACTION_DOWN){  
             if(getCurrentFocus()!=null && getCurrentFocus().getWindowToken()!=null){ 
                 keyboardUtil.hideKeyboard();
             }
        }
        return super.onTouchEvent(event);
    }

ps:如果把該密碼輸入框和其他類型輸入框並用時要註意兩者之間焦點變化時將系統軟鍵盤和自定義的數字鍵盤隱藏,我的做法是給密碼輸入框綁定OnFacusChangeListener事件,來控制就好。如下:

edtPwd.setOnFocusChangeListener(new OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (hasFocus) {
                    // 如果系統鍵盤是彈出狀態,先隱藏
                    ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE))
                    .hideSoftInputFromWindow(getCurrentFocus()
                    .getWindowToken(),
                    InputMethodManager.HIDE_NOT_ALWAYS);
                    keyboardUtil.showKeyboard();
                } else {
                    keyboardUtil.hideKeyboard();
                }
            }
        });

  


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...