<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Android仿淘寶密碼輸入框功能

          共 11958字,需瀏覽 24分鐘

           ·

          2021-11-08 11:41

          背景

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

          效果圖


          挽起袖子擼代碼

          • 密碼框的java代碼:

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


          • 密碼框的自定義屬性

                                                                                                                      


          • 定制的數(shù)字鍵盤的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); }
          /** * 設置鍵盤子View的點擊事件 */ private void setChildViewOnclick(ViewGroup parent) { int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { // 不斷的遞歸設置點擊事件 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) { // 如果點擊的是TextView String number = ((TextView) clickView).getText().toString(); if (!TextUtils.isEmpty(number)) { if (mListener != null) { // 回調 mListener.click(number); } } } else if (clickView instanceof ImageView) { // 如果是圖片那肯定點擊的是刪除 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; } }
          /** * 設置鍵盤的點擊回調監(jiān)聽 */ public void setOnDigitKeyboardClickListener(DigitKeyboardClickListener listener) { this.mListener = listener; }
          /** * 點擊鍵盤的回調監(jiān)聽 */ public interface DigitKeyboardClickListener { public void click(String number); public void delete(); }}


          • 鍵盤的布局文件:digit_keyboard.xml(這邊用LinearLayout層級比較多,推薦可以使用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)聽 */ 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); }


          到這里就結束啦。
          瀏覽 35
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  av乱伦网址 | 在线毛片网址 | A片免费直接看 | 北条麻妃99精品青青久久 | 欧美成人免费观看视频 |