1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Android仿淘寶密碼輸入框功能

        共 11958字,需瀏覽 24分鐘

         ·

        2021-11-08 11:41

        背景

        近期公司項(xiàng)目需要實(shí)現(xiàn)青少年模式,UI上需要一個(gè)特定的密碼輸入框,類(lèi)似淘寶和銀行。

        效果圖


        挽起袖子擼代碼

        • 密碼框的java代碼:

        public class PasswordEditText extends EditText {
        /** 默認(rèn)的密碼顏色 */ private static final int DEFAULT_PASSWORD_COLOR = Color.parseColor("#333333");
        /** 默認(rèn)邊框的顏色 */ private static final int DEFAULT_BORDER_COLOR = Color.parseColor("#d1d2d6");
        /** 默認(rèn)密碼下劃線(xiàn)的顏色 */ private static final int DEFAULT_UNDERLINE_COLOR = Color.parseColor("#666666");
        private static final int BACKGROUND_STYLE_BORDER = 0;
        private static final int BACKGROUND_STYLE_UNDERLINE = 1;
        /** 密碼的畫(huà)筆 */ private Paint mPasswordPaint; /** 密碼圓點(diǎn)的顏色 */ private int mPasswordColor = DEFAULT_PASSWORD_COLOR; /** 一個(gè)密碼所占的寬度 */ private int mPasswordItemWidth; /** 密碼的個(gè)數(shù),默認(rèn)為4位數(shù) */ private int mPasswordNumber = 4; /** 密碼圓點(diǎn)的半徑大小,m默認(rèn)為4像素 */ private int mPasswordRadius = 4;
        /** 下劃線(xiàn)的畫(huà)筆 */ private Paint mUnderlinePaint; /** 密碼底部下劃線(xiàn)的寬度 */ private int mUnderlineWidth; /** 密碼底部下劃線(xiàn)的厚度 */ private int mUnderlineSize = 1; /** 密碼底部下劃線(xiàn)的寬度 */ private int mUnderlineColor = DEFAULT_UNDERLINE_COLOR;
        /** 邊框的畫(huà)筆 */ private Paint mBorderPaint; /** 背景邊框顏色 */ private int mBorderColor = DEFAULT_BORDER_COLOR; /** 背景邊框厚度大小 */ private int mBorderStrokeSize = 1; /** 背景邊框圓角大小 */ private int mBorderCorner = 0;
        /** 分隔線(xiàn)的畫(huà)筆 */ private Paint mDivisionLinePaint; /** 分割線(xiàn)的顏色,默認(rèn)跟邊框同個(gè)顏色 */ private int mDivisionLineColor = mBorderColor; /** 分割線(xiàn)的大小 */ private int mDivisionLineSize = 1;
        /** 樣式類(lèi)型 */ private int mBgStyle = 0;
        public PasswordEditText(Context context) { this(context, null); }
        public PasswordEditText(Context context, AttributeSet attrs) { super(context, attrs); initAttributeSet(context, attrs); initPaint(); // 默認(rèn)只能夠設(shè)置數(shù)字 setInputType(EditorInfo.TYPE_TEXT_VARIATION_PASSWORD); }
        /** * 初始化畫(huà)筆 */ private void initPaint() { // 初始化密碼邊框的畫(huà)筆 mBorderPaint = new Paint(); // 抗鋸齒 mBorderPaint.setAntiAlias(true); // 防抖動(dòng) mBorderPaint.setDither(true); // 給畫(huà)筆設(shè)置大小 mBorderPaint.setStrokeWidth(mBorderStrokeSize); // 設(shè)置背景的顏色 mBorderPaint.setColor(mBorderColor); // 畫(huà)空心 mBorderPaint.setStyle(Paint.Style.STROKE);
        // 初始化分隔線(xiàn)的畫(huà)筆 mDivisionLinePaint = new Paint(); // 抗鋸齒 mDivisionLinePaint.setAntiAlias(true); // 防抖動(dòng) mDivisionLinePaint.setDither(true); // 分割線(xiàn)畫(huà)筆設(shè)置大小 mDivisionLinePaint.setStrokeWidth(mDivisionLineSize); // 設(shè)置分割線(xiàn)的顏色 mDivisionLinePaint.setColor(mDivisionLineColor);
        //初始化密碼的畫(huà)筆 mPasswordPaint = new Paint(); // 抗鋸齒 mPasswordPaint.setAntiAlias(true); // 防抖動(dòng) mPasswordPaint.setDither(true); // 密碼繪制是實(shí)心 mPasswordPaint.setStyle(Paint.Style.FILL); // 設(shè)置密碼的顏色 mPasswordPaint.setColor(mPasswordColor);
        //初始化下劃線(xiàn)的畫(huà)筆 mUnderlinePaint = new Paint(); // 抗鋸齒 mUnderlinePaint.setAntiAlias(true); // 防抖動(dòng) mUnderlinePaint.setDither(true); // 設(shè)置顏色 mUnderlinePaint.setColor(mUnderlineColor); // 設(shè)置畫(huà)筆的大小 mUnderlinePaint.setStrokeWidth(mUnderlineSize); }
        /** * 初始化屬性 */ private void initAttributeSet(Context context, AttributeSet attrs) { TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.PasswordEditText); // 密碼的顏色 mPasswordColor = array.getColor(R.styleable.PasswordEditText_passwordColor, mPasswordColor); // 密碼圓點(diǎn)的半徑 mPasswordRadius = (int) array.getDimension(R.styleable.PasswordEditText_passwordRadius, dip2px(mPasswordRadius)); // 密碼的個(gè)數(shù) mPasswordNumber = array.getInteger(R.styleable.PasswordEditText_passwordNumber, mPasswordNumber);
        // 間隔線(xiàn)大小 mDivisionLineSize = (int) array.getDimension(R.styleable.PasswordEditText_divisionLineSize, dip2px(mDivisionLineSize)); // 間隔線(xiàn)的顏色 mDivisionLineColor = array.getColor(R.styleable.PasswordEditText_divisionLineColor, mDivisionLineColor);
        // 邊框的厚度 mBorderStrokeSize = (int) array.getDimension(R.styleable.PasswordEditText_bgSize, dip2px( mBorderStrokeSize)); // 邊框的圓角 mBorderCorner = (int) array.getDimension(R.styleable.PasswordEditText_bgCorner, 0); // 獲取邊框的顏色 mBorderColor = array.getColor(R.styleable.PasswordEditText_bgColor, mBorderColor);
        // 下劃線(xiàn)的顏色 mUnderlineColor = array.getColor(R.styleable.PasswordEditText_underlineColor, mUnderlineColor); // 下劃線(xiàn)的厚度 mUnderlineSize = (int) array.getDimension(R.styleable.PasswordEditText_underlineSize, dip2px(mUnderlineSize));
        // 樣式類(lèi)型 mBgStyle = array.getInteger(R.styleable.PasswordEditText_bgStyle, BACKGROUND_STYLE_BORDER); array.recycle(); }
        /** * dip 轉(zhuǎn) px */ private float dip2px(int dip) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, getResources().getDisplayMetrics()); }
        @Override protected void onDraw(Canvas canvas) { // 一個(gè)密碼的寬度 mPasswordItemWidth = (getWidth() - 2 * mBorderStrokeSize - (mPasswordNumber - 1) * mDivisionLineSize) / mPasswordNumber; mUnderlineWidth = mPasswordItemWidth - 8 * mBorderStrokeSize;
        if(mBgStyle == BACKGROUND_STYLE_UNDERLINE) { //繪制下劃線(xiàn) drawUnderLine(canvas); }else { // 畫(huà)背景 drawBg(canvas); // 畫(huà)分割線(xiàn) drawDivisionLine(canvas); } // 畫(huà)密碼 drawPassword(canvas);
        // 當(dāng)前密碼是不是滿(mǎn)了 if (mListener != null) { String password = getText().toString().trim(); if (password.length() >= mPasswordNumber) { mListener.passwordFull(password); } else { mListener.passwordChanged(password); } } }
        /** * 繪制密碼 */ private void drawPassword(Canvas canvas) { // 獲取當(dāng)前text String text = getText().toString().trim(); // 獲取密碼的長(zhǎng)度 int passwordLength = text.length(); // 不斷的繪制密碼 for (int i = 0; i < passwordLength; i++) { int cy = getHeight() / 2; int cx = mBorderStrokeSize + i * mPasswordItemWidth + i * mDivisionLineSize + mPasswordItemWidth / 2; canvas.drawCircle(cx, cy, mPasswordRadius, mPasswordPaint); } }
        /** * 繪制分割線(xiàn) */ private void drawDivisionLine(Canvas canvas) {
        for (int i = 0; i < mPasswordNumber - 1; i++) { int startX = mBorderStrokeSize + (i + 1) * mPasswordItemWidth + i * mDivisionLineSize; int startY = mBorderStrokeSize; int endX = startX; int endY = getHeight() - mBorderStrokeSize; canvas.drawLine(startX, startY, endX, endY, mDivisionLinePaint); } }
        /** * 繪制背景 */ private void drawBg(Canvas canvas) { RectF rect = new RectF(mBorderStrokeSize, mBorderStrokeSize, getWidth() - mBorderStrokeSize, getHeight() - mBorderStrokeSize); // 繪制背景 drawRect , drawRoundRect , // 如果有圓角那么就繪制drawRoundRect,否則繪制drawRect if (mBorderCorner == 0) { canvas.drawRect(rect, mBorderPaint); } else { canvas.drawRoundRect(rect, mBorderCorner, mBorderCorner, mBorderPaint); } }
        /** * 繪制每個(gè)密碼項(xiàng)的底部下劃線(xiàn) */ private void drawUnderLine(Canvas canvas) { for (int i = 0; i < mPasswordNumber; i++) { int startX = mBorderStrokeSize * 4 + i * mPasswordItemWidth; int startY = getHeight() - mBorderStrokeSize; int endX = startX + mUnderlineWidth; int endY = getHeight() - mBorderStrokeSize; canvas.drawLine(startX, startY, endX, endY, mUnderlinePaint); } }
        /** * 添加一個(gè)密碼 */ public void addPassword(String number) { // 把之前的密碼取出來(lái) String password = getText().toString().trim(); if (password.length() >= mPasswordNumber) { // 密碼不能超過(guò)當(dāng)前密碼個(gè)輸 return; } // 密碼疊加 password += number; setText(password); }
        /** * 刪除最后一位密碼 */ public void deleteLastPassword() { String password = getText().toString().trim(); // 判斷當(dāng)前密碼是不是空 if (TextUtils.isEmpty(password)) { return; } password = password.substring(0, password.length() - 1); setText(password); }
        // 設(shè)置當(dāng)前密碼是否已滿(mǎn)的接口回掉 private PasswordFullListener mListener;
        public void setOnPasswordFullListener(PasswordFullListener listener) { this.mListener = listener; }
        /** * 密碼已經(jīng)全部填滿(mǎn) */ public interface PasswordFullListener { void passwordFull(String password); void passwordChanged(String password); }}


        • 密碼框的自定義屬性

                                                                                                                    


        • 定制的數(shù)字鍵盤(pán)的java代碼:

        public class DigitKeyboard extends LinearLayout implements View.OnClickListener {  private DigitKeyboardClickListener mListener;
        public DigitKeyboard(Context context) { this(context, null); }
        public DigitKeyboard(Context context, AttributeSet attrs) { this(context, attrs, 0); }
        public DigitKeyboard(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); inflate(context, R.layout.digit_keyboard, this); setChildViewOnclick(this); }
        /** * 設(shè)置鍵盤(pán)子View的點(diǎn)擊事件 */ private void setChildViewOnclick(ViewGroup parent) { int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { // 不斷的遞歸設(shè)置點(diǎn)擊事件 View view = parent.getChildAt(i); if (view instanceof ViewGroup) { setChildViewOnclick((ViewGroup) view); continue; } view.setOnClickListener(this); } }
        @Override public void onClick(View v) { View clickView = v; if (clickView instanceof TextView) { // 如果點(diǎn)擊的是TextView String number = ((TextView) clickView).getText().toString(); if (!TextUtils.isEmpty(number)) { if (mListener != null) { // 回調(diào) mListener.click(number); } } } else if (clickView instanceof ImageView) { // 如果是圖片那肯定點(diǎn)擊的是刪除 if (mListener != null) { mListener.delete(); } } }
        public boolean dispatchKeyEventInFullScreen(KeyEvent event) { if(event == null){ return false; } switch (event.getKeyCode()) { case KeyEvent.KEYCODE_BACK: if (isShown()) { setVisibility(GONE); return true; } default: return false; } }
        /** * 設(shè)置鍵盤(pán)的點(diǎn)擊回調(diào)監(jiān)聽(tīng) */ public void setOnDigitKeyboardClickListener(DigitKeyboardClickListener listener) { this.mListener = listener; }
        /** * 點(diǎn)擊鍵盤(pán)的回調(diào)監(jiān)聽(tīng) */ public interface DigitKeyboardClickListener { public void click(String number); public void delete(); }}


        • 鍵盤(pán)的布局文件:digit_keyboard.xml(這邊用LinearLayout層級(jí)比較多,推薦可以使用GridView)

            android:layout_width="match_parent"    android:layout_height="wrap_content"    android:paddingTop="1dp"    android:background="#EBEBEB"    android:orientation="vertical">
        android:layout_width="match_parent" android:layout_height="wrap_content">
        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" />
        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" />
        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" />
        android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="1dp">
        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" />
        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" />
        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" />
        android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="1dp">
        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" />
        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" />
        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" />

        android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="1dp" android:orientation="horizontal">
        android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginRight="1dp" android:layout_weight="1" android:gravity="center" android:padding="20dp" />
        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" />
        android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:padding="15dp" android:layout_gravity="center" android:src="@drawable/hkyb_keyboard_delete" />


        使用

        • 布局文件引用:

          xmlns:app="http://schemas.android.com/apk/res-auto"  android:layout_width="match_parent"  android:layout_height="match_parent"  >      android:orientation="vertical"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="@color/hykb_white"    >          android:orientation="vertical"      android:layout_width="match_parent"      android:layout_height="44dp"      >              android:id="@+id/btn_close"        android:layout_width="wrap_content"        android:layout_height="match_parent"        android:paddingLeft="12dp"        android:paddingRight="12dp"        android:src="@drawable/ic_back_default"        />    
        android:id="@+id/tv_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginBottom="36dp" android:layout_marginLeft="24dp" android:layout_marginRight="24dp" android:layout_marginTop="38dp" android:lineSpacingExtra="4dp" android:textColor="@color/black" android:textSize="24sp" android:textStyle="bold" />
        android:id="@+id/tv_content" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginBottom="30dp" android:layout_marginLeft="24dp" android:layout_marginRight="24dp" android:textColor="@color/gray" android:textSize="14sp" />
        android:id="@+id/et_password" android:layout_width="240dp" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:background="@null" android:digits="0123456789" android:inputType="number" android:padding="10dp" app:bgCorner="3dp" app:passwordColor="@color/black" app:bgStyle="underline" app:underlineSize="2dp" app:underlineColor="@color/thin_gray" />
        android:id="@+id/btn_sure" android:layout_width="match_parent" android:layout_height="44dp" android:layout_marginLeft="24dp" android:layout_marginRight="24dp" android:layout_marginTop="30dp" android:background="@drawable/bg_open_button" android:gravity="center" android:textColor="@color/hykb_white" android:textSize="16sp" />
        android:id="@+id/tv_get_password" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:textColorHighlight="@android:color/transparent" android:layout_marginTop="20dp" android:visibility="gone" /> android:id="@+id/custom_key_board" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" />


        • java代碼引用:

        public class PasswordActivity extends BaseActivity    implements DigitKeyboard.DigitKeyboardClickListener,    PasswordEditText.PasswordFullListener {
        private PasswordEditText pwdEdit; private DigitKeyboard keyboard;
        @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(ResourcesUtils.getLayoutId(this, "activity_password"));
        initView(); initListener(); }
        /** * 初始化控件 */ private void initView() { pwdEdit = findViewById(ResourcesUtils.getId(this, "et_password")); keyboard = findViewById(ResourcesUtils.getId(this, "custom_key_board")); }
        /** * 初始化事件監(jiān)聽(tīng) */ private void initListener() { keyboard.setOnDigitKeyboardClickListener(this); pwdEdit.setOnPasswordFullListener(this);
        pwdEdit.setEnabled(true); pwdEdit.setFocusable(false); pwdEdit.setFocusableInTouchMode(false); pwdEdit.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { keyboard.setVisibility(View.VISIBLE); } }); }
        @Override public void click(String number) { pwdEdit.addPassword(number); }
        @Override public void delete() { pwdEdit.deleteLastPassword(); }
        @Override public void passwordFull(String password) { setButtonStatus(true); }
        @Override public void passwordChanged(String password) { setButtonStatus(false); }
        @Override public boolean onKeyDown(int keyCode, KeyEvent event) { boolean isConsum = keyboard.dispatchKeyEventInFullScreen(event); return isConsum ? isConsum : super.onKeyDown(keyCode, event); }


        到這里就結(jié)束啦。
        瀏覽 35
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            大香蕉婷婷在线 | 久久久裸体视频 | 丁香五月在线观看 | 男人舔女人下部视频 | 成人无码免费在线视频 | 欧美成人一级片 | 伊人久久天天 | 亚洲精品观看 | 天堂俺去俺来也WWW | 69国产精品人妻无码免费 |