自定义view-仿支付宝淘宝自定义密码

本文介绍如何在Android中自定义键盘布局及密码输入框,包括XML布局定义、密码框属性配置、绘制背景、分割线及密码圆点等关键步骤。

这里写图片描述

自定义键盘布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#EBEBEB"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginRight="1dp"
            android:layout_weight="1"
            android:background="#FFFFFF"
            android:gravity="center"
            android:padding="20dp"
            android:text="1" />

        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginRight="1dp"
            android:layout_weight="1"
            android:background="#FFFFFF"
            android:gravity="center"
            android:padding="20dp"
            android:text="2" />

        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="#FFFFFF"
            android:gravity="center"
            android:padding="20dp"
            android:text="3" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="1dp">

        <TextView
            android:id="@+id/textView3"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginRight="1dp"
            android:layout_weight="1"
            android:background="#FFFFFF"
            android:gravity="center"
            android:padding="20dp"
            android:text="4" />

        <TextView
            android:id="@+id/textView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginRight="1dp"
            android:layout_weight="1"
            android:background="#FFFFFF"
            android:gravity="center"
            android:padding="20dp"
            android:text="5" />

        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="#FFFFFF"
            android:gravity="center"
            android:padding="20dp"
            android:text="6" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="1dp">

        <TextView
            android:id="@+id/textView2"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginRight="1dp"
            android:layout_weight="1"
            android:background="#FFFFFF"
            android:gravity="center"
            android:padding="20dp"
            android:text="7" />

        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginRight="1dp"
            android:layout_weight="1"
            android:background="#FFFFFF"
            android:gravity="center"
            android:padding="20dp"
            android:text="8" />

        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="#FFFFFF"
            android:gravity="center"
            android:padding="20dp"
            android:text="9" />

    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="1dp"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/textView4"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginRight="1dp"
            android:layout_weight="1"
            android:gravity="center"
            android:padding="20dp" />

        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginRight="1dp"
            android:layout_weight="1"
            android:background="#FFFFFF"
            android:gravity="center"
            android:padding="20dp"
            android:text="0" />

        <ImageView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center"
            android:padding="15dp"
            android:layout_gravity="center_vertical"
            android:src="@drawable/customer_password_keyboard_delete" />
    </LinearLayout>
</LinearLayout>

自定义密码框

  • 属性
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="PasswordEditText">
        <!-- 密码的个数 -->
        <attr name="passwordNumber" format="integer"/>
        <!-- 密码圆点的半径 -->
        <attr name="passwordRadius" format="dimension" />
        <!-- 密码圆点的颜色 -->
        <attr name="passwordColor" format="color" />
        <!-- 分割线的颜色 -->
        <attr name="divisionLineColor" format="color" />
        <!-- 分割线的大小 -->
        <attr name="divisionLineSize" format="dimension" />
        <!-- 背景边框的颜色 -->
        <attr name="bgColor" format="color" />
        <!-- 背景边框的大小 -->
        <attr name="bgSize" format="dimension" />
        <!-- 背景边框的圆角大小 -->
        <attr name="bgCorner" format="dimension"/>
    </declare-styleable>
</resources>

自定义输入框

public class PasswordEditText extends EditText {
    // 画笔
    private Paint mPaint;
    // 一个密码所占的宽度
    private int mPasswordItemWidth;
    // 密码的个数默认为6位数
    private int mPasswordNumber = 6;
    // 背景边框颜色
    private int mBgColor = Color.parseColor("#d1d2d6");
    // 背景边框大小
    private int mBgSize = 1;
    // 背景边框圆角大小
    private int mBgCorner = 0;
    // 分割线的颜色
    private int mDivisionLineColor = mBgColor;
    // 分割线的大小
    private int mDivisionLineSize = 1;
    // 密码圆点的颜色
    private int mPasswordColor = mDivisionLineColor;
    // 密码圆点的半径大小
    private int mPasswordRadius = 4;

