Android密码输入框PasswordView-自定义view系列(1)


功能简介

强大的密码输入框PasswordView,多种功能自由组合。高亮,光标,隐藏输入后的内容,任意数量,任意大小,任意drawable设置样式,自动弹出/关闭键盘,锁定状态

完整代码:Github项目可自行下载: 点击跳转
相关文章:onMeasure()讲解: 点击跳转


Gif演示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


PasswordView的xml属性介绍

属性名称设置-属性介绍
password_setViewBackgroundPasswordView背景
password_box_setNumber盒子数量(密码长度)
password_box_setMargin盒子间距
password_box_setSize盒子大小
password_box_notInput_backgroundDrawable盒子未输入内容的背景
password_box_hasInput_backgroundDrawable盒子已输入过内容的背景
password_box_highLight_backgroundDrawable盒子高亮的背景
password_box_locked_backgroundDrawable盒子锁定状态下的背景
password_text_setColor文字颜色
password_text_setSize文字大小
password_text_setIsBold文字粗细
password_text_setInputType文字输入的类型
password_cursorHeight光标高度
password_cursorWidth光标宽度
password_cursorFrequencyMillisecond光标闪烁间隔(毫秒)
password_cursorBackgroundDrawable光标背景
password_cursorColor光标颜色
属性名称控制-属性介绍
password_enableCursor控制-显/隐 光标
password_enableHighLight控制-显/隐 高亮盒子
password_enableLockTextView控制-显/隐 锁定状态盒子
password_enableCursor控制-显/隐 光标
password_enableSoftKeyboardAutoShow控制-开/关 自动打开软键盘
password_enableSoftKeyboardAutoShow控制-开/关 自动关闭软键盘 (输满后)
password_enableHideCode控制-显/隐 输入过的内容
password_enableHideCodeSetText设置-当隐藏内容时所展示的内容
password_enableHideBoxWhenNotInput控制-显/隐 未输入内容的盒子

实现步骤

1.创建PasswordView.java并继承一个view
2.实现TypedArray和atts.xml数据关联,使得自绘制组件view可在xml设置并传递参数
3.在onMeasure()的方法里,根据设置PasswordView的参数来计算组件的长和宽
4.在PasswordView里创建一个EditText用来触发点击弹出键盘(曾尝试过手动点击弹出键盘,但是好像无法捕获当前键盘切换格式后的删除内容,所以放弃了这方法,改为用EditText,顺便还可以用来调控输入内容格式,更方便).
5.对EditText改造.将一切东西设为透明,EditText大小跟计算出来的尺寸保持一致,并通过EditText.addTextChangedListener(new mWatcher())来监听输入内容
6.设置回调接口 OnResultListener 监听输入结果
7.一切准备就绪后,在onDraw(Canvas canvas)方法上并通过各种计算,用canvas进行绘制密码输入的盒子.
8.一共4种盒子(未输入内容(mBox_notInput),已输入内容(mBox_hasInput),高亮(mBox_highLight),锁定状态(mBox_locked)),1种光标(mCursor).


java代码

package com.yfz.password;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.text.Editable;
import android.text.InputFilter;
import android.text.InputType;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.Timer;
import java.util.TimerTask;

/**
 * 简介:自定义验证码输入框 (组合+自绘)
 * 作者:YFZ
 * Android技术生活-QQ交流群:723592501
 * 主要功能: (
 * 以下功能涉及到盒子样式的改变,均可单独控制功能的盒子样式,默认为画笔,可自定设置backgroundDrawable替代)
 *
 * mBox_notInput_backgroundDrawable;//盒子未输入内容背景Drawable
 * mBox_hasInput_backgroundDrawable;//盒子已输入内容背景Drawable
 * mBox_highLight_backgroundDrawable;//盒子高亮背景Drawable
 * mBox_locked_backgroundDrawable;//盒子锁定状态下背景Drawable
 *
 * mEnableHideCode 是否隐藏输入内容
 * mEnableHighLight 是否开启高亮
 * mEnableCursor 是否开启光标
 * mEnableHideNotInputBox 是否将没有输入内容的盒子隐藏
 * mEnableSoftKeyboardAutoClose 开关自动关闭软键盘
 * mEnableSoftKeyboardAutoShow 开关自动展现软键盘
 * mEnableLockCodeTextIfMaxCode 开关输入内容满足长度后是否锁定
 */

