自定义V_04_InputPassword

一、效果


密码输入.png

二、描述
实现一个密码输入框,继承自Editext免去了位置的测量,将这个放入一个Dialog中,可以实现一个自定义的输入密码键盘
三、分析
1.首先要画好背景框
2.在画里面的竖线
1)每一次:从上一次的竖线宽度+(本次条目的宽度 )+ 本次边框的宽度
int startX = bgBorderSize + (i + 1) * itemWidth + i * bgBorderSize;


表格.png

3.画圆点
1)其实就是用的Canvas画View替换了系统的draw(),如果这里不注释 super.onDraw(canvas);在最开始的起点那里长按依然可以选中那些文字,当然这不是重点;

2)获取文字长度计算圆点个数:画的位置相当于一个 错位 的感觉,就是第一次是框的宽度的一半,下一个圆点距离就是上次位置加一个框的宽度
圆点.png

3)键盘就简单多了,继承自LinearLayout引入布局,主要是把子View设置监听事件,然后进行一个回调。

四、动手
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);
    //屏蔽系统键盘
    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 {
  //密码个数
  private int inputCount;
  //点的半径大小
  private int pointSizePi;
  //点的颜色
  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;
  //设置最大输入个数
  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); //把用户输入的内容设置为透明
      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);
  }


  /**
   * 绘制框中心的点
   */
  private void drawPWD(Canvas canvas) {
      //实心圆
      //输入的个数
      int pwdLength = getText().toString().length();
      for (int i = 0; i < pwdLength; i++) {
          //核心:竖线宽度 + 宽度的一半
          //      竖线宽度      + 项的宽度* i  +  i+竖线条数       + 项宽度一半
          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) {
      //总的宽度 - (数量减-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();
      //抗据齿
      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);
    }

    /**
     * 递归设置子View事件
     * @param view
     */
    private void addKeyBordClickListener(View view) {
        if (view instanceof ViewGroup){
            //遍历所有的子View设置事件
            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){
            //强转获取键盘的数字
            String tx = ((TextView) v).getText().toString();
            if (keyBordBack==null)return;
            if ("删除".equals(tx)){
                keyBordBack.delete();
            }else {
                keyBordBack.click(tx);
            }
        }
    }
}

五、结论
在画框那里有点复杂,主要是算位置那里一定画图参考,明白计算的过程,只有动手才能明白内在的流程。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容