自定义控件

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

2017-06-29  本文已影响3343人  独孤行者1992
最近在做项目的时候,有这样一个需求,要实现取件码的输入,效果图如下:
要实现效果

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

实现方法总结:
一、直接写四个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);
        }

这种方式和第二种相比,缺点是需要计算文本显示区域,间距显示区域。优点是扩展性好一点。
上一篇下一篇

猜你喜欢

热点阅读