public class PasswordView extends LinearLayout {
    private final static String TAG= PasswordView.class.getName();
    private Context mContext;
    private int measureWidthMode =0;
    private int measureWidthSize =0;
    private int measureHeightMode =0;
    private int measureHeightSize =0;

    private boolean mEnableHideCode =false;//是否隐藏输入code
    private boolean mEnableHighLight=false;//是否开启高亮
    private boolean mEnableCursor =false;//是否开启光标
    private boolean mEnableHideNotInputBox=false;//是否将没有输入内容的盒子隐藏
    private boolean mEnableSoftKeyboardAutoShow=true;//是否自动打开软键盘
    private boolean mEnableSoftKeyboardAutoClose=true;//是否自动关闭软键盘(输入内容长度==最大长度)
    private boolean mEnableLockCodeTextIfMaxCode =false;//是否限制输满后锁定view
    //默认设置-盒子画笔相关
    private Paint mBox_default_paint;//笔刷
    private final String mBox_default_hideText ="*";//隐藏输入过的盒子展示的内容
    private int mBox_default_hasInputColor =Color.RED; //盒子输入过的颜色
    private int mBox_default_notInputColor =Color.BLUE; //盒子未输入过的颜色
    private int mBox_default_highLightColor =Color.CYAN; //盒子高亮的颜色
    private int mBox_default_cursorColor =Color.BLACK; //盒子光标的颜色
    private int mBox_default_lockColor =Color.GRAY; //盒子锁定状态下的颜色
    private int mBox_default_strokeWidth =1; //盒子宽度
    private float mBox_default_radius =5f;//圆弧半径
    //输入框样式
    private final int TEXT_INPUT_TYPE_NUMBER=200, TEXT_INPUT_TYPE_PHONE =201, TEXT_INPUT_TYPE_TEXT =202,TEXT_INPUT_TYPE_DATETIME=203;
    private boolean mIsLocked=false;
    private boolean mIsCodeFull =false;
    private int mIsFirstTime=0;
    private int mBox_nextInputIndex =0;//待输入盒子的下坐标
    private OnResultListener mOnResultListener;
    private InputMethodManager inputMethodManager;
    private EditText mEditText;
    private String mEnableHideCode_text;//隐藏输入code-显示的内容
    private int mViewBackground=Color.TRANSPARENT;//背景Drawable
    //盒子
    private RectF mBoxRectF;//矩形(绘制位置)
    private int mBox_setNumber =4;//数量
    private int mBox_setSize =50;//大小
    private int mBox_setMargin =10;//盒子之间的间距
    private Drawable mBox_notInput_backgroundDrawable;//盒子未输入内容背景Drawable
    private Drawable mBox_hasInput_backgroundDrawable;//盒子已输入内容背景Drawable
    private Drawable mBox_highLight_backgroundDrawable;//盒子高亮背景Drawable
    private Drawable mBox_locked_backgroundDrawable;//盒子锁定状态下背景Drawable
    //文字
    private Paint mPaintText;//笔刷
    private Rect mTextRect;//矩形(绘制位置)
    private String[] mCodeArray;//输入Code内容
    private int mTextColor=Color.BLACK;//颜色
    private int mTextSize=10;//大小
    private int mTextInputType=TEXT_INPUT_TYPE_NUMBER;//类型
    private boolean mTextBold=true;//粗细
    //光标
    private Timer mCursorTimer;//定时器
    private TimerTask mCursorTimerTask;//定时器任务
    private Drawable mCursorBackgroundDrawable;//背景
    private int mCursorColor;//颜色
    private int mCursorHeight =1;//上下边距
    private int mCursorWidth =1;//上下边距
    private int mCursorFrequency=500;//闪烁频率
    private boolean mCursorDisplayingByTimer =false;//显示光标-定时器-闪烁效果
    private boolean mCursorDisplayingByIndex =false;//显示光标-第一次下坐标

    public PasswordView(@NonNull Context context) {
        super(context);
        initial(context);
    }
    public PasswordView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        TypedArray typedArray=context.obtainStyledAttributes(attrs, R.styleable.PasswordView);

