1. 程式人生 > >Android 密碼輸入框、驗證碼輸入框,完整版;

Android 密碼輸入框、驗證碼輸入框,完整版;

接上篇,優化了一下程式碼,新增一些屬性;

      "space" //每個輸入框之間的間距;
       "strokeWidth" //邊框的高度;
       "checkedColor"  //已輸入的顏色
       "defaultColor" //未輸入的預設顏色
       "textLength"  //規定輸入長度
       "backColor"   //輸入框的背景顏色
       "textColor"   //字型顏色
        "circle"   //密文密碼 ● 的大小;
        "round"   //輸入框的圓角弧度
        "textSize"   //字型大小
        "isPwd"   //是否密文輸入 預設true
        "waitInputColor"   //待輸入線的顏色
       "isWaitInput"  //是否顯示待輸入線 預設false

如何使用:

public class MainActivity extends AppCompatActivity {

    private PwdEditText p;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        p = findViewById(R.id.p);
        p.setOnTextChangeListener(new PwdEditText.OnTextChangeListener() {
            @Override
            public void onTextChange(String pwd) {
                if (pwd.length() == p.getTextLength()){
                    //輸入監聽
                    Toast.makeText(MainActivity.this,pwd,Toast.LENGTH_SHORT).show();
                }
            }
        });
        findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                p.clearText(); //清空輸入內容
            }
        });
    }
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

   <c.c.b.pwdinputedittext.PwdEditText
       android:id="@+id/p"
       android:layout_centerInParent="true"
       android:layout_width="330dp"
       android:layout_height="wrap_content"
       />
   <Button
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="清空"
       android:id="@+id/btn"
       android:layout_below="@id/p"
       android:layout_centerHorizontal="true"
       />

</RelativeLayout>

看程式碼,PwdEditText :

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.support.v7.widget.AppCompatEditText;
import android.text.InputType;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;

public class PwdEditText extends AppCompatEditText {

     private Paint sidePaint , backPaint , textPaint;
     private Context mC;
    private String mText;
    private List<RectF> rectFS;
    private int StrokeWidth,spzceX ,spzceY,textSize;
    private int checkedColor,defaultColor,backColor ,textColor ,waitInputColor;
    private int textLength;
    private int Circle,Round;
    private boolean isPwd , isWaitInput;

    public PwdEditText(Context context) {
        super(context);

        mC = context;
        setAttrs( null);
        init();
    }

