开源项目GridPasswordView使用和源码分析
来源:互联网 发布:视频打马赛克软件 编辑:程序博客网 时间:2024/05/01 21:59
GridPasswordView是一个密码输入视图,类似于微信或支付宝的支付密码视图。可以设置文字颜色和大小、分割线颜色、密码的长度。
项目地址:
https://github.com/Jungerr/GridPasswordView
其中包含项目源码和示例代码。
运行效果图:
一、项目使用
(1).在工程的build.gradle文件中添加项目引用。
dependencies { compile 'com.jungly:gridPasswordView:0.3'}(2).在布局中添加GridPasswordView。
<com.jungly.gridpasswordview.GridPasswordView android:id="@+id/gridpassword" android:layout_width="match_parent" android:layout_height="50dp" />(3).添加Java代码。
GridPasswordView gridPasswordView = findViewById(R.id.gridpassword);gridPasswordView.setOnPasswordChangedListener(new GridPasswordView.OnPasswordChangedListener() { @Override public void onTextChanged(String psw) { // add your code here } @Override public void onInputFinish(String psw) { // add your code here }});
二、源码分析
实现原理:
整个网格密码输入框最外层是一个水平方向的LinearLayout,内部包括显示密码的View和垂直分隔线View。而多个显示密码的View中,第一个位置放置的是EditText,其余均为TextView。如图所示。
当LinearLayout被点击时,让EditText获取焦点并弹出软键盘。定义一个String类型数组保存已输入的密码,当监听到EditText有新的字符输入时,截取下来保存到数组中,并保持EditText中始终只存在一个字符。每当监听到EditText的退格键时,删除String数组的最后一条数据。最后遍历String数组得到的就是用户输入的密码。
代码核心部分包括视图的添加、字符输入的监听和退格键的监听。
(1).初始化视图
在构造方法中,完成View的初始化。包括强制设置方向为水平,添加一个EditText和多个TextView以及之间的分割线。由于EditText和多个TextView的layout_width=0且layout_weight=1,所以会均分宽度。
public class GridPasswordView extends LinearLayout { private String[] mPasswordArr; private TextView[] mViewArr; public GridPasswordView(Context context) { super(context);mPasswordArr = new String[mPasswordLength]; mViewArr = new TextView[mPasswordLength]; initViews(context); } private void initViews(Context context) { super.setBackgroundDrawable(mOuterLineDrawable); setShowDividers(SHOW_DIVIDER_NONE); // 设置方向为水平 setOrientation(HORIZONTAL); mTransformationMethod = new CustomPasswordTransformationMethod(mPasswordTransformation); inflaterViews(context); } // 添加视图操作 private void inflaterViews(Context context) { // 布局gridpasswordview中只有一个EditText,添加到当前视图 LayoutInflater inflater = LayoutInflater.from(context); inflater.inflate(R.layout.gridpasswordview, this); mInputView = (ImeDelBugFixedEditText) findViewById(R.id.inputView); mInputView.setMaxEms(mPasswordLength);// 添加监听 mInputView.addTextChangedListener(textWatcher);// 添加监听 mInputView.setDelKeyEventListener(onDelKeyEventListener); setCustomAttr(mInputView); // 索引0是EditText mViewArr[0] = mInputView; // 索引1~mPasswordLength是TextView int index = 1; while (index < mPasswordLength) { // 调用addView()添加分割线 View dividerView = inflater.inflate(R.layout.divider, null); LayoutParams dividerParams = new LayoutParams(mLineWidth, LayoutParams.MATCH_PARENT); dividerView.setBackgroundDrawable(mLineDrawable); addView(dividerView, dividerParams); // 调用addView()添加文本 TextView textView = (TextView) inflater.inflate(R.layout.textview, null); setCustomAttr(textView); LayoutParams textViewParams = new LayoutParams(0, LayoutParams.MATCH_PARENT, 1f); addView(textView, textViewParams); mViewArr[index] = textView; index++; } // 设置点击事件 setOnClickListener(mOnClickListener); }}
(2).弹出软键盘
当LinearLayout被点击时,触发mOnClickListener。使EditText强制获取焦点,弹出键盘。
private OnClickListener mOnClickListener = new OnClickListener() { @Override public void onClick(View v) { forceInputViewGetFocus(); }};// EditText强制获取焦点,弹出键盘private void forceInputViewGetFocus() { mInputView.setFocusable(true); mInputView.setFocusableInTouchMode(true); mInputView.requestFocus(); InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); imm.showSoftInput(mInputView, InputMethodManager.SHOW_IMPLICIT);}
(3).监听字符输入
使用TextWatcher监听EditText的字符输入。关键点在于使用数组保存每次输入的密码,和维持EditText内始终只显示首个密码字符。
private TextWatcher textWatcher = 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 (s == null) { return; } String newStr = s.toString(); if (newStr.length() == 1) {// 初次输入字符,赋值给索引0 mPasswordArr[0] = newStr; notifyTextChanged(); } else if (newStr.length() == 2) {// 非首次输入字符 // 截取第2个字符 String newNum = newStr.substring(1); for (int i = 0; i < mPasswordArr.length; i++) { if (mPasswordArr[i] == null) { // 赋值给数组mPasswordArr,mPasswordArr中存储的就是最终的密码 mPasswordArr[i] = newNum; // 给TextView设值 mViewArr[i].setText(newNum); // 通知密码发生改变 notifyTextChanged(); break; } } // 上述逻辑执行完毕后,把索引0的字符设置给mInputView // 这样,之后再输入内容时,newStr.length()始终等于2。mInputView的内容长度始终等于1 mInputView.removeTextChangedListener(this); mInputView.setText(mPasswordArr[0]); if (mInputView.getText().length() >= 1) { mInputView.setSelection(1); } mInputView.addTextChangedListener(this); } } @Override public void afterTextChanged(Editable s) { }};
(4).监听退格键
当监听到EditText内触发退格键时,删除mPasswordArr数组内最后一个字符。
private ImeDelBugFixedEditText.OnDelKeyEventListener onDelKeyEventListener = new ImeDelBugFixedEditText .OnDelKeyEventListener() { @Override public void onDeleteClick() { for (int i = mPasswordArr.length - 1; i >= 0; i--) { // 找到已输入的最后一个字符,将其置为null if (mPasswordArr[i] != null) { mPasswordArr[i] = null; mViewArr[i].setText(null); notifyTextChanged(); break; } else { mViewArr[i].setText(null); } } }};
关键在于EditText对退格键的监听。在有的软键盘中,OnKeyListener无法监听到键盘的退格键KeyEvent.KEYCODE_DEL事件,在stackoverflow中已经有人给出了解决方法:
http://stackoverflow.com/questions/4886858/android-edittext-deletebackspace-key-event
EditText被重写后的核心代码:
public class ImeDelBugFixedEditText extends EditText { private OnDelKeyEventListener delKeyEventListener; // ...... // 键盘弹出时被调用 @Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) { return new ZanyInputConnection(super.onCreateInputConnection(outAttrs), true); } private class ZanyInputConnection extends InputConnectionWrapper { public ZanyInputConnection(InputConnection target, boolean mutable) { super(target, mutable); } // 将KeyEvent.KEYCODE_DEL事件回调出去 @Override public boolean sendKeyEvent(KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode() == KeyEvent.KEYCODE_DEL) { if (delKeyEventListener != null) { delKeyEventListener.onDeleteClick(); return true; } } return super.sendKeyEvent(event); } // deleteSurroundingText():删除字符,区间:当前光标前beforeLength个长度,当前光标后afterLength个长度 // beforeLength == 1 && afterLength == 0表示向前删除一个字符,可视为KeyEvent.KEYCODE_DEL @Override public boolean deleteSurroundingText(int beforeLength, int afterLength) { if (beforeLength == 1 && afterLength == 0) { return sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL)) && sendKeyEvent(new KeyEvent (KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL)); } return super.deleteSurroundingText(beforeLength, afterLength); } } public void setDelKeyEventListener(OnDelKeyEventListener delKeyEventListener) { this.delKeyEventListener = delKeyEventListener; } public interface OnDelKeyEventListener { void onDeleteClick(); }}
0 0
- 开源项目GridPasswordView使用和源码分析
- 开源项目ExpandableTextView使用和源码分析
- 开源项目android-process-button使用和源码分析
- 开源项目GridViewWithHeaderAndFooter使用和源码分析
- 【Android开源项目分析】自定义圆形头像CircleImageView的使用和源码分析
- 【Android开源项目分析】TAB导航栏PagerSlidingTabStrip的使用和源码分析
- 【Android开源项目分析】自定义圆形头像CircleImageView的使用和源码分析
- 【Android开源项目分析】自定义圆形头像CircleImageView的使用和源码分析
- 二维码识别开源项目zxing的使用和源码分析
- 二维码识别开源项目zxing的使用和源码分析
- Android开源项目和应用源码分析
- Android开源项目和应用源码分析
- BT开源项目Snark源码分析
- 开源项目之EventBus 源码分析
- 开源项目ViewPagerIndicator源码分析
- 开源项目ToggleButton源码分析
- 开源项目- Lottie 源码分析
- ThreadLocal使用和源码分析
- 外网访问mysql视图数据
- Jquery在手机上双击事件的实现
- [美剧赏析] 权力的游戏<Game of Thrones>完全赏析 (19-20)
- Android中AsyncTask的使用
- ACM解题总结——HihoCoder1200 (微软笔试题)
- 开源项目GridPasswordView使用和源码分析
- Android整点报时
- mysql数据库报错:InnoDB: Operating system error number 13 in a file operation
- codeforces B. Cells Not Under Attack (数学)
- NOIP2005提高组——谁拿了最多的奖学金(scholar)
- AndroidStudio中文方块问题
- Jgroups初步讲解
- Redis3.0中redis.config的一些笔记
- java.net.ConnectException: Connection refused: connect 解决