        //自动弹出键盘
        mEnableSoftKeyboardAutoShow=typedArray.getBoolean(R.styleable.PasswordView_password_enableSoftKeyboardAutoShow, mEnableSoftKeyboardAutoShow);
        //自动隐藏键盘
        mEnableSoftKeyboardAutoClose =typedArray.getBoolean(R.styleable.PasswordView_password_enableSoftKeyboardAutoClose, mEnableSoftKeyboardAutoClose);
        //是否隐藏输入内容
        mEnableHideCode =typedArray.getBoolean(R.styleable.PasswordView_password_enableHideCode, mEnableHideCode);
        //隐藏输入的内容,显示设置的文案
        mEnableHideCode_text =typedArray.getString(R.styleable.PasswordView_password_enableHideCodeSetText);
        //是否将没有输入内容的盒子隐藏
        mEnableHideNotInputBox =typedArray.getBoolean(R.styleable.PasswordView_password_enableHideBoxWhenNotInput, mEnableHideNotInputBox);
        //是否绘制高亮盒子
        mEnableHighLight=typedArray.getBoolean(R.styleable.PasswordView_password_enableHighLight,mEnableHighLight);
        //是否绘制光标
        mEnableCursor =typedArray.getBoolean(R.styleable.PasswordView_password_enableCursor, mEnableCursor);
        //是否锁定组件当输入满长度后(禁止点击,可以主动setUnLock()调解除锁定)
        mEnableLockCodeTextIfMaxCode =typedArray.getBoolean(R.styleable.PasswordView_password_enableLockTextView, mEnableLockCodeTextIfMaxCode);
        //View背景Drawable
        mViewBackground =typedArray.getResourceId(R.styleable.PasswordView_password_setViewBackground,Color.TRANSPARENT);
        //文字颜色
        mTextColor=typedArray.getColor(R.styleable.PasswordView_password_text_setColor,mTextColor);
        //文字大小
        mTextSize=typedArray.getInt(R.styleable.PasswordView_password_text_setSize,mTextSize);
        //文字输入框类型
        mTextInputType=typedArray.getInt(R.styleable.PasswordView_password_text_setInputType,mTextInputType);
        //文字粗细
        mTextBold=typedArray.getBoolean(R.styleable.PasswordView_password_text_setIsBold,mTextBold);
        //设置盒子总数量
        mBox_setNumber =typedArray.getInt(R.styleable.PasswordView_password_box_setNumber, mBox_setNumber);
        //设置盒子间距
        mBox_setMargin =typedArray.getInt(R.styleable.PasswordView_password_box_setMargin, mBox_setMargin);
        //设置盒子大小
        mBox_setSize =typedArray.getInt(R.styleable.PasswordView_password_box_setSize, mBox_setSize);
        //设置盒子-未输入的背景Drawable
        mBox_notInput_backgroundDrawable =typedArray.getDrawable(R.styleable.PasswordView_password_box_notInput_backgroundDrawable);
        //设置盒子-输入后的背景Drawable
        mBox_hasInput_backgroundDrawable =typedArray.getDrawable(R.styleable.PasswordView_password_box_hasInput_backgroundDrawable);
        //设置盒子-高亮的背景Drawable
        mBox_highLight_backgroundDrawable =typedArray.getDrawable(R.styleable.PasswordView_password_box_highLight_backgroundDrawable);
        //设置盒子-锁定状态下的背景Drawable
        mBox_locked_backgroundDrawable =typedArray.getDrawable(R.styleable.PasswordView_password_box_locked_backgroundDrawable);
        //设置光标高度
        mCursorHeight =typedArray.getInt(R.styleable.PasswordView_password_cursorHeight,mCursorHeight);
        //设置光标宽度
        mCursorWidth =typedArray.getInt(R.styleable.PasswordView_password_cursorWidth,mCursorWidth);
        //设置光标闪烁频率
        mCursorFrequency=typedArray.getInt(R.styleable.PasswordView_password_cursorFrequencyMillisecond,mCursorFrequency);
        //设置光标颜色
        mCursorColor=typedArray.getInt(R.styleable.PasswordView_password_cursorColor,mBox_default_cursorColor);
        //设置光标背景
        mCursorBackgroundDrawable =typedArray.getDrawable(R.styleable.PasswordView_password_cursorBackgroundDrawable);
        //回收
        typedArray.recycle();
        //初始化
        initial(context);
    }

    //测量-CodeText大小
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        measureWidthMode =MeasureSpec.getMode(widthMeasureSpec);
        measureWidthSize =MeasureSpec.getSize(widthMeasureSpec);
        measureHeightMode =MeasureSpec.getMode(heightMeasureSpec);
        measureHeightSize =MeasureSpec.getSize(heightMeasureSpec);
        if(measureWidthMode==MeasureSpec.AT_MOST && measureHeightMode==MeasureSpec.AT_MOST){
            //宽高均未声明绝对值
            //组件宽 = (盒子大小*数量)+(盒子边距*(数量-1))+画笔宽度
            //组件高 = (盒子大小)
            measureWidthSize = mBox_setSize * (mBox_setNumber) + mBox_setMargin * (mBox_setNumber - 1) ;
            measureHeightSize = mBox_setSize;
        }else if(measureWidthMode==MeasureSpec.EXACTLY && measureHeightMode==MeasureSpec.EXACTLY){
            //宽高均声明了绝对值
            //只需计算盒子大小= (测量高-(盒子边距*(数量-1)+画笔宽度)/ 盒子数量)
            mBox_setSize =(int)((measureWidthSize -  mBox_setMargin * (mBox_setNumber - 1))/(mBox_setNumber));
        }else if(measureWidthMode==MeasureSpec.EXACTLY && measureHeightMode==MeasureSpec.AT_MOST){
            //只声明了宽的绝对值,高未声明
            mBox_setSize =(int)((measureWidthSize -  mBox_setMargin * (mBox_setNumber - 1))/(mBox_setNumber));
        }else if(measureHeightMode==MeasureSpec.EXACTLY && measureWidthMode==MeasureSpec.AT_MOST){
            //只声明了高的绝对值,宽未声明
            mBox_setSize =(int)((measureWidthSize -  mBox_setMargin * (mBox_setNumber - 1))/(mBox_setNumber));
        }
        setMeasuredDimension(measureWidthSize, measureHeightSize);
    }

    //初始化-CodeText
    @SuppressLint("ResourceType")
    private void initial(Context context){
        this.mContext=context;
            try{
                Drawable drawable= getResources().getDrawable(mViewBackground);
                this.setBackground(drawable);
            }catch (Exception e){
                this.setBackgroundColor(mViewBackground);
            }
        mCodeArray =new String[mBox_setNumber];
        for(int i=0;i<mCodeArray.length;i++){
            mCodeArray[i]="";
        }
        if(null==this.mEnableHideCode_text){
            this.mEnableHideCode_text = mBox_default_hideText;
        }else if(this.mEnableHideCode_text.length()>0) {
            this.mEnableHideCode_text = mEnableHideCode_text.substring(0, 1);
        }
        mCursorTimerTask = new TimerTask() {
            @Override
            public void run() {
                mCursorDisplayingByTimer = !mCursorDisplayingByTimer;
                postInvalidate();
            }
        };
        mCursorTimer = new Timer();
        initialEditText();
        initialPaint();
        initialBoxAndRectPosition();
        setOnLayoutListener(mEditText);
        setOnTouchListener(this);
    }

    //初始化EdiText
    private void initialEditText(){
        this.mEditText=new EditText(this.getContext());
        LayoutParams layoutParams=new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        this.mEditText.setLayoutParams(layoutParams);
        this.mEditText.setBackgroundColor(Color.TRANSPARENT);
        this.mEditText.setTextColor(Color.TRANSPARENT);
        this.addView(mEditText);
        this.mEditText.setWidth(1);
        this.mEditText.setHeight(1);
        this.mEditText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(mBox_setNumber)});
        switch (mTextInputType){
            case TEXT_INPUT_TYPE_NUMBER:
                this.mEditText.setInputType(InputType.TYPE_CLASS_NUMBER);
                break;
            case TEXT_INPUT_TYPE_PHONE:
                this.mEditText.setInputType(InputType.TYPE_CLASS_PHONE);
                break;
            case TEXT_INPUT_TYPE_TEXT:
                this.mEditText.setInputType(InputType.TYPE_CLASS_TEXT);
                break;
            case TEXT_INPUT_TYPE_DATETIME:
                this.mEditText.setInputType(InputType.TYPE_CLASS_DATETIME);
                break;
        }
        this.mEditText.setSingleLine();
        this.mEditText.setCursorVisible(false);
        inputMethodManager = (InputMethodManager) this.mEditText.getContext().getSystemService(this.mEditText.getContext().INPUT_METHOD_SERVICE);
        this.mEditText.addTextChangedListener(new mWatcher());
    }
    //初始化-盒子和位置
    private void initialBoxAndRectPosition(){
        this.mBox_setSize = DisplayUtils.dip2px(mContext, mBox_setSize);
        this.mBox_setMargin = DisplayUtils.dip2px(mContext, mBox_setMargin);
        this.mBox_default_radius = DisplayUtils.dip2pxFloat(mContext, mBox_default_radius);
        this.mBoxRectF=new RectF();
        this.mTextRect=new Rect();
    }
    //初始化-笔刷
    private void initialPaint(){
        //文字
        this.mPaintText=new Paint(Paint.ANTI_ALIAS_FLAG);
        this.mPaintText.setStyle(Paint.Style.FILL);
        this.mPaintText.setTextSize(DisplayUtils.dip2px(this.getContext(),mTextSize)*2);
        this.mPaintText.setColor(mTextColor);
        this.mPaintText.setFakeBoldText(mTextBold);
        //盒子
        this.mBox_default_paint =new Paint(Paint.ANTI_ALIAS_FLAG);
        this.mBox_default_paint.setStyle(Paint.Style.STROKE);
        this.mBox_default_paint.setStrokeWidth(DisplayUtils.dip2px(mContext, mBox_default_strokeWidth));

    }
    //监听点击事件-打开弹窗
    private void setOnTouchListener(View view){
        if(null != view) {
            view.setOnTouchListener(new OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                  if(event.getAction()==MotionEvent.ACTION_UP && (!mIsLocked || !mEnableLockCodeTextIfMaxCode )) {
                          openSoftKeyboard(mEditText);
                  }
                    return true;
                }
            });
        }
    }

    class mWatcher implements TextWatcher{
        @Override
        public void beforeTextChanged(CharSequence text, int start, int count, int after) {
        }
        @Override
        public void onTextChanged(CharSequence text, int start, int end, int count) {
        }
        @Override
        public void afterTextChanged(Editable text) {
            mBox_nextInputIndex =text.length(); //高亮盒子下坐标=当前输入内容长度
            if(null!= mCodeArray ) {
                    for (int i = 0; i< mBox_setNumber; i++){
                        if(i<=text.length()-1) {
                            mCodeArray[i] = text.toString().substring(i, i + 1);
                        }else {
                            mCodeArray[i] = "";
                        }
                    }
                    mCursorDisplayingByIndex=true;
                if( text.length()== mBox_setNumber){ //内容长度与盒子数量一致->返回回调结果
                    mIsCodeFull = true;
                    if(null!=mOnResultListener) {
                        mOnResultListener.finish(text.toString());
                    }
                    if(mEnableSoftKeyboardAutoClose || mEnableLockCodeTextIfMaxCode){
                        closeSoftKeyboard(mEditText);
                    }
                    mIsLocked = true ;
                }else {
                    if(null!=mOnResultListener) {
                        mOnResultListener.typing(text.toString());
                    }
                }
             postInvalidate();

            }
        }
    }

    //锁定CodeText
    public void setOnLock(){
        mEnableLockCodeTextIfMaxCode=true;
        mIsLocked=true;
    }
    //解除锁定CodeText
    public void setUnLock(){
//        mEnableLockCodeTextIfMaxCode=false;
        if(mIsCodeFull) {
            openSoftKeyboard(mEditText);
            mIsLocked=false;
        }
    }

    //监听View是否渲染完成,如果开启了自动弹出软键盘,则弹出
    private void setOnLayoutListener(final View view){
        if(null != view) {
            view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    if (!mIsCodeFull && mIsFirstTime <= 3 && mEnableSoftKeyboardAutoShow) {
                        openSoftKeyboard(view);
                        mIsFirstTime++;
                    }
                }
            });
        }
    }

    //画布-绘制板
    @Override
    protected void onDraw(Canvas canvas) {
        for (int i = 0; i < mBox_setNumber; i++) {
            mBoxRectF.left   = (mBox_setSize + mBox_setMargin) * i;
            mBoxRectF.top    = 0;
            mBoxRectF.right  = mBoxRectF.left + mBox_setSize;
            mBoxRectF.bottom = getHeight();
            if( (mEnableHighLight||mEnableCursor) && i == mBox_nextInputIndex){ //如果开启了高亮或鼠标 且 i==待输入index
                onDrawHighLightCursor(canvas); //绘制盒子 - 高亮或光标
            } else if (mCodeArray[i].length()>=1) { //如果盒子内容的长度>=1,则视为已输入过内容的盒子
                onDrawHasInput(canvas,i); //绘制盒子 - 已输入过内容
            } else { //未输入过内容的盒子
                onDrawNotInput(canvas); //绘制盒子 - 未输入过内容
            }
        }

    }
    //绘制盒子 - 未输入过内容
    private void onDrawNotInput(Canvas canvas) {
        if(!mEnableHideNotInputBox) { //如果没有开启隐藏 未输入内容盒子
            if (null != mBox_notInput_backgroundDrawable) {  //如果有设置drawable,则绘制drawable
                mBox_notInput_backgroundDrawable.setBounds((int) mBoxRectF.left, (int) mBoxRectF.top, (int) mBoxRectF.right, (int) mBoxRectF.bottom);
                mBox_notInput_backgroundDrawable.draw(canvas);
            } else {
                mBox_default_paint.setColor(mBox_default_notInputColor);
                canvas.drawRoundRect(mBoxRectF, mBox_default_radius, mBox_default_radius, mBox_default_paint);
            }
        }
    }
    //绘制盒子 - 已输入过内容 boxAfter样式
    private void onDrawHasInput(Canvas canvas,int i){
            if(mIsLocked && mEnableLockCodeTextIfMaxCode){ //如果开启了输入完毕锁定内容,则绘制boxLock样式
                if(null!= mBox_locked_backgroundDrawable){//如果有设置高亮drawable,则绘制drawable,没有则用画笔绘制
                    mBox_locked_backgroundDrawable.setBounds((int)mBoxRectF.left,(int)mBoxRectF.top,(int)mBoxRectF.right,(int)mBoxRectF.bottom);
                    mBox_locked_backgroundDrawable.draw(canvas);
                }else {
                    mBox_default_paint.setColor(mBox_default_lockColor);
                    canvas.drawRoundRect(mBoxRectF, mBox_default_radius, mBox_default_radius, mBox_default_paint);
                }
            }else { //没有开启锁定,绘制正常的boxAfter样式
                if(null!= mBox_hasInput_backgroundDrawable) {  //如果有设置drawable,则绘制drawable
                    mBox_hasInput_backgroundDrawable.setBounds((int)mBoxRectF.left,(int)mBoxRectF.top,(int)mBoxRectF.right,(int)mBoxRectF.bottom);
                    mBox_hasInput_backgroundDrawable.draw(canvas);
                }else {
                    mBox_default_paint.setColor(mBox_default_hasInputColor);
                    canvas.drawRoundRect(mBoxRectF, mBox_default_radius, mBox_default_radius, mBox_default_paint);
                }

            }

        //绘制输入的内容文字
        mPaintText.getTextBounds(mEnableHideCode ? mEnableHideCode_text : mCodeArray[i], 0, mCodeArray[i].length(), mTextRect);
        canvas.drawText(mEnableHideCode ? mEnableHideCode_text : mCodeArray[i], (mBoxRectF.left + mBoxRectF.right) / 2 - (mTextRect.left + mTextRect.right) / 2, (mBoxRectF.top + mBoxRectF.bottom) / 2 - (mTextRect.top + mTextRect.bottom) / 2, mPaintText);

    }
    //绘制盒子 - 高亮或光标
    private void onDrawHighLightCursor(Canvas canvas){
        if(null!= mBox_highLight_backgroundDrawable) {  //如果有设置高亮drawable,则绘制drawable,没有则用画笔绘制
            mBox_highLight_backgroundDrawable.setBounds((int)mBoxRectF.left,(int)mBoxRectF.top,(int)mBoxRectF.right,(int)mBoxRectF.bottom);
            mBox_highLight_backgroundDrawable.draw(canvas);
        }else {
            mBox_default_paint.setColor(mBox_default_highLightColor);
            canvas.drawRoundRect(mBoxRectF, mBox_default_radius, mBox_default_radius, mBox_default_paint);
        }
        if(mEnableCursor) { //如果开启了光标,则绘制
            onDrawCursor(canvas, mBox_default_paint, mBoxRectF);
        }
    }
    //绘制-光标
    private void onDrawCursor(Canvas canvas,Paint paint,RectF rectF){
            if(null!= mCursorBackgroundDrawable){
                mCursorBackgroundDrawable.setBounds(
                        (int)((rectF.left + rectF.right) / 2 - mCursorWidth),
                        (int)(mCursorHeight <= 1 ? (rectF.top + rectF.bottom) / 4:mCursorHeight ),
                        (int)((rectF.left + rectF.right) / 2 + mCursorWidth),
                        (int) (rectF.bottom - (mCursorHeight <= 1 ? (rectF.top + rectF.bottom) / 4:mCursorHeight ))
                );
                if((mCursorDisplayingByTimer || mCursorDisplayingByIndex) ){
                    mCursorBackgroundDrawable.draw(canvas);
                }
            }else {
                paint.setColor((mCursorDisplayingByTimer || mCursorDisplayingByIndex) ? mCursorColor : Color.TRANSPARENT);
                canvas.drawRect(
                        (float) ((rectF.left + rectF.right) / 2 - mCursorWidth),
                        (float) (mCursorHeight <= 1 ? (rectF.top + rectF.bottom) / 4:mCursorHeight ),
                        (float) ((rectF.left + rectF.right) / 2 + mCursorWidth),
                        (float) (rectF.bottom - (mCursorHeight <= 1 ? (rectF.top + rectF.bottom) / 4 :mCursorHeight))
                        , paint);
            }
        mCursorDisplayingByIndex=false;
    }
    //开始计时器,开始光标闪烁
    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if(mEnableCursor) {
            if(null!=mCursorTimer) {
                mCursorTimer.scheduleAtFixedRate(mCursorTimerTask, 0, mCursorFrequency);
            }
        }
    }
    //停止计时器,停止光标闪烁
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        mCursorTimer.cancel();
    }
    //打开软键盘
    public void openSoftKeyboard(View view){
        if(null != view ) {
            view.setFocusable(true);
            view.setFocusableInTouchMode(true);
            view.requestFocus();
            inputMethodManager.showSoftInput(view, 0);
        }

    }
    //关闭软键盘
    public void closeSoftKeyboard(View view){
        if(null != view) {
            if (mEnableSoftKeyboardAutoClose || mIsLocked || mEnableLockCodeTextIfMaxCode) {
                view.clearFocus();
                inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
            }
        }
    }
    //接口回调输入结果
    public interface OnResultListener {
        void finish(String result);
        void typing(String typing);
    }

    //监听接口回调
    public void setOnResultListener(OnResultListener onResultListener){
        this.mOnResultListener=onResultListener;
    }

}


