最近在做项目的时候,有这样一个需求,要实现取件码的输入,效果图如下:
看到这个图,立马想到,这个类似于支付宝、微信的密码输入框。
实现方法总结:
一、直接写四个EditText,然后对其设置maxLength为1。
1 2 3 4 5 6 7 8
| <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)当删除的时候,使其使其失去焦点,同时让前一个获取焦点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| 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文件中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| <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)代码中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| 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) { 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获取焦点,再设置最大长度。设置字体颜色为透明,隐藏光标。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 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)设置背景,实现四个显示框,以及中间间距。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| private void drawBackground(Canvas canvas) { contentWidth = (getWidth() - spacingWidth*(maxLength-1))/maxLength; for (int i = 0;i < maxLength;i++){ mPaint.setColor(contentColor); Rect rect = new Rect(i*(spacingWidth + contentWidth),0,i*(spacingWidth + contentWidth) + contentWidth,getHeight()); canvas.drawRect(rect,mPaint);
if (i != maxLength -1){ mPaint.setColor(spacingColor); Rect spacingRect = new Rect(i*(spacingWidth + contentWidth) + contentWidth,0,(i+1)*(spacingWidth + contentWidth),getHeight()); canvas.drawRect(spacingRect,mPaint); } } }
|
6)绘制文字。
1 2 3 4 5 6 7
| 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); }
|
这种方式和第二种相比,缺点是需要计算文本显示区域,间距显示区域。优点是扩展性好一点。