自定義V_04_InputPassword

一、效果


密碼輸入.png

二、描述
實現(xiàn)一個密碼輸入框,繼承自Editext免去了位置的測量,將這個放入一個Dialog中,可以實現(xiàn)一個自定義的輸入密碼鍵盤
三、分析
1.首先要畫好背景框
2.在畫里面的豎線
1)每一次:從上一次的豎線寬度+(本次條目的寬度 )+ 本次邊框的寬度
int startX = bgBorderSize + (i + 1) * itemWidth + i * bgBorderSize;


表格.png

3.畫圓點(diǎn)
1)其實就是用的Canvas畫View替換了系統(tǒng)的draw(),如果這里不注釋 super.onDraw(canvas);在最開始的起點(diǎn)那里長按依然可以選中那些文字,當(dāng)然這不是重點(diǎn);

2)獲取文字長度計算圓點(diǎn)個數(shù):畫的位置相當(dāng)于一個 錯位 的感覺,就是第一次是框的寬度的一半,下一個圓點(diǎn)距離就是上次位置加一個框的寬度
圓點(diǎn).png

3)鍵盤就簡單多了,繼承自LinearLayout引入布局,主要是把子View設(shè)置監(jiān)聽事件,然后進(jìn)行一個回調(diào)。

四、動手
1)man.xml

<com.example.my_inputlayout.view.MyEditextLayout
    android:id="@+id/editextLayout"
    android:layout_width="300dp"
    android:layout_height="50dp"
    android:layout_margin="10dp"
    android:background="@null"
    app:bgCircularBeadSize="1dp"
    app:inputCount="6"
    app:bgBorderSize="1dp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:pointSizePi="6dp"
    app:lineColor="@color/colorAccent"
    app:lineWidth="2" />

<com.example.my_inputlayout.view.InputKeybordLayout
    android:id="@+id/inputKeyBord"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    ></com.example.my_inputlayout.view.InputKeybordLayout>

··
2)Main.java

    editextLayout = findViewById(R.id.editextLayout);
    inputKeyBord = findViewById(R.id.inputKeyBord);
    //屏蔽系統(tǒng)鍵盤
    editextLayout.setEnabled(false);

    inputKeyBord.setKeyBordBack(new InputKeybordLayout.keyBordBack() {
        @Override
        public void click(String str) {
            editextLayout.addTextNumber(str);
        }

        @Override
        public void delete() {
            editextLayout.deleteNumber();
        }
    });

3)MyEditextLayout.java

public class MyEditextLayout extends AppCompatEditText {
  //密碼個數(shù)
  private int inputCount;
  //點(diǎn)的半徑大小
  private int pointSizePi;
  //點(diǎn)的顏色
  private int pointColor = Color.GRAY;
  //分隔線顏色
  private int lineColor = Color.GRAY;
  //線條寬度
  private int lineWidth = 1;
  //背景邊框顏色
  private int bgBorderColor = Color.GRAY;
  //背景邊框大小
  private int bgBorderSize = 1;
  //背景邊框圓角
  private int bgCircularBeadSize = 2;
  //設(shè)置最大輸入個數(shù)
  private int MAXNUMBERS = 6;
  private Paint mPaint;
  private Paint mBGPaint;
  private Paint mPointPaint;
  public MyEditextLayout(Context context) {
      super(context);
  }
public MyEditextLayout(Context context, AttributeSet attrs) {
      super(context, attrs);
      init(context, attrs);
  }

  public MyEditextLayout(Context context, AttributeSet attrs, int defStyleAttr) {
      super(context, attrs, defStyleAttr);
      init(context, attrs);
  }

  private void init(Context context, AttributeSet attrs) {
      TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MyEditextLayout);

      inputCount = array.getInteger(R.styleable.MyEditextLayout_inputCount, inputCount);
      pointSizePi = (int) array.getDimension(R.styleable.MyEditextLayout_pointSizePi, dip2px(pointSizePi));
      pointColor = array.getColor(R.styleable.MyEditextLayout_pointColor, pointColor);
      lineColor = array.getColor(R.styleable.MyEditextLayout_lineColor, lineColor);
      lineWidth = array.getInteger(R.styleable.MyEditextLayout_lineWidth, (int) dip2px(lineWidth));
      bgBorderColor = array.getColor(R.styleable.MyEditextLayout_bgBorderColor, bgBorderColor);
      bgBorderSize = (int) array.getDimension(R.styleable.MyEditextLayout_bgBorderSize, dip2px(bgBorderSize));
      bgCircularBeadSize = (int) array.getDimension(R.styleable.MyEditextLayout_bgCircularBeadSize, bgCircularBeadSize);

      array.recycle();

      mPaint = getMPaint();
      mPaint.setColor(bgBorderColor);


      mBGPaint = getMPaint();
      mBGPaint.setColor(bgBorderColor);
      mBGPaint.setStrokeWidth(bgBorderSize);

      mPointPaint = getMPaint();
      mPointPaint.setColor(pointColor);
      mPointPaint.setStyle(Paint.Style.FILL_AND_STROKE);