    public PasswordEditText(Context context) {
        this(context, null);
    }

    public PasswordEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        initAttributeSet(context, attrs);
        initPaint();
        //设置默认只能设置数字和字母
        setInputType(EditorInfo.TYPE_TEXT_VARIATION_PASSWORD);
    }

    /**
     * 初始化画笔
     */
    private void initPaint() {
        mPaint = new Paint();
        // 抗锯齿
        mPaint.setAntiAlias(true);

        // 防抖动
        mPaint.setDither(true);
    }

    /**
     * 初始化属性
     */
    private void initAttributeSet(Context context, AttributeSet attrs) {
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.PasswordEditText);
        // 获取大小
        mDivisionLineSize = (int) array.getDimension(R.styleable.PasswordEditText_divisionLineSize, dip2px(mDivisionLineSize));
        mPasswordRadius = (int) array.getDimension(R.styleable.PasswordEditText_passwordRadius, dip2px(mPasswordRadius));
        mBgSize = (int) array.getDimension(R.styleable.PasswordEditText_bgSize, dip2px(mBgSize));
        mBgCorner = (int) array.getDimension(R.styleable.PasswordEditText_bgCorner, 0);
        // 获取颜色
        mBgColor = array.getColor(R.styleable.PasswordEditText_bgColor, mBgColor);
        mDivisionLineColor = array.getColor(R.styleable.PasswordEditText_divisionLineColor, mDivisionLineColor);
        mPasswordColor = array.getColor(R.styleable.PasswordEditText_passwordColor, mDivisionLineColor);
        array.recycle();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // 一个密码的宽度
        mPasswordItemWidth = (getWidth() - 2 * mBgSize - (mPasswordNumber - 1) * mDivisionLineSize) / mPasswordNumber;
        //画背景
        drawBg(canvas);
        // 画分割线
        drawDivisionLine(canvas);
        //画密码
        drawPassWord(canvas);

    }

    /**
     * 绘制密码
     */
    private void drawPassWord(Canvas canvas) {
        //设置为实心
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(mPasswordColor);

        //获取输入框内容
        String password = getText().toString().trim();
        int length = password.length();
        //for循环
        for (int i = 0; i < length; i++) {
            int cy=getHeight()/2;
            int cx = mBgSize + i * mPasswordItemWidth + i * mDivisionLineSize + mPasswordItemWidth / 2;
            canvas.drawCircle(cx,cy,mPasswordRadius,mPaint);
        }
    }

    /**
     * 画分割线
     */
    private void drawDivisionLine(Canvas canvas) {
        mPaint.setStrokeWidth(mDivisionLineSize);
        mPaint.setColor(mDivisionLineColor);
        for (int i = 0; i < mPasswordNumber-1; i++) {
            float startX = (i+1)*mPasswordItemWidth+mBgSize+mDivisionLineSize;
            float startY = mBgSize;
            float endX = startX;
            float endY = getHeight()-mBgSize;
            canvas.drawLine(startX, startY, endX, endY, mPaint);
        }

    }

    /**
     * 绘制背景
     */
    private void drawBg(Canvas canvas) {
        //如果没有设置背景则 canvas.drawRect();
//        RectF rect=new RectF(0,0,getWidth(),getHeight());
        RectF rect = new RectF(mBgSize, mBgSize, getWidth() - mBgSize, getHeight() - mBgSize);
        mPaint.setStrokeWidth(mBgSize);
        //设置画笔为空心
        mPaint.setStyle(Paint.Style.STROKE);
        if (mBgCorner == 0) {
            canvas.drawRect(rect, mPaint);
        } else {
            canvas.drawRoundRect(rect, mBgCorner, mBgCorner, mPaint);
        }

    }

    /**
     * px 转 dp
     */
    private float dip2px(int dip) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                dip, getResources().getDisplayMetrics());
    }

    /**
     * 添加密码
     */
    public void addPassWordNumber(String number) {
        String passWord = getText().toString();
        if(passWord.length()>=mPasswordNumber){//当前密码的长度大于当前密码数量return
            return;
        }
        passWord+=number;
        setText(passWord);
        //判断是否添加密码是否添加完成
        if(mListener!=null){
            if(passWord.length()>=mPasswordNumber){
                mListener.passwordFull(getText().toString().trim());
            }
        }
    }

    /**
     * 删除密码
     */
    public void deletePassWord() {
        String passWord = getText().toString().trim();
        if(passWord.length()<=0){
            return;
        }
        passWord=passWord.substring(0,passWord.length()-1);
        setText(passWord);
    }
    // 设置当前密码是否已满的接口回掉
    private PasswordFullListener mListener;
    public void setOnPasswordFullListener(PasswordFullListener listener){
        this.mListener = listener;
    }



    /**
     * 密码已经全部填满
     */
    public interface PasswordFullListener {
        public void passwordFull(String password);
    }
}

