最近项目要实现如下的密码框样式(实现效果图如下)
先看单个EditText xml配置的属性:
只允许最多输入一个字符
<EditText
android:id="@+id/EditText01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:layout_weight="1"
android:maxLength="1"
android:inputType="numberPassword" />
控件初始化:
private void initView() {
editText1 = (EditText) findViewById(R.id.EditText01);
editText2 = (EditText) findViewById(R.id.EditText02);
editText3 = (EditText) findViewById(R.id.EditText03);
editText4 = (EditText) findViewById(R.id.EditText04);
editText5 = (EditText) findViewById(R.id.EditText05);
editText6 = (EditText) findViewById(R.id.EditText06);
//添加TAG 用于textChangeListener的标示
editText1.setTag(1);
editText2.setTag(2);
editText3.setTag(3);
editText4.setTag(4);
editText5.setTag(5);
editText6.setTag(6);
//添加 内容change listener :输入焦点后移 + 密码验证
editText1.addTextChangedListener(new MyTextChangeWatcher(1));
editText2.addTextChangedListener(new MyTextChangeWatcher(2));
editText3.addTextChangedListener(new MyTextChangeWatcher(3));
editText4.addTextChangedListener(new MyTextChangeWatcher(4));
editText5.addTextChangedListener(new MyTextChangeWatcher(5));
//editText6.addTextChangedListener(new MyTextChangeWatcher(6));
//del 监听,输入焦点前移
editText2.setOnKeyListener(keyListener);
editText3.setOnKeyListener(keyListener);
editText4.setOnKeyListener(keyListener);
editText5.setOnKeyListener(keyListener);
editText6.setOnKeyListener(keyListener);
// test();
// testClear();
}
用TextWatcher 进行 焦点后移处理:
每个EditText 有内容输入后,通过index把焦点后移一位,然后发送命令,扫描输入框是否都有输入,若都有,则判断密码的有效性。
class MyTextChangeWatcher implements TextWatcher {
//标示 绑定的EditText
private int index;
public MyTextChangeWatcher(int index) {
super();
this.index = index;
}
@Override
public void afterTextChanged(Editable s) {
DEBUG("afterTextChanged --s=" + s.toString());
if (s != null && s.length() == 1) {
if (index < 6) {// 焦点后移
getEditTextFromIndex(index).clearFocus();
getEditTextFromIndex(index + 1).requestFocusFromTouch();
} else {
// TODO 判断
// handler.sendEmptyMessage(1);
}
setFlag(false, index);// 对应标志位 置 1
//有内容输入,判断密码是否输入OK
handler.sendEmptyMessage(1);
} else {
//清除 对应 标识位
setFlag(true, index);
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
DEBUG("beforeTextChanged --s=" + s.toString());
}
@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
DEBUG("onTextChanged --s=" + s.toString());
}
}
扫描 输入框与密码判断:
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
//标志位 方法判断
if (!checkHasNull()) {// 都 已输入
if (judgePassWord()) {
DEBUG("密码正确");
} else {
DEBUG("密码错误");
}
} else {
DEBUG("有输入框未输入值");
}
//扫描输入框,是否全都已输入
if (scanEditTextHasNull()) {
return;
}
//判断 密码有效性
if (judgePassWord()) {
startActivity(new Intent(MainActivity.this, TMainActivity.class));
} else {
Toast.makeText(MainActivity.this, "密码输入错误", Toast.LENGTH_SHORT)
.show();
}
};
};
/**
* 扫描EditText 是否存在没有输入的
* @return true 有空, false 都填写值了
*/
private boolean scanEditTextHasNull() {
for (int i = 0; i < 6; i++) {
if (getEditTextFromIndex(i + 1).getText() == null
|| getEditTextFromIndex(i + 1).getText().length() != 1) {
//有一个为空,立即返回
return true;
}
}
return false;
}
单个字符,循环对比。
/**
* 判断密码是否正确
*/
private boolean judgePassWord() {
for (int i = 0; i < 6; i++) {
DEBUG("String.valueOf(pw.charAt(0)=" + String.valueOf(pw.charAt(0)));
DEBUG("getEditTextFromIndex(i+1).getText()="
+ getEditTextFromIndex(i + 1).getText());
if (!String.valueOf(pw.charAt(0)).equals(
getEditTextFromIndex(i + 1).getText().toString())) {
return false;// 有一个密码不符合,就立即跳出
}
}
return true;
}
用OnKeyListener 焦点前移:
当前EditText 内容为空,并且del键 按下,焦点前移
/**
* 监听删除键 前移焦点
*/
private OnKeyListener keyListener = new OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
DEBUG(" keyCode=" + keyCode + " event=" + event);
DEBUG(((EditText) v).getText().toString());
if ((((EditText) v).getText().toString() == null || ((EditText) v)
.getText().toString().isEmpty())
&& keyCode == KeyEvent.KEYCODE_DEL
&& event.getAction() == KeyEvent.ACTION_DOWN) {
// 该EditText的 内容已为空,并且 del 键按下
v.clearFocus();// 清除该控件焦点
// 将焦点给到前面一个EditText
EditText editText = getEditTextFromIndex(Integer
.parseInt(String.valueOf(v.getTag())) - 1);
// editText.requestFocus(); //也可以
editText.requestFocusFromTouch();
}
return false;
}
};
TAG 与EditText 映射
private EditText getEditTextFromIndex(int index) {
switch (index) {
case 1 :
return editText1;
case 2 :
return editText2;
case 3 :
return editText3;
case 4 :
return editText4;
case 5 :
return editText5;
case 6 :
return editText6;
default :
break;
}
return null;
}
关于密码框是否有输入值,除了循环扫描外,还用个人觉得更轻量级一些的方法做了另外一种实现:通过标识位0 和1 来判断,指定位置对应的EditText是否有输入值 :1,有。
设置 指定标志位
/**
* 对指定位 进行位操作
*
* @param isNull
* true:当前值为null ,清零。false:有值,该标志位 给1.
* @param index
* 标志位index
*/
private void setFlag(boolean isNull, int index) {
// 得到 唯一一个 1的二进制数 00001000
byte b = (byte) (1 << (index - 1));
if (isNull) {// 指定 位 清零
b = (byte) ~b; // 11110111
flag = (byte) (flag & b);
} else {// 制定位 赋值 1
flag = (byte) (flag | b);
}
}
判断是否都已输入值
// 判断 是否有未输入的
private boolean checkHasNull() {
// 00111111
if (flag == 0x3f) {
return false;
}
return true;
}
标识位 具体变化设置,参见 上面的MyTextChangeWatcher类中的afterTextChanged方法。
代码下载路径: