安卓/Android 模仿支付宝/微信 支付密码输入框的自定义View
2017-07-12 10:26
881 查看
类似这个密码输入框相信在博客上已经不少了,但是我稍微看了一下,大都是通过XML布局,然后组合成的一个自定义View。但是我想只用一个java文件,拿来就用该怎么办呢?
那就需要自己画出来了。水平有限,这里提供我自己自定义的一个过程,哪里不好,大家提提意见。
先上个效果图预览吧,我这里只是实现了那个框,具体输入布局大家可以在xml随意定义。
使用起来还是比较方便的,主要开放有四个方法和一个输入完成的回调接口。
这几个方法下面会介绍。
实现过程
这个密码输入框整体是一个输入框,每个密码之间有一根竖线间隔,每输入一个密码,就绘制一个屏蔽图案(一般是圆形小点)。
那么我们需要:
1.绘制外部的输入框
2.根据密码个数绘制间隔的竖线
3.根据用户输入的密码个数绘制屏蔽图
大概流程就这样,具体每一部分代码就不贴出来了,我直接贴这个文件的代码吧
之前说的开放四个方法分别就是:输入一个密码、删除一个密码、清空输入、获取当前输入的所有密码这四个。监听就是用户输入所有密码后回调。
总体来说,能够自定义的属性还是很多的,但是我没有开放出方法,也没有定义xml属性,如果需要,大家稍作修改即可。
大家看我的全局变量的定义就知道能够自动义那些内容,包括最大输入的密码个数;外框线条大小、颜色、圆角,分割线大小、颜色、距离外框的大小、屏蔽图案的大小颜色等。
如果有需要,大家还可以修改分割线是实线还是虚线、屏蔽图案任意图片、各种阴影效果,输入光标等都可以的。
使用起来也比较方便,只需要在xml中定义:
这里有两点需要注意的是,
1.为什么我加了一个padding,因为我绘制并没有留出空隙,这个view是多大就画多大,如果大家觉得边框过于紧凑,加个padding就行了(建议加上,否则如果设置外框线条太粗可能显示没有设置的粗,或者圆角不明显等)。
2.我直接定义了宽和高,这显然不太好,其实这只是为了方便我测试而已,大家把onMeasure方法测量逻辑改成下面这样,使用wrap_content就行咯。
使用wrap_content:
java代码中的使用:
这大概只能算是半成品,但是如果要求不高,拿来直接用也是可以的。
如果有特殊要求,例如我不想自己写个密码输入布局,我想使用自带输入法,点击密码框就弹出输入法输入。这就要大家自己实现了监听输入法的输入了。
----------------修改继承自edittext 可以调用自带输入法进行密码输入,同时edittext的大部分属性都可以使用。同时加了输入指示,输入完成变色等---------
效果图:
JAVA源码:
package cn.small_qi.transitiontest.diyview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.support.v7.widget.AppCompatEditText;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
/**
* Created by small_qi on 2017/7/12.
*/
public class PayInputView extends AppCompatEditText {
private Paint mPaint;
private InputFinishListener inputFinishListener;//输入完成监听
private int inputNum = 0;//当前输入的密码个数
private int passwordNum = 6;//密码个数
private int boundWidth = 2;//外层框线条粗细
private int boundColor = Color.BLACK;//外层框线条颜色
private int boundRadius = 0;//外框圆角半径
private int deliverWidth = 1;//分割线粗细
private int deliverColor = Color.GRAY;//分割线条颜色
private int deliverPadding = 5;//分割线距离框的大小
private int circleRadius = 15;//密码圆点半径大小
private int circleColor = Color.BLACK;//密码圆点颜色
private StringBuilder currentPassword;//用户输入的密码
public PayInputView(Context context) {
super(context);
init();
}
public PayInputView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
currentPassword = new StringBuilder();
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
setBackgroundDrawable(null);
setMaxLines(1);
//禁止复制等操作
disableCopy();
}
private void disableCopy() {
setLongClickable(false);
setTextIsSelectable(false);
setSelected(false);
setCustomSelectionActionModeCallback(new ActionMode.Callback() {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
return false;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return false;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
}
});
}
public PayInputView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/**
* 根据手机的分辨率从 dp 的单位 转成为 px(像素)
*/
private int dip2px(float dpValue) {
final float scale = getContext().getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width, height;
if (widthMode == MeasureSpec.AT_MOST) {
width = dip2px(36) * passwordNum;
} else {
width = widthSize;
}
if (heightMode == MeasureSpec.AT_MOST) {
height = dip2px(36);
} else {
height = heightSize;
}
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
if (inputNum==passwordNum){
//如果输入完毕 整个框变色 如无此需求可删除这段代码
if (hasFocus()&&hasFocusable()){
boundColor=Color.BLUE;
deliverColor =Color.BLUE;
}else{
boundColor=Color.BLACK;
deliverColor =Color.BLACK;
}
}else{
boundColor=Color.BLACK;
deliverColor =Color.BLACK;
}
//
int width = getWidth();
int height = getHeight();
float deliverSize = (width - getPaddingLeft() - getPaddingRight()) / passwordNum;
//1.画外框
drawBound(canvas, width, height);
//2.画分割线
drawDeliver(canvas, height, deliverSize);
//2.1.输入指示
drawIndicator(canvas, height, deliverSize);
//3.输入密码之后显示的图案
drawCircle(canvas, height, deliverSize);
}
private void drawIndicator(Canvas canvas, int height, float deliverSize) {
if (inputNum < 0 || inputNum == passwordNum ||!(hasFocus()&&hasFocusable())) return;
mPaint.setColor(Color.BLUE);
//mPaint.setShadowLayer(5,3,3,0xFFFFAAFF);//阴影效果
mPaint.setStrokeWidth(boundWidth + 2);
RectF rectF = new RectF(deliverSize * inputNum + getPaddingLeft(), getPaddingTop(), deliverSize * (inputNum + 1) + getPaddingLeft(), height - getPaddingBottom());
canvas.drawRoundRect(rectF, boundRadius, boundRadius, mPaint);
}
private void drawBound(Canvas canvas, int width, int height) {
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(boundWidth);
mPaint.setColor(boundColor);
RectF rectF = new RectF(getPaddingLeft(), getPaddingTop(), width - getPaddingRight(), height - getPaddingBottom());
canvas.drawRoundRect(rectF, boundRadius, boundRadius, mPaint);
}
private void drawDeliver(Canvas canvas, int height, float deliverSize) {
mPaint.setStrokeWidth(deliverWidth);
mPaint.setColor(deliverColor);
Path path = new Path();
for (int i = 1; i < passwordNum; i++) {
path.reset();
path.moveTo(deliverSize * i + getPaddingLeft(), 0 + deliverPadding + getPaddingTop());
path.lineTo(deliverSize * i + getPaddingLeft(), height - deliverPadding - getPaddingBottom());
canvas.drawPath(path, mPaint);
}
}
private void drawCircle(Canvas canvas, int height, float deliverSize) {
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(circleColor);
for (int i = 0; i < inputNum; i++) {
acf5
canvas.drawCircle(deliverSize * i + getPaddingLeft() + deliverSize / 2, (height - getPaddingTop() - getPaddingBottom()) / 2 + getPaddingTop(), circleRadius, mPaint);
}
}
//监听文字输入长度
@Override
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
Log.i("TAG", "onTextChanged: " + text + " " + start + " " + lengthBefore + " " + lengthAfter);
//改变之后长度大于之前 证明是输入操作
if (Math.abs(lengthAfter - lengthBefore) == 1) {
if (lengthAfter < lengthBefore) {
deletePassword();
} else if (inputNum<passwordNum){
if (start == 0) {
notifyPasswordChange(text.charAt(lengthAfter - 1));
} else {
notifyPasswordChange(text.charAt(start));
}
}
} else{
for (int i = 0; i < lengthAfter-lengthBefore; i++) {
if (inputNum<passwordNum) {
notifyPasswordChange(text.charAt(start + i));
}
}
}
//缓存字符大于20时清空文字缓存
if (text.length()>20){
setText(getPassword());
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
//输入一个密码
public void inputPassword(Object pwd) {
append(String.valueOf(pwd));
}
private void notifyPasswordChange(Object pwd) {
if (inputNum < passwordNum) {
currentPassword.append(pwd);
inputNum++;
invalidate();
}
if (inputNum == passwordNum) {
if (inputFinishListener != null) {
inputFinishListener.onFinish(getPassword());
}
}
}
//删除一个密码
public void deletePassword() {
if (currentPassword.length() > 0) {
currentPassword.deleteCharAt(currentPassword.length() - 1);
inputNum--;
invalidate();
}
}
//清空输入的所有密码
public void cleanInput() {
inputNum = 0;
currentPassword.delete(0, currentPassword.length());
invalidate();
}
//获取输入的所有密码
public String getPassword() {
return currentPassword.toString();
}
public void setInputFinishListener(InputFinishListener inputFinishListener) {
this.inputFinishListener = inputFinishListener;
}
public interface InputFinishListener {
void onFinish(String pwd);
}
}
--有意见别忘了在评论中提出哦--
那就需要自己画出来了。水平有限,这里提供我自己自定义的一个过程,哪里不好,大家提提意见。
先上个效果图预览吧,我这里只是实现了那个框,具体输入布局大家可以在xml随意定义。
使用起来还是比较方便的,主要开放有四个方法和一个输入完成的回调接口。
这几个方法下面会介绍。
实现过程
这个密码输入框整体是一个输入框,每个密码之间有一根竖线间隔,每输入一个密码,就绘制一个屏蔽图案(一般是圆形小点)。
那么我们需要:
1.绘制外部的输入框
2.根据密码个数绘制间隔的竖线
3.根据用户输入的密码个数绘制屏蔽图
大概流程就这样,具体每一部分代码就不贴出来了,我直接贴这个文件的代码吧
package cn.small_qi.transitiontest.diyview; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.RectF; import android.support.annotation.Nullable; import android.util.AttributeSet; import android.view.View; /** * Created by small_qi on 2017/7/12. */ public class PayInputView extends View { private Paint mPaint; private InputFinishListener inputFinishListener;//输入完成监听 private int inputNum=0;//当前输入的密码个数 private int passwordNum=6;//密码个数 private 4000 int boundWidth=2;//外层框线条粗细 private int boundColor= Color.BLACK;//外层框线条颜色 private int boundRadius=0;//外框圆角半径 private int deliverWidth=1;//分割线粗细 private int deliverColor=Color.GRAY;//分割线条颜色 private int deliverPadding=5;//分割线距离框的大小 private int circleRadius =15;//密码圆点半径大小 private int circleColor= Color.BLACK;//密码圆点颜色 private StringBuilder currentPassword;//用户输入的密码 public PayInputView(Context context) { super(context); init(); } public PayInputView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } private void init() { currentPassword=new StringBuilder(); mPaint=new Paint(Paint.ANTI_ALIAS_FLAG); } public PayInputView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //TODO 此处应处理控件的测量逻辑 } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int width =getWidth(); int height =getHeight(); float deliverSize=(width-getPaddingLeft()-getPaddingRight())/passwordNum; //1.画外框 drawBound(canvas, width, height); //2.画分割线 drawDeliver(canvas, height, deliverSize); //3.输入密码之后显示的图案 drawCircle(canvas, height, deliverSize); } private void drawBound(Canvas canvas, int width, int height) { mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(boundWidth); mPaint.setColor(boundColor); RectF rectF = new RectF(getPaddingLeft(),getPaddingTop(),width-getPaddingRight(),height-getPaddingBottom()); canvas.drawRoundRect(rectF,boundRadius,boundRadius,mPaint); } private void drawDeliver(Canvas canvas, int height, float deliverSize) { mPaint.setStrokeWidth(deliverWidth); mPaint.setColor(deliverColor); Path path = new Path(); for (int i = 1; i < passwordNum; i++) { path.reset(); path.moveTo(deliverSize*i+getPaddingLeft(),0+deliverPadding+getPaddingTop()); path.lineTo(deliverSize*i+getPaddingLeft(),height-deliverPadding-getPaddingBottom()); canvas.drawPath(path,mPaint); } } private void drawCircle(Canvas canvas, int height, float deliverSize) { mPaint.setStyle(Paint.Style.FILL); mPaint.setColor(circleColor); for (int i = 0; i < inputNum; i++) { canvas.drawCircle(deliverSize*i+getPaddingLeft()+deliverSize/2,(height-getPaddingTop()-getPaddingBottom())/2+getPaddingTop(), circleRadius,mPaint); } } //输入一个密码 public void inputPassword(Object pwd){ if (inputNum<passwordNum) { currentPassword.append(pwd); inputNum++; } invalidate(); if (inputNum==passwordNum){ if (inputFinishListener!=null){ inputFinishListener.onFinish(getPassword()); } } } //删除一个密码 public void deletePassword(){ if (currentPassword.length()>0) { currentPassword.deleteCharAt(currentPassword.length() - 1); inputNum--; } invalidate(); } //清空输入的所有密码 public void cleanInput(){ inputNum=0; currentPassword.delete(0,currentPassword.length()); invalidate(); } //获取输入的所有密码 public String getPassword(){ return currentPassword.toString(); } public void setInputFinishListener(InputFinishListener inputFinishListener) { this.inputFinishListener = inputFinishListener; } public interface InputFinishListener{ void onFinish(String pwd); } }
之前说的开放四个方法分别就是:输入一个密码、删除一个密码、清空输入、获取当前输入的所有密码这四个。监听就是用户输入所有密码后回调。
总体来说,能够自定义的属性还是很多的,但是我没有开放出方法,也没有定义xml属性,如果需要,大家稍作修改即可。
大家看我的全局变量的定义就知道能够自动义那些内容,包括最大输入的密码个数;外框线条大小、颜色、圆角,分割线大小、颜色、距离外框的大小、屏蔽图案的大小颜色等。
如果有需要,大家还可以修改分割线是实线还是虚线、屏蔽图案任意图片、各种阴影效果,输入光标等都可以的。
使用起来也比较方便,只需要在xml中定义:
<your.package.PayInputView android:id="@+id/inputview" android:layout_width="256dp" android:padding="1dp" android:layout_height="48dp" />
这里有两点需要注意的是,
1.为什么我加了一个padding,因为我绘制并没有留出空隙,这个view是多大就画多大,如果大家觉得边框过于紧凑,加个padding就行了(建议加上,否则如果设置外框线条太粗可能显示没有设置的粗,或者圆角不明显等)。
2.我直接定义了宽和高,这显然不太好,其实这只是为了方便我测试而已,大家把onMeasure方法测量逻辑改成下面这样,使用wrap_content就行咯。
使用wrap_content:
/** * 根据手机的分辨率从 dp 的单位 转成为 px(像素) */ private int dip2px(float dpValue) { final float scale = getContext().getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widthMode=MeasureSpec.getMode(widthMeasureSpec); int widthSize=MeasureSpec.getSize(widthMeasureSpec); int heightMode=MeasureSpec.getMode(heightMeasureSpec); int heightSize=MeasureSpec.getSize(heightMeasureSpec); int width,height; if (widthMode==MeasureSpec.AT_MOST){ width=dip2px(36)*passwordNum; }else { width=widthSize; } if (heightMode==MeasureSpec.AT_MOST){ height=dip2px(36); }else{ height=heightSize; } setMeasuredDimension(width,height); }
java代码中的使用:
private PayInputView payView; private void initPayView() { payView = (PayInputView) findViewById(R.id.inputview); //输入完成监听 payView.setInputFinishListener(new PayInputView.InputFinishListener() { @Override public void onFinish(String pwd) { Toast.makeText(MainActivity.this, "你输入的密码:"+pwd, Toast.LENGTH_SHORT).show(); } }); } public void onClick(View v){ switch (v.getId()){ case R.id.input://输入按钮 //这里只是模拟用户输入密码,具体使用时,用户按一个数字就调用这个方法把密码传过去即可。 payView.inputPassword(2); break; case R.id.delete://删除按钮 payView.deletePassword(); break; case R.id.clear://清除按钮 payView.cleanInput(); break; } }
这大概只能算是半成品,但是如果要求不高,拿来直接用也是可以的。
如果有特殊要求,例如我不想自己写个密码输入布局,我想使用自带输入法,点击密码框就弹出输入法输入。这就要大家自己实现了监听输入法的输入了。
----------------修改继承自edittext 可以调用自带输入法进行密码输入,同时edittext的大部分属性都可以使用。同时加了输入指示,输入完成变色等---------
效果图:
JAVA源码:
package cn.small_qi.transitiontest.diyview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.support.v7.widget.AppCompatEditText;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
/**
* Created by small_qi on 2017/7/12.
*/
public class PayInputView extends AppCompatEditText {
private Paint mPaint;
private InputFinishListener inputFinishListener;//输入完成监听
private int inputNum = 0;//当前输入的密码个数
private int passwordNum = 6;//密码个数
private int boundWidth = 2;//外层框线条粗细
private int boundColor = Color.BLACK;//外层框线条颜色
private int boundRadius = 0;//外框圆角半径
private int deliverWidth = 1;//分割线粗细
private int deliverColor = Color.GRAY;//分割线条颜色
private int deliverPadding = 5;//分割线距离框的大小
private int circleRadius = 15;//密码圆点半径大小
private int circleColor = Color.BLACK;//密码圆点颜色
private StringBuilder currentPassword;//用户输入的密码
public PayInputView(Context context) {
super(context);
init();
}
public PayInputView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
currentPassword = new StringBuilder();
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
setBackgroundDrawable(null);
setMaxLines(1);
//禁止复制等操作
disableCopy();
}
private void disableCopy() {
setLongClickable(false);
setTextIsSelectable(false);
setSelected(false);
setCustomSelectionActionModeCallback(new ActionMode.Callback() {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
return false;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return false;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
}
});
}
public PayInputView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/**
* 根据手机的分辨率从 dp 的单位 转成为 px(像素)
*/
private int dip2px(float dpValue) {
final float scale = getContext().getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width, height;
if (widthMode == MeasureSpec.AT_MOST) {
width = dip2px(36) * passwordNum;
} else {
width = widthSize;
}
if (heightMode == MeasureSpec.AT_MOST) {
height = dip2px(36);
} else {
height = heightSize;
}
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
if (inputNum==passwordNum){
//如果输入完毕 整个框变色 如无此需求可删除这段代码
if (hasFocus()&&hasFocusable()){
boundColor=Color.BLUE;
deliverColor =Color.BLUE;
}else{
boundColor=Color.BLACK;
deliverColor =Color.BLACK;
}
}else{
boundColor=Color.BLACK;
deliverColor =Color.BLACK;
}
//
int width = getWidth();
int height = getHeight();
float deliverSize = (width - getPaddingLeft() - getPaddingRight()) / passwordNum;
//1.画外框
drawBound(canvas, width, height);
//2.画分割线
drawDeliver(canvas, height, deliverSize);
//2.1.输入指示
drawIndicator(canvas, height, deliverSize);
//3.输入密码之后显示的图案
drawCircle(canvas, height, deliverSize);
}
private void drawIndicator(Canvas canvas, int height, float deliverSize) {
if (inputNum < 0 || inputNum == passwordNum ||!(hasFocus()&&hasFocusable())) return;
mPaint.setColor(Color.BLUE);
//mPaint.setShadowLayer(5,3,3,0xFFFFAAFF);//阴影效果
mPaint.setStrokeWidth(boundWidth + 2);
RectF rectF = new RectF(deliverSize * inputNum + getPaddingLeft(), getPaddingTop(), deliverSize * (inputNum + 1) + getPaddingLeft(), height - getPaddingBottom());
canvas.drawRoundRect(rectF, boundRadius, boundRadius, mPaint);
}
private void drawBound(Canvas canvas, int width, int height) {
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(boundWidth);
mPaint.setColor(boundColor);
RectF rectF = new RectF(getPaddingLeft(), getPaddingTop(), width - getPaddingRight(), height - getPaddingBottom());
canvas.drawRoundRect(rectF, boundRadius, boundRadius, mPaint);
}
private void drawDeliver(Canvas canvas, int height, float deliverSize) {
mPaint.setStrokeWidth(deliverWidth);
mPaint.setColor(deliverColor);
Path path = new Path();
for (int i = 1; i < passwordNum; i++) {
path.reset();
path.moveTo(deliverSize * i + getPaddingLeft(), 0 + deliverPadding + getPaddingTop());
path.lineTo(deliverSize * i + getPaddingLeft(), height - deliverPadding - getPaddingBottom());
canvas.drawPath(path, mPaint);
}
}
private void drawCircle(Canvas canvas, int height, float deliverSize) {
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(circleColor);
for (int i = 0; i < inputNum; i++) {
acf5
canvas.drawCircle(deliverSize * i + getPaddingLeft() + deliverSize / 2, (height - getPaddingTop() - getPaddingBottom()) / 2 + getPaddingTop(), circleRadius, mPaint);
}
}
//监听文字输入长度
@Override
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
Log.i("TAG", "onTextChanged: " + text + " " + start + " " + lengthBefore + " " + lengthAfter);
//改变之后长度大于之前 证明是输入操作
if (Math.abs(lengthAfter - lengthBefore) == 1) {
if (lengthAfter < lengthBefore) {
deletePassword();
} else if (inputNum<passwordNum){
if (start == 0) {
notifyPasswordChange(text.charAt(lengthAfter - 1));
} else {
notifyPasswordChange(text.charAt(start));
}
}
} else{
for (int i = 0; i < lengthAfter-lengthBefore; i++) {
if (inputNum<passwordNum) {
notifyPasswordChange(text.charAt(start + i));
}
}
}
//缓存字符大于20时清空文字缓存
if (text.length()>20){
setText(getPassword());
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
//输入一个密码
public void inputPassword(Object pwd) {
append(String.valueOf(pwd));
}
private void notifyPasswordChange(Object pwd) {
if (inputNum < passwordNum) {
currentPassword.append(pwd);
inputNum++;
invalidate();
}
if (inputNum == passwordNum) {
if (inputFinishListener != null) {
inputFinishListener.onFinish(getPassword());
}
}
}
//删除一个密码
public void deletePassword() {
if (currentPassword.length() > 0) {
currentPassword.deleteCharAt(currentPassword.length() - 1);
inputNum--;
invalidate();
}
}
//清空输入的所有密码
public void cleanInput() {
inputNum = 0;
currentPassword.delete(0, currentPassword.length());
invalidate();
}
//获取输入的所有密码
public String getPassword() {
return currentPassword.toString();
}
public void setInputFinishListener(InputFinishListener inputFinishListener) {
this.inputFinishListener = inputFinishListener;
}
public interface InputFinishListener {
void onFinish(String pwd);
}
}
--有意见别忘了在评论中提出哦--
相关文章推荐
- [Android UI开发] 仿微信/支付宝的密码输入框效果:GridPasswordView
- Android自定义View仿支付宝输入六位密码功能
- 自定义view,仿微信、支付宝密码输入控件的源码实现
- Android自定义View仿支付宝输入六位密码功能_Android
- Android高效率实现自定义密码输入效果,仿微信和支付宝密码输入效果
- 仿微信/支付宝的密码输入框效果 android
- 仿微信/支付宝的密码输入框效果 带自定义键盘
- 仿微信/支付宝的密码输入框效果 android
- Android 支付宝支付密码输入界面
- GridPasswordView 类似支付宝支付密码输入框
- Android仿支付宝支付密码输入框
- [Android]仿支付宝自定义View密码框
- android中6个EditText输入验证码(仿支付宝支付输入密码框)
- 自定义view仿支付宝密码输入框
- Android自定义View模仿密码输入框
- Android仿支付宝支付密码输入框
- 自定义view密码框等同于支付宝支付密码框
- Android自定义支付密码输入框
- 仿微信/支付宝的密码输入框效果 android
- android:仿支付宝/微信的密码输入框效果