您的位置:首页 > 移动开发 > Android开发

仿支付宝密码输入以及细节总结

2017-11-29 10:43 483 查看
网上已经有很多现成的轮子了,虽然说重复造轮子不好,但是对于初学者还是多写多实现,了解原理最重要。

首先看下效果:



需求

主要有以下几个点:

密码输入框由几个方框组成

当在软键盘上输入密码时,在对应的方框内会用圆点作为代替

当输入完成以后,自动进行验证和执行操作

点击密码框时自动弹出软键盘,并且软键盘是数字键盘,输入其他字符无效,当焦点变化时自动隐藏软键盘

支持删除操作

分析

有三种实现方式:

在一个
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();
}
}


总结一下,其实看上去挺简单的,但是对于新手来说操作起来还是有很多细节的,不多说,继续学习!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android