CustomerKeyboard:自定义键盘

public class CustomerKeyboard extends LinearLayout implements View.OnClickListener {
    public CustomerKeyboard(Context context) {
        this(context, null);
    }

    public CustomerKeyboard(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CustomerKeyboard(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        LayoutInflater.from(context).inflate(R.layout.ui_customer_keyboard, this);
        setItemClickListener(this);
    }

    /**
     * 设置子view的点击事件
     */
    public void setItemClickListener(View view) {
        if (view instanceof ViewGroup) {
            ViewGroup viewGroup = (ViewGroup) view;//LinearLayout
            //继续遍历
            int childCount = viewGroup.getChildCount();
            for (int i = 0; i < childCount; i++) {
                //不断遍历循环
                View childView = viewGroup.getChildAt(i);
                setItemClickListener(childView);
            }
        } else {
            view.setOnClickListener(this);
        }

    }

    @Override
    public void onClick(View v) {
        if (v instanceof TextView) {
            String number = ((TextView) v).getText().toString().trim();
            if(v.getId()==R.id.textView4){
                Toast.makeText(getContext(),"改按钮不可点击",Toast.LENGTH_SHORT).show();
                return;
            }
            if (mListener != null) {
                mListener.click(number);
            }
        }
        if(v instanceof ImageView){
            if(mListener!=null){
                mListener.delete();
            }
        }
    }

    // 设置点击回掉监听
    private CustomerKeyboardClickListener mListener;

    public void setOnCustomerKeyboardClickListener(CustomerKeyboardClickListener listener) {
        this.mListener = listener;
    }

    /**
     * 点击键盘的回调监听
     */
    public interface CustomerKeyboardClickListener {
        public void click(String number);

        public void delete();
    }
}

MainActivity中使用

   mPasswordEditText = (PasswordEditText) findViewById(R.id.password_edit_text);
        mCustomerKeyBoard = (CustomerKeyboard) findViewById(R.id.customer_key_board);
        mPasswordEditText.setOnPasswordFullListener(this);
        mCustomerKeyBoard.setOnCustomerKeyboardClickListener(new CustomerKeyboard.CustomerKeyboardClickListener() {
            @Override
            public void click(String number) {
                //Toast.makeText(MainActivity.this,"点击了"+number,Toast.LENGTH_SHORT).show();
                mPasswordEditText.addPassWordNumber(number);
            }

            @Override
            public void delete() {
                //Toast.makeText(MainActivity.this,"点击了删除",Toast.LENGTH_SHORT).show();
                mPasswordEditText.deletePassWord();
            }
        });

@Override
    public void passwordFull(String password) {
        Toast.makeText(MainActivity.this,"你输入的密码是:"+password,Toast.LENGTH_SHORT).show();
    }

最后:附上源码的位置:https://gitee.com/yijia_cn/Android_Advanced.git

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值