仿支付宝密码输入以及细节总结
2017-11-29 10:43
483 查看
网上已经有很多现成的轮子了,虽然说重复造轮子不好,但是对于初学者还是多写多实现,了解原理最重要。
首先看下效果:
密码输入框由几个方框组成
当在软键盘上输入密码时,在对应的方框内会用圆点作为代替
当输入完成以后,自动进行验证和执行操作
点击密码框时自动弹出软键盘,并且软键盘是数字键盘,输入其他字符无效,当焦点变化时自动隐藏软键盘
支持删除操作
在一个
继承自
直接继承自
对于方框本文采用先绘制整体的外围矩形,再通过循环绘制每一格的分割线。
对于圆点,可以动态绘制,通过监听输入数据,获取总的数据的大小,从而重绘。
对于删除和软键盘的弹入弹出,在下面边附代码边解释。
首先在
在
此外还有一个循环绘制圆点的方法,通过获取数据的大小动态通知重绘:
方框的绘制很简单,主要就是注意视图大小的获取是在
此外也可以在
也可以在
也可以在java代码中设置
设置好了以后就可以获取触摸事件弹起软键盘了:
上面的
这里有两种方法,一种是在根布局中设置点击事件监听器,如果点击事件发生的
第二种方法是通过
注意此处用
这里的
总结一下,其实看上去挺简单的,但是对于新手来说操作起来还是有很多细节的,不多说,继续学习!
首先看下效果:
需求
主要有以下几个点:密码输入框由几个方框组成
当在软键盘上输入密码时,在对应的方框内会用圆点作为代替
当输入完成以后,自动进行验证和执行操作
点击密码框时自动弹出软键盘,并且软键盘是数字键盘,输入其他字符无效,当焦点变化时自动隐藏软键盘
支持删除操作
分析
有三种实现方式:在一个
LinearLayout中布局几个方框,每个方框都是可编辑的,再对输入监听
继承自
EditText,绘制方框并且去除下划线等,对输入监听
直接继承自
View,全定制,本文采用这种方法
对于方框本文采用先绘制整体的外围矩形,再通过循环绘制每一格的分割线。
对于圆点,可以动态绘制,通过监听输入数据,获取总的数据的大小,从而重绘。
对于删除和软键盘的弹入弹出,在下面边附代码边解释。
代码详解
方框的绘制
由于View中的方法很多都是返回的px,所以在View中去设定方框的长宽以及分隔线的大小并不好,建议在格式xml文件中定义,然后在布局xml中设置并赋值,在View的构造函数中导入,这样的设置耦合度小,也易于控制。首先在
View的
onSizeChanged()方法中获取视图的宽高,设置方框的大小:
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); textHeight = h; textWidth = w; rectF.set(0, 0, textWidth, textHeight); }
在
onDraw方法中绘制方框和分隔线:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawRoundRect(rectF, rx, ry, textRectPaint); for (int i=1; i<numberCount; i++){ canvas.drawLine(i*textWidth/numberCount, 0, i*textWidth/numberCount, textHeight, textRectPaint); } drawCircle(canvas); }
此外还有一个循环绘制圆点的方法,通过获取数据的大小动态通知重绘:
private void drawCircle(Canvas canvas){ if (array.size()==0) { return; } for (int i=1; i<=array.size(); i++){ canvas.drawCircle((float)((i-0.5)*textWidth/numberCount), textHeight/2, 20, pointPaint); } }
方框的绘制很简单,主要就是注意视图大小的获取是在
onSizeChanged方法中,该方法在视图布局变化时回调,在
View的
onMeasure和
layout方法执行后会回调。
此外也可以在
layout方法中通过下面的方式获取,注意必须在
onMeasure方法之后调用
textWidth = getMeasuredWidth(); textHeight = getMeasuredHeight();
也可以在
layout方法之后通过
getWidth()和
getHeight()方法获取视图的长宽,具体原理见我的另一篇文章:《android中各种height和width总结》
软键盘的触摸弹起和失去焦点隐藏
首先必须将该View设置为可获得焦点并且在触摸模式下也是可以获得焦点的,触摸模式下获得焦点意味着在支持键盘输入并且软键盘输入的时候该
View仍然持有焦点,想要能够获取用户输入必须设置此属性,在布局xml文件中添加如下两行:
android:focusable="true" android:focusableInTouchMode="true"
也可以在java代码中设置
view.requestFocus()和
view.setFocusableInTouchMode(true),优先级比xml中要高。
设置好了以后就可以获取触摸事件弹起软键盘了:
@Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { input.showSoftInput(this, InputMethodManager.SHOW_FORCED); return true; } return super.onTouchEvent(event); }
input的初始化如下:
input = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
上面的
SHOW_FORCED意思是强制弹出软键盘。下面看失去焦点后如何隐藏软键盘。
这里有两种方法,一种是在根布局中设置点击事件监听器,如果点击事件发生的
View为根布局,就隐藏软键盘,这种适合控件很少且不需要获取单击事件的情况,具体代码如下:
@Override public void onClick(View v) { switch (v.getId()) { case R.id.traceroute_rootview: InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(v.getWindowToken(), 0); break; } }
第二种方法是通过
Activity的事件分发机制,获取当前焦点所在的
View,也就是弹出软键盘所在的
View,判断触摸事件是否发生在
View的范围以内,否就不处理,是就收起软键盘。代码如下:
@Override public boolean dispatchTouchEvent(MotionEvent ev) { if (ev.getAction()==MotionEvent.ACTION_DOWN) { touchView = getCurrentFocus(); if (isShouldHideInput(touchView, ev)) { input = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); if (input!=null) { input.hideSoftInputFromWindow(touchView.getWindowToken(), 0); } } } return super.dispatchTouchEvent(ev); } private boolean isShouldHideInput(View view, MotionEvent event){ if (view!=null) { int[] locations = new int[2]; view.getLocationInWindow(locations); int left = locations[0]; int top = locations[1]; int right = left+view.getWidth(); int bottom = top+view.getHeight(); if (event.getRawX()>=left && event.getRawX()<=right && event.getRawY()>=top && event.getRawY()<=bottom) { return false; } return true; } return false; }
注意此处用
getRawX(),因为前面是获取当前
Window下的坐标,所以不是相对于父容器的坐标。执行完以后调用父类的方法,继续分发事件,经验证不影响其他控件的触摸事件。
限定弹出键盘的类型
为了更好的用户体验,弹出的键盘需要是数字键盘,避免用户手动切换,代码如下:@Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) { outAttrs.inputType = InputType.TYPE_CLASS_NUMBER; outAttrs.imeOptions = EditorInfo.IME_ACTION_DONE; return super.onCreateInputConnection(outAttrs); }
这里的
inputType规定了弹出键盘是
NUMBER类型。具体见博客:Android控件TextView的实现原理分析
键盘输入
弹出键盘以后,我们就可以输入密码了,但是我们还需要进行判断,对不是数字的输入不作响应。每次输入一个数字,就将此数字加入到List中,一旦输入完以后自动进行验证和交易,这里我就用一个
Toast来代表验证过程了。删除可以通过监听删除键对List进行操作。具体监听是继承
View.OnKeyListener类重写
onKey方法。代码如下:
class MyOnKeyListener implements View.OnKeyListener{ @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN) { if (keyCode>=KeyEvent.KEYCODE_0 && keyCode<=KeyEvent.KEYCODE_9) { if (list.size()<numberCount) { list.add(keyCode-7); invalidate(); if (list.size()==numberCount) { ensureFinishInput(); //输入结束后收起键盘 input.hideSoftInputFromWindow(MyEditText.this.getWindowToken(), 0); } } return true; } if (keyCode==KeyEvent.KEYCODE_DEL) { if (list.size()!=0) { list.remove(list.size()-1); invalidate(); } return true; } } return false; } private void ensureFinishInput(){ StringBuffer sb = new StringBuffer(); sb.append(list.toString()); Toast.makeText(getContext(),sb.toString(),Toast.LENGTH_SHORT).show(); } }
总结一下,其实看上去挺简单的,但是对于新手来说操作起来还是有很多细节的,不多说,继续学习!
相关文章推荐
- suggestion开发小结以及对键盘事件的总结(针对中文输入法状态)
- C语言编程在Xcode中Scanf 输入跳过以及清空键盘缓冲区总结
- 安卓实现支付宝6位密码输入界面
- 总结三种Shell脚本编程中避免SFTP输入密码的方法
- 仿微信/支付宝的密码输入框效果 android
- iOS简单的密码输入组件XLPasswordView,UI类似支付宝
- 添加码云上的SSH公钥以及解决使用命令git pull/push 输入密码问题
- 封装仿支付宝密码输入效果
- 关于Linux登录不进去的原因总结(输入正确用户名和密码,屏幕老是回到登录界面)
- 关于各种输入输出流的二次理解总结 ,以及输入的三种方法总结。
- Android仿支付宝支付密码输入框
- 类似支付宝或微信支付输入密码
- 不输入密码ssh直接登录Linux主机的实践与总结
- Python 3.x 控制台输入密码的方法总结
- 只能游客登录以及ubuntu输入密码登录后继续回到登录界面
- 碰到一个基本输入输出流的问题,以及对于getline使用总结。
- 【总结】DateTime日期类型格式化显示(转)以及判断输入文本框是否符合日期格式
- Android仿支付宝密码输入效果封装
- 关于各种输入输出流的二次理解总结 ,以及输入的三种方法总结。