最近在做项目的时候,有这样一个需求,要实现取件码的输入,效果图如下:
看到这个图,立马想到,这个类似于支付宝、微信的密码输入框。
实现方法总结:
一、直接写四个EditText,然后对其设置maxLength为1。
在代码中,对其设置监听事件,事件主要功能如下:
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文件中:
.......
android:cursorVisible="false"/>
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);
}