我自己手头一直用的IOS系统,写这个密码框的时候功能方面也参考了一个下苹果的屏幕解锁。这个密码框也是修修改改两三天才算完善,效果虽然实现了,但很多细节地方还是不太明白,还希望高人指点。
1.功能介绍及效果图
做密码框的时候考虑了两个方案,一个方案是用6个EditText,另一个方案则是在EditText上画5条线。因为我基本没接触过draw部分的代码,对语法都不了解,所以果断选择了第一种。接下来考虑密码框需要实现的功能和用户体验的问题。
功能1:输入密码删除密码流畅
功能2:用户点击任意密码框焦点在正确的位置
功能3:输入的密码直接显示为圆点
2.源码
- package com.example.passwordview;
- import java.util.ArrayList;
- import java.util.List;
- import android.app.Activity;
- import android.content.Context;
- import android.os.Bundle;
- import android.os.Handler;
- import android.text.Editable;
- import android.text.TextUtils;
- import android.text.TextWatcher;
- import android.util.Log;
- import android.view.KeyEvent;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.view.View.OnKeyListener;
- import android.view.inputmethod.InputMethodManager;
- import android.widget.Button;
- import android.widget.EditText;
- import android.widget.LinearLayout;
- import android.widget.Toast;
- public class MainActivity extends Activity implements TextWatcher{
- private EditText et_pwd1;
- private EditText et_pwd2;
- private EditText et_pwd3;
- private EditText et_pwd4;
- private EditText et_pwd5;
- private EditText et_pwd6;
- private List<EditText> et_group;
- private OnKeyListener onKeyListener;
- public int cursorPosition=0;
- private InputMethodManager imm;
- public Context context;
- private String[] password=new String[6];
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.httfund_enter_password);
- intiView();
- setListener();
- testcursorPosition();
- }
- public void intiView(){
- et_pwd1=(EditText)findViewById(R.id.et_pwd1);
- et_pwd2=(EditText)findViewById(R.id.et_pwd2);
- et_pwd3=(EditText)findViewById(R.id.et_pwd3);
- et_pwd4=(EditText)findViewById(R.id.et_pwd4);
- et_pwd5=(EditText)findViewById(R.id.et_pwd5);
- et_pwd6=(EditText)findViewById(R.id.et_pwd6);
- et_group=new ArrayList<EditText>();
- et_group.add(et_pwd1);
- et_group.add(et_pwd2);
- et_group.add(et_pwd3);
- et_group.add(et_pwd4);
- et_group.add(et_pwd5);
- et_group.add(et_pwd6);
- }
- /**
- * 输入判断,光标永远在第一个空白格
- */
- public void testcursorPosition(){
- cursorPosition=0;
- for(EditText editView : et_group){
- editView.setFocusableInTouchMode(true);
- }
- for(EditText et : et_group){
- if(!TextUtils.isEmpty(et.getText().toString())){
- ++cursorPosition;
- }else{
- break;
- }
- }
- if(cursorPosition==6){
- cursorPosition=5;
- }
- EditText et=et_group.get(cursorPosition);
- et.requestFocus();
- et.setSelection(et.getText().toString().length());
- imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
- if(imm.isActive()){
- imm.toggleSoftInput(0, InputMethodManager.HIDE_IMPLICIT_ONLY);
- }
- setEditViewEnable();
- }
- /**
- * 设置EditView的Enable属性
- * 仅将包含光标的EditView设置为true
- */
- public void setEditViewEnable(){
- int i=0;
- for(EditText et : et_group){
- if(i++!=cursorPosition){
- et.setFocusableInTouchMode(false);
- }
- }
- }
- /**
- * 事件监听
- */
- public void setListener(){
- /**
- * EditView 监听软键盘,监听删除键
- */
- onKeyListener=new OnKeyListener() {
- @Override
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- // TODO Auto-generated method stub
- if(keyCode==KeyEvent.KEYCODE_DEL&&event.getAction()==KeyEvent.ACTION_DOWN){
- testcursorPosition();
- Log.d("pwd", "删除密码"+Integer.toString(cursorPosition));
- if(cursorPosition!=6&&cursorPosition!=0){
- EditText et=et_group.get(cursorPosition);
- if(TextUtils.isEmpty(et.getText().toString())){
- et_group.get(cursorPosition-1).setText("");
- }
- }
- }
- return false;
- }
- };
- /**
- * EditView的点击事件
- */
- OnClickListener clickListener=new OnClickListener() {
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- testcursorPosition();
- }
- };
- for(EditText et : et_group){
- et.addTextChangedListener(this);
- et.setOnKeyListener(onKeyListener);
- et.setOnClickListener(clickListener);
- }
- }
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count,
- int after) {
- // TODO Auto-generated method stub
- }
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- // TODO Auto-generated method stub
- EditText et = et_group.get(cursorPosition);
- if(s.length()>1){
- s=s.toString().subSequence(0, 1);
- et.setText(s);
- et.setSelection(s.length());
- }
- if(!TextUtils.isEmpty(et.getText().toString())&&
- !et.getText().toString().equals("*")){
- password[cursorPosition]=et.getText().toString();
- et.setText("*");
- }else if(!et.getText().toString().equals("*")){
- password[cursorPosition]=et.getText().toString();
- }
- testcursorPosition();
- }
- @Override
- public void afterTextChanged(Editable s) {
- // TODO Auto-generated method stub
- }
- }
package com.example.passwordview;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.Toast;
public class MainActivity extends Activity implements TextWatcher{
private EditText et_pwd1;
private EditText et_pwd2;
private EditText et_pwd3;
private EditText et_pwd4;
private EditText et_pwd5;
private EditText et_pwd6;
private List<EditText> et_group;
private OnKeyListener onKeyListener;
public int cursorPosition=0;
private InputMethodManager imm;
public Context context;
private String[] password=new String[6];
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.httfund_enter_password);
intiView();
setListener();
testcursorPosition();
}
public void intiView(){
et_pwd1=(EditText)findViewById(R.id.et_pwd1);
et_pwd2=(EditText)findViewById(R.id.et_pwd2);
et_pwd3=(EditText)findViewById(R.id.et_pwd3);
et_pwd4=(EditText)findViewById(R.id.et_pwd4);
et_pwd5=(EditText)findViewById(R.id.et_pwd5);
et_pwd6=(EditText)findViewById(R.id.et_pwd6);
et_group=new ArrayList<EditText>();
et_group.add(et_pwd1);
et_group.add(et_pwd2);
et_group.add(et_pwd3);
et_group.add(et_pwd4);
et_group.add(et_pwd5);
et_group.add(et_pwd6);
}
/**
* 输入判断,光标永远在第一个空白格
*/
public void testcursorPosition(){
cursorPosition=0;
for(EditText editView : et_group){
editView.setFocusableInTouchMode(true);
}
for(EditText et : et_group){
if(!TextUtils.isEmpty(et.getText().toString())){
++cursorPosition;
}else{
break;
}
}
if(cursorPosition==6){
cursorPosition=5;
}
EditText et=et_group.get(cursorPosition);
et.requestFocus();
et.setSelection(et.getText().toString().length());
imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
if(imm.isActive()){
imm.toggleSoftInput(0, InputMethodManager.HIDE_IMPLICIT_ONLY);
}
setEditViewEnable();
}
/**
* 设置EditView的Enable属性
* 仅将包含光标的EditView设置为true
*/
public void setEditViewEnable(){
int i=0;
for(EditText et : et_group){
if(i++!=cursorPosition){
et.setFocusableInTouchMode(false);
}
}
}
/**
* 事件监听
*/
public void setListener(){
/**
* EditView 监听软键盘,监听删除键
*/
onKeyListener=new OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
if(keyCode==KeyEvent.KEYCODE_DEL&&event.getAction()==KeyEvent.ACTION_DOWN){
testcursorPosition();
Log.d("pwd", "删除密码"+Integer.toString(cursorPosition));
if(cursorPosition!=6&&cursorPosition!=0){
EditText et=et_group.get(cursorPosition);
if(TextUtils.isEmpty(et.getText().toString())){
et_group.get(cursorPosition-1).setText("");
}
}
}
return false;
}
};
/**
* EditView的点击事件
*/
OnClickListener clickListener=new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
testcursorPosition();
}
};
for(EditText et : et_group){
et.addTextChangedListener(this);
et.setOnKeyListener(onKeyListener);
et.setOnClickListener(clickListener);
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// TODO Auto-generated method stub
EditText et = et_group.get(cursorPosition);
if(s.length()>1){
s=s.toString().subSequence(0, 1);
et.setText(s);
et.setSelection(s.length());
}
if(!TextUtils.isEmpty(et.getText().toString())&&
!et.getText().toString().equals("*")){
password[cursorPosition]=et.getText().toString();
et.setText("*");
}else if(!et.getText().toString().equals("*")){
password[cursorPosition]=et.getText().toString();
}
testcursorPosition();
}
@Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
}
}
代码并不难,testcursorPosition用来检测光标应该在的正确位置。InputMethodManager用于显示软键盘,设置成HIDE_IMPLICIT_ONLY唯一的一个问题就是可能弹出密码框的时候会自动弹出软键盘,这个软键盘在弹出后会弹回,但是解决了在输入密码的时候软键盘弹出弹回影响用户体验的问题。在onTextChanged对EditText的长度进行了限制。把数字显示成“*”
整个逻辑跑通之后最大的问题就是输入密码变圆点,如果不直接设置成*号,密码框变成圆点的过程会很长,而且时间不定,体验非常差。