      setTextColor(0X00ffffff); //把用戶輸入的內(nèi)容設(shè)置為透明
      setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_NORMAL);
      this.setBackgroundDrawable(null);
      setLongClickable(false);
      setTextIsSelectable(false);
      setCursorVisible(false);
  }@Override
  protected void onDraw(Canvas canvas) {//        super.onDraw(canvas);
      drawBorderBG(canvas);
      drawBorderSeparate(canvas);
      drawPWD(canvas);
  }

  public void addTextNumber(String str) {
      if (TextUtils.isEmpty(str) || MAXNUMBERS == str.length())
          return;
      setText(getText() + str);
  }

  public void deleteNumber() {
      if (TextUtils.isEmpty(getText()) || getText().length() <= 0)
          return;
      String str = getText().toString().trim();
      str = str.substring(0, str.length() - 1);
      setText(str);
  }


  /**
   * 繪制框中心的點(diǎn)
   */
  private void drawPWD(Canvas canvas) {
      //實心圓
      //輸入的個數(shù)
      int pwdLength = getText().toString().length();
      for (int i = 0; i < pwdLength; i++) {
          //核心:豎線寬度 + 寬度的一半
          //      豎線寬度      + 項的寬度* i  +  i+豎線條數(shù)       + 項寬度一半
          int cx = bgBorderSize + itemWidth * i + i * bgBorderSize + itemWidth / 2;
          int cy = getHeight() / 2;
          canvas.drawCircle(cx, cy, pointSizePi, mPointPaint);
      }
  }

  /**
   * 中間的分隔
   *
   * @param canvas
   */
  private int itemWidth = 0;

  private void drawBorderSeparate(Canvas canvas) {
      //總的寬度 - (數(shù)量減-1 * 條豎線)
      int passwordWidth = getWidth() - (inputCount - 1) * lineWidth;
      itemWidth = passwordWidth / inputCount;
      mPaint.setStrokeWidth(bgBorderSize);
      //        itemWidth = (getWidth() - 2 * bgBorderSize - (inputCount - 1) * lineWidth) / inputCount;
      for (int i = 0; i < inputCount - 1; i++) {
          //x = 每一次:從上一次的豎線寬度+(本次條目的寬度 )+ 本次次邊框的寬度
          int startX = bgBorderSize + (i + 1) * itemWidth + i * bgBorderSize;
          int startY = bgBorderSize;
          int endX = startX;
          int endY = getHeight() - bgBorderSize;
          canvas.drawLine(startX, startY, endX, endY, mPaint);
      }

  }

  /**
   * 確定背景
   *
   * @param canvas
   */
  private void drawBorderBG(Canvas canvas) {
      RectF mRect = new RectF(bgCircularBeadSize, bgCircularBeadSize, getWidth() - bgCircularBeadSize, getHeight() - bgCircularBeadSize);
      if (bgCircularBeadSize > 0) {
          canvas.drawRoundRect(mRect, bgCircularBeadSize, bgCircularBeadSize, mBGPaint);
      } else {
          canvas.drawRect(mRect, mBGPaint);
      }

  }

  private Paint getMPaint() {
      Paint mPaint = new Paint();
      //抗據(jù)齒
      mPaint.setAntiAlias(true);
      //防抖動
      mPaint.setDither(true);
      mPaint.setStyle(Paint.Style.STROKE);
      return mPaint;
  }

  private float dip2px(int dip) {
      return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, getResources().getDisplayMetrics());
  }

4)InputKeybordLayout.java

public class InputKeybordLayout extends LinearLayout implements View.OnClickListener {
    public interface keyBordBack{
        void click(String str);
        void delete();
    }
    private keyBordBack keyBordBack;

    public void setKeyBordBack(InputKeybordLayout.keyBordBack keyBordBack) {
        this.keyBordBack = keyBordBack;
    }

    public InputKeybordLayout(Context context) {
        //        super(context);
        this(context, null);
    }

    public InputKeybordLayout(Context context, @Nullable AttributeSet attrs) {
        //        super(context, attrs);
        this(context, attrs, 0);
    }

    public InputKeybordLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        //加載布局
        inflate(context, R.layout.layout_keybord, this);
        addKeyBordClickListener(this);
    }

    /**
     * 遞歸設(shè)置子View事件
     * @param view
     */
    private void addKeyBordClickListener(View view) {
        if (view instanceof ViewGroup){
            //遍歷所有的子View設(shè)置事件
            for (int i=0;i<((ViewGroup) view).getChildCount();i++){
                View childV = ((ViewGroup) view).getChildAt(i);
                addKeyBordClickListener(childV);
            }
        }else {
            view.setOnClickListener(this);
        }
    }

    @Override
    public void onClick(View v) {
        if (v instanceof TextView){
            //強(qiáng)轉(zhuǎn)獲取鍵盤的數(shù)字
            String tx = ((TextView) v).getText().toString();
            if (keyBordBack==null)return;
            if ("刪除".equals(tx)){
                keyBordBack.delete();
            }else {
                keyBordBack.click(tx);
            }
        }
    }
}

五、結(jié)論
在畫框那里有點(diǎn)復(fù)雜,主要是算位置那里一定畫圖參考,明白計算的過程,只有動手才能明白內(nèi)在的流程。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容