美文网首页自定义控件
Android实现验证码、密码输入框

Android实现验证码、密码输入框

作者: 独孤行者1992 | 来源:发表于2017-06-29 20:53 被阅读3343次
    最近在做项目的时候,有这样一个需求,要实现取件码的输入,效果图如下:
    要实现效果

    看到这个图,立马想到,这个类似于支付宝、微信的密码输入框。

    实现方法总结:
    一、直接写四个EditText,然后对其设置maxLength为1。
      <EditText
          android:id="@+id/et_inputPickupNum1"
          android:layout_width="40dp"
          android:layout_height="40dp"
          android:inputType="number"
          android:gravity="center"
          android:maxLength="1"
          android:background="#0000ff"/>
    
    在代码中,对其设置监听事件,事件主要功能如下:

    1)当有输入后,立马使其失去焦点,同时让下一个EditText获取焦点。
    2)当删除的时候,使其使其失去焦点,同时让前一个获取焦点。

            etPickupNum2.addTextChangedListener(new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                }
    
                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                    if (!TextUtils.isEmpty(s.toString().trim())){
                        etPickupNum2.clearFocus();
                        etPickupNum2.setFocusable(false);
                        etPickupNum3.setFocusable(true);
                        etPickupNum3.setFocusableInTouchMode(true);
                        etPickupNum3.requestFocus();
                    }else{
                        etPickupNum2.clearFocus();
                        etPickupNum1.setFocusable(true);
                        etPickupNum1.setFocusableInTouchMode(true);
                        etPickupNum1.requestFocus();
                    }
                }
    
                @Override
                public void afterTextChanged(Editable s) {
                }
            });
    
    不过,这种实现方式代码量大,可扩展性差。这种实现方式,还存在一个问题,就是删除一个后,光标跳到前一个去了,继续输入还得点一下EditText。
    二、在同一个布局容器中添加四个TextView,用于显示输入后的文字。同时在这个布局容器上边添加一个背景透明的、隐藏了光标、字体也是透明的EditText。在代码中,对EditText设置输入监听事件。

    1)xml文件中:

            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="40dp">
    
    
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:orientation="horizontal">
    
                    <TextView
                        android:id="@+id/tv_inputPickupNum1"
                        android:layout_width="40dp"
                        android:layout_height="40dp"
                        android:textColor="#ffffff"
                        android:background="#0000ff"/>
    
                    <View
                        android:layout_weight="1"
                        android:layout_width="0dp"
                        android:layout_height="match_parent"/>
    
                      .......
    
                </LinearLayout>
    
                <EditText
                    android:id="@+id/et_inputPickupNum"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:maxLength="4"
                    android:background="@android:color/transparent"
                    android:textColor="@android:color/transparent"
                    <!--cursorVisible设置为false,表示隐藏光标-->
                    android:cursorVisible="false"/>
            </RelativeLayout>
    

    2)代码中:

            etnum.addTextChangedListener(new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                }
    
                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                    //numList是一个存放四个TextView的集合
                    for (TextView tvNum:numList){
                       tvNum.setText("");
                    }
                    String str = s.toString().trim();
                    if (!TextUtils.isEmpty(str)){
                        for(int i = 0;i < str.length();i++){
                            numList.get(i).setText(str.substring(i,i+1));
                        }
                    }
                }
    
                @Override
                public void afterTextChanged(Editable s) {
                }
            });
    
    这种和第一种比较,就是不用考虑焦点的得失。
    三、自定义View。实现思路是:

    1) 定义内容背景颜色、间距、间距颜色、字体颜色等属性。
    2)在xml中设置这些属性值。
    3)写一个类继承EditText,获取上边属性值,并且实现输入事件监听。
    4)做全局配置:让该EditText获取焦点,再设置最大长度。设置字体颜色为透明,隐藏光标。

        private void initView() {
            setFocusable(true);
            setFocusableInTouchMode(true);
            this.setFilters(new InputFilter[]{new InputFilter.LengthFilter(maxLength)});
            this.setTextColor(Color.TRANSPARENT);
            this.setGravity(Gravity.CENTER_VERTICAL);
            if(mPaint == null){
                mPaint = new Paint();
            }
            mPaint.setTextSize(textSize);
            mPaint.setColor(spacingColor);
            if (mBound == null){
                mBound = new Rect();
            }
        }
    

    5)设置背景,实现四个显示框,以及中间间距。

    private void drawBackground(Canvas canvas) {
             //contentWidth为显示框宽度,spacingWidth为间距宽度,maxLength为最大长度
            contentWidth = (getWidth() - spacingWidth*(maxLength-1))/maxLength;
            for (int i = 0;i < maxLength;i++){
                //contentColor为文本框背景颜色
                mPaint.setColor(contentColor);
                Rect rect = new Rect(i*(spacingWidth + contentWidth),0,i*(spacingWidth + contentWidth) + contentWidth,getHeight());
                canvas.drawRect(rect,mPaint);
    
                if (i != maxLength -1){
                    //spacingColor为间距的背景颜色
                    mPaint.setColor(spacingColor);
                    Rect spacingRect = new Rect(i*(spacingWidth + contentWidth) + contentWidth,0,(i+1)*(spacingWidth + contentWidth),getHeight());
                    canvas.drawRect(spacingRect,mPaint);
                }
            }
        }
    

    6)绘制文字。

            //content用于记录当前输入字符串
            mPaint.getTextBounds(content,0,content.length(),mBound);
            mPaint.setColor(textColor);
            for (int i = 0;i < content.length();i++){
                canvas.drawText(content.substring(i,i+1),i*(spacingWidth + contentWidth),getHeight()/2 + mBound.height()/2,mPaint);
            }
    
    
    这种方式和第二种相比,缺点是需要计算文本显示区域,间距显示区域。优点是扩展性好一点。

    相关文章

      网友评论

        本文标题:Android实现验证码、密码输入框

        本文链接:https://www.haomeiwen.com/subject/dajvcxtx.html