    public PwdEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        mC = context;
        setAttrs( attrs);
        init();
    }

    public PwdEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mC = context;
        setAttrs( attrs);
        init();
    }

    private void setAttrs(AttributeSet attrs) {
         TypedArray t = mC.obtainStyledAttributes(attrs, R.styleable.PwdEditText);
         if (t != null) {
             textLength = t.getInt(R.styleable.PwdEditText_textLength,6);
             spzceX = t.getDimensionPixelSize(R.styleable.PwdEditText_space, (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,3,getResources().getDisplayMetrics()));
             spzceY = t.getDimensionPixelSize(R.styleable.PwdEditText_space, (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,3,getResources().getDisplayMetrics()));
            StrokeWidth = t.getDimensionPixelSize(R.styleable.PwdEditText_strokeWidth, (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,1,getResources().getDisplayMetrics()));
            Round = t.getDimensionPixelSize(R.styleable.PwdEditText_round, (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,3,getResources().getDisplayMetrics()));
            Circle = t.getDimensionPixelSize(R.styleable.PwdEditText_circle, (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,7,getResources().getDisplayMetrics()));
             textSize = t.getDimensionPixelSize(R.styleable.PwdEditText_textSize, (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,16,getResources().getDisplayMetrics()));
            checkedColor = t.getColor(R.styleable.PwdEditText_checkedColor,0xff44ce61);
            defaultColor = t.getColor(R.styleable.PwdEditText_defaultColor,0xffd0d0d0);
            backColor = t.getColor(R.styleable.PwdEditText_backColor,0xfff1f1f1);
            textColor = t.getColor(R.styleable.PwdEditText_textColor,0xFF444444);
            waitInputColor = t.getColor(R.styleable.PwdEditText_waitInputColor,0xFF444444);
            isPwd = t.getBoolean(R.styleable.PwdEditText_isPwd,true);
            isWaitInput = t.getBoolean(R.styleable.PwdEditText_isWaitInput,false);
            t.recycle();
         }
    }

    private void init() {
        setTextColor(0X00ffffff); //把使用者輸入的內容設定為透明
        setInputType(InputType.TYPE_CLASS_NUMBER|InputType.TYPE_NUMBER_VARIATION_NORMAL);
        sidePaint = new Paint();
        backPaint = new Paint();
        textPaint = new Paint();

        rectFS = new ArrayList<>();
        mText = "" ;

        this.setBackgroundDrawable(null);
        setLongClickable(false);
        setTextIsSelectable(false);
        setCursorVisible(false);

    }

    @Override
    protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
        super.onTextChanged(text, start, lengthBefore, lengthAfter);
        if (mText == null) {return;}
        //如果字數不超過使用者設定的總字數,就賦值給成員變數mText;
        // 如果字數大於使用者設定的總字數,就只保留使用者設定的幾位數字,並把游標制動到最後,讓使用者可以刪除;
        if (text.toString().length() <= textLength){
            mText = text.toString();
        }else{
            setText(mText);
            setSelection(getText().toString().length());  //游標制動到最後
            //呼叫setText(mText)之後鍵盤會還原,再次把鍵盤設定為數字鍵盤;
            setInputType(InputType.TYPE_CLASS_NUMBER|InputType.TYPE_NUMBER_VARIATION_NORMAL);
        }
        if (OnTextChangeListener != null) OnTextChangeListener.onTextChange(mText);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        switch (heightMode){
            case MeasureSpec.EXACTLY:
                heightSize = MeasureSpec.getSize(heightMeasureSpec);
                break;
            case MeasureSpec.AT_MOST:
                heightSize = widthSize/textLength;
                break;
        }
        setMeasuredDimension(widthSize,heightSize);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //邊框畫筆
        sidePaint.setAntiAlias(true);//消除鋸齒
        sidePaint.setStrokeWidth(StrokeWidth);//設定畫筆的寬度
        sidePaint.setStyle(Paint.Style.STROKE);//設定繪製輪廓
        sidePaint.setColor(defaultColor);
        //背景色畫筆
        backPaint.setStyle(Paint.Style.FILL);
        backPaint.setColor(backColor);
        //文字的畫筆
        textPaint.setTextSize(textSize);
        textPaint.setStyle(Paint.Style.FILL);
        textPaint.setColor(textColor);

        int Wide = Math.min(getMeasuredHeight(), getMeasuredWidth() / textLength);

        for (int i = 0; i < textLength; i++) {
            //區分已輸入和未輸入的邊框顏色
            if (mText.length() >= i){
                sidePaint.setColor(checkedColor);
            }else {
                sidePaint.setColor(defaultColor);
            }

            //RectF的引數(left,  top,  right,  bottom); 畫出每個矩形框並設定間距,間距其實是增加左邊框距離,縮小上下右邊框距離;
            RectF rect = new RectF(i * Wide + spzceX, spzceY,i * Wide + Wide - spzceX,Wide - spzceY); //四個值,分別代表4條線,距離起點位置的線
            canvas.drawRoundRect(rect,Round,Round,backPaint); //繪製背景色
            canvas.drawRoundRect(rect,Round,Round,sidePaint); //繪製邊框;
            rectFS.add(rect);

            if (isWaitInput && i == mText.length()) {  //顯示待輸入的線
                Paint l = new Paint();
                l.setStrokeWidth(3);
                l.setStyle(Paint.Style.FILL);
                l.setColor(waitInputColor);
                canvas.drawLine(i * Wide + Wide / 2, Wide / 2 - Wide / 5, i * Wide + Wide / 2, Wide / 2 + Wide / 5, l);
            }
        }
        //畫密碼圓點
        for (int j = 0; j < mText.length(); j++) {
            if (isPwd) {
                canvas.drawCircle(rectFS.get(j).centerX(), rectFS.get(j).centerY(), Circle, textPaint);
            }else {
                canvas.drawText(mText.substring(j,j+1),rectFS.get(j).centerX()-(textSize - spzceX)/2, rectFS.get(j).centerY()+(textSize - spzceY)/2, textPaint);
//                Rect textRect = new Rect();
//                textPaint.getTextBounds(mText.substring(j, j + 1), 0, 1, textRect);
//                canvas.drawText(mText.substring(j, j + 1), rectFS.get(j).left + (rectFS.get(j).right - rectFS.get(j).left) / 2 - textRect.width() / 2,
//                        rectFS.get(j).top + ((rectFS.get(j).bottom - rectFS.get(j).top) / 2) + textRect.height() / 2, textPaint);
            }
        }
    }

    private int dp2px(float dpValue){
        float scale=mC.getResources().getDisplayMetrics().density;
        return (int)(dpValue*scale+0.5f);
    }

    /**
     * 輸入監聽
     */
    interface OnTextChangeListener{
        void onTextChange(String pwd);
    }
    private OnTextChangeListener OnTextChangeListener;
    public void setOnTextChangeListener(OnTextChangeListener OnTextChangeListener){
        this.OnTextChangeListener = OnTextChangeListener;
    }

    /**
     * 清空所有輸入的內容
     */
    public void clearText(){
        setText("");
        setInputType(InputType.TYPE_CLASS_NUMBER|InputType.TYPE_NUMBER_VARIATION_NORMAL);
    }
    /**
     * 設定密碼框間距
     */
    public void setSpace(int space){
        spzceX = space;
        spzceY = space;
    }
    /**
     * 設定密碼框個數
     */
    public void setTextLength(int textLength){
        this.textLength = textLength;
    }
    /**
     * 獲得密碼框個數
     */
    public int getTextLength(){
        return this.textLength;
    }
    /**
     * 設定已輸入密碼框顏色
     */
    public void setcheckedColorColor(int checkedColor){
        this.checkedColor = checkedColor;
    }
    /**
     * 設定未輸入密碼框顏色
     */
    public void setdefaultColorColor(int defaultColor){
        this.defaultColor = defaultColor;
    }
    /**
     * 設定密碼框背景色
     */
    public void setBackColor(int backColor){
        this.backColor = backColor;
    }
    /**
     * 設定密碼圓點的顏色
     */
    public void setPwdTextColor(int textColor){
        this.textColor = textColor;
    }
    /**
     * 設定密碼框 邊框的寬度
     */
    public void setStrokeWidth(int width){
        StrokeWidth = width;
    }

    /**
     * 密碼的圓點大小
     */
    public void setCircle(int Circle){
        this.Circle = Circle;
    }
    /**
     * 密碼邊框的圓角大小
     */
    public void setRound(int Round){
        this.Round = Round;
    }

    public int getStrokeWidth() {
        return StrokeWidth;
    }

    public int getSpzceX() {
        return spzceX;
    }

    public int getSpzceY() {
        return spzceY;
    }

    public int getCheckedColor() {
        return checkedColor;
    }

    public int getDefaultColor() {
        return defaultColor;
    }

    public int getBackColor() {
        return backColor;
    }

    public int getTextColor() {
        return textColor;
    }

    public int getCircle() {
        return Circle;
    }

    public int getRound() {
        return Round;
    }
    public int gettextSize() {
        return textSize;
    }

    public void settextSize(int textSize) {
        this.textSize = textSize;
    }

    public boolean isPwd() {
        return isPwd;
    }

    /**
     * 是否密文輸入
     * @param pwd
     */
    public void setPwd(boolean pwd) {
        isPwd = pwd;
    }

    public int getWaitInputColor() {
        return waitInputColor;
    }

    /**\
     * 待輸入線的顏色
     * @param waitInputColor
     */
    public void setWaitInputColor(int waitInputColor) {
        this.waitInputColor = waitInputColor;
    }

    public boolean isWaitInput() {
        return isWaitInput;
    }

    /**
     * 是否顯示待輸入的線
     * @param waitInput
     */
    public void setWaitInput(boolean waitInput) {
        isWaitInput = waitInput;
    }

}

style中的程式碼:

    <declare-styleable name="PwdEditText">
        <attr name="space" format="dimension"/>
        <attr name="strokeWidth" format="dimension"/>
        <attr name="checkedColor" format="color"/>
        <attr name="defaultColor" format="color"/>
        <attr name="textLength" format="integer"/>
        <attr name="backColor" format="color"/>
        <attr name="textColor" format="color"/>
        <attr name="circle" format="dimension"/>
        <attr name="round" format="dimension"/>
        <attr name="textSize" format="dimension"/>
        <attr name="isPwd" format="boolean"/>
        <attr name="waitInputColor" format="color"/>
        <attr name="isWaitInput" format="boolean"/>
    </declare-styleable>