attrs.xml代码

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="PasswordView">
        <attr name="password_setViewBackground" format="reference|color"></attr>
        <attr name="password_enableHideCode" format="boolean"></attr>
        <attr name="password_enableHideBoxWhenNotInput" format="boolean"></attr>
        <attr name="password_enableHideCodeSetText" format="string"></attr>
        <attr name="password_enableCursor" format="boolean"></attr>
        <attr name="password_enableHighLight" format="boolean"></attr>
        <attr name="password_enableSoftKeyboardAutoShow" format="boolean"></attr>
        <attr name="password_enableSoftKeyboardAutoClose" format="boolean"></attr>
        <attr name="password_enableLockTextView" format="boolean"></attr>
        <attr name="password_text_setColor" format="color"></attr>
        <attr name="password_text_setSize" format="integer"></attr>
        <attr name="password_text_setInputType" format="integer">
            <enum name="Number" value="200" />
            <enum name="Phone" value="201" />
            <enum name="Text" value="202" />
            <enum name="DateTime" value="203" />
        </attr>
        <attr name="password_text_setIsBold" format="boolean"></attr>
        <attr name="password_box_setNumber" format="integer"></attr>
        <attr name="password_box_setMargin" format="integer"></attr>
        <attr name="password_box_setSize" format="integer"></attr>

        <attr name="password_box_notInput_backgroundDrawable" format="reference|color"></attr>
        <attr name="password_box_locked_backgroundDrawable" format="reference|color"></attr>
        <attr name="password_box_highLight_backgroundDrawable" format="reference|color"></attr>
        <attr name="password_box_hasInput_backgroundDrawable" format="reference|color"></attr>

        <attr name="password_cursorHeight" format="integer"></attr>
        <attr name="password_cursorWidth" format="integer"></attr>
        <attr name="password_cursorFrequencyMillisecond" format="integer"></attr>
        <attr name="password_cursorBackgroundDrawable" format="reference|color"></attr>
        <attr name="password_cursorColor" format="reference|color"></attr>
    </declare-styleable>
</resources>

Android技术生活交流

微信 ----- qq群


  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值