700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 安卓/Android 模仿支付宝/微信 支付密码输入框的自定义View

安卓/Android 模仿支付宝/微信 支付密码输入框的自定义View

时间:2021-12-04 13:22:52

相关推荐

安卓/Android 模仿支付宝/微信 支付密码输入框的自定义View

类似这个密码输入框相信在博客上已经不少了,但是我稍微看了一下,大都是通过XML布局,然后组合成的一个自定义View。但是我想只用一个java文件,拿来就用该怎么办呢?

那就需要自己画出来了。水平有限,这里提供我自己自定义的一个过程,哪里不好,大家提提意见。

先上个效果图预览吧,我这里只是实现了那个框,具体输入布局大家可以在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 /7/12.*/public class PayInputView extends View {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);}public PayInputView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);//TODO 此处应处理控件的测量逻辑}@Overrideprotected 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.PayInputViewandroid: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);}@Overrideprotected 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() {@Overridepublic 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 /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() {@Overridepublic boolean onCreateActionMode(ActionMode mode, Menu menu) {return false;}@Overridepublic boolean onPrepareActionMode(ActionMode mode, Menu menu) {return false;}@Overridepublic boolean onActionItemClicked(ActionMode mode, MenuItem item) {return false;}@Overridepublic 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);}@Overrideprotected 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);}@Overrideprotected 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++) {canvas.drawCircle(deliverSize * i + getPaddingLeft() + deliverSize / 2, (height - getPaddingTop() - getPaddingBottom()) / 2 + getPaddingTop(), circleRadius, mPaint);}}//监听文字输入长度@Overrideprotected 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());}}@Overridepublic 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);}}

--有意见别忘了在评论中提出哦--

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。