相信大家对支付保的密码输入框应该很熟悉吧(毕竟经常用),先给大家看一下支付宝的
好吧回归正题,昨天我的部门老大给了我一个APP让我看看里面有那些好的地方,可以放到我们自己APP中的模块、功能、流程(哎,小公司就这样各种抄袭),在这个APP中我看到了这个密码输入框我就想自己写一个,而身为菜鸟的我没有什么好的思路,就去github的海洋中游了一圈down了几个开源项目找了找思路,最终有了这个。
设计思路:
实现这种输入的效果我们得用自定义View
第一步:创建一个类继承EditText(我继承的是AppCompatEditText,其实是一样的)
第二步:创建一个attr文件,在里面写好自己的自定义属性。
第三步:重写onDraw方法画界面
第四步:写一个回调接口将密码输入完成的操作回调出去。
设计思路大概就是这样的,其中最重要的就是在onDraw方法中画界面,其他的都非常的简单,这里也主要将onDraw方法中的操作,其他步骤一会看完整的代码(我会在文章的最后吧代码贴出来)
界面的绘制
界面的绘制我的思路是这样的:
第一步:绘制背景,背景为浅灰色背景
第二步:绘制白色的内容区,内容区比背景稍微窄一点、矮一点,这样就能形成咱这个输入框的外边框啦。
第三步:绘制分割线
第四步:绘制输入的内容(用小圆点代替)
背景的绘制,代码如下:
//画背景
RectF bgRect = new RectF(0, 0, width, height);
//设置背景的颜色
bgPaint.setColor(borderColor);
canvas.drawRect(bgRect, bgPaint);
内容区的绘制,代码如下:
//画内容区
RectF contentRect = new RectF(bgRect.left + borderWidth, bgRect.top + borderWidth, bgRect.right - borderWidth, bgRect.bottom - borderWidth);
rectPaint.setColor(chunkColor);
canvas.drawRect(contentRect, rectPaint);
上述代码中borderWidth这个值,你可以把它认为是外边框的宽度,我的这个外边框的形成其实就是一个大矩形里面套了一个小矩形,这两个矩形的颜色不一样而形成的外边框。
绘制分割线,代码如下:
//画分割线
bgPaint.setStrokeWidth(linesWidth);//设置分割线的宽度
bgPaint.setColor(linesColor);//设置分割线的颜色
for (int i = 0; i < defultCount; i++) {
float x = width / defultCount * i;
canvas.drawLine(x, borderWidth, x, height - borderWidth, bgPaint);
}
上述代码中最重要的就是这句: float x = width / defultCount * i;
这句话的意思就是计算分割线的位置,分割线y轴是不变的改变的就是x轴的值,我们来解释一下这段代码;
width:控件的整体长度
defultCount:控件有几个格子
i:i是从0开始的,它在for循环中递增从而算出第一个分割线到最后一个分割线x轴的位置
绘制密码,代码如下:
if (textLength > 0) {
//画密码
int j = getWidth() / defultCount / 2;
for (int i = 0; i < textLength; i++) {
int cx = width / defultCount * i + j;
circleRadius = height / 6;
canvas.drawCircle(cx, getHeight() / 2, circleRadius, bgPaint);
}
}
我们在输入的密码长度大于零的时候才开始绘制
上面的代码我就不做解释了(伙伴们应该看的懂吧),到这里我们的绘制工作就算是完结了,下面就是对输入内容的监听并回调。
对输入内容的监听:
为了监听输入内容,我们得重写onTextChanged方法,代码如下:
@Override
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
super.onTextChanged(text, start, lengthBefore, lengthAfter);
textLength = text.toString().length();
invalidate();
if (textLength == defultCount) {
if (onInputFinishListener != null) {
onInputFinishListener.inputFinish(text.toString());
}
}
}
这里面需要我们自己去写一个回调接口,如下:
//声明接口
private OnInputFinishListener onInputFinishListener;
//接口的set方法
public void setOnInputFinishListener(OnInputFinishListener onInputFinishListener) {
this.onInputFinishListener = onInputFinishListener;
}
//接口的本体
public interface OnInputFinishListener {
void inputFinish(String text);
}
—————————————————————我是分割线——————————————————
要是大家没兴趣看文章的话可以直接copy代码,代码如下:
package com.example.administrator.coo.passwordEditText;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.support.v7.widget.AppCompatEditText;
import android.util.AttributeSet;
import android.view.ViewGroup;
import com.example.administrator.coo.R;
/**
* Created by zhanglei on 2017/6/9.
* 仿支付保密码输入框
*/
public class PasswordEditText extends AppCompatEditText {
/**
* 输入格子的数量
*/
private int defultCount = 6;
/**
* 用来画背景的画笔
*/
private Paint bgPaint = new Paint();
/**
* 用来画内容块的画笔
*/
private Paint rectPaint = new Paint();
/**
* 密码的长度
*/
private int textLength = 0;
/**
* 分割线的宽度
*/
private float linesWidth = 0;
/**
* 边框的宽度
*/
private float borderWidth = 0;
/**
* 边框的颜色
*/
private int borderColor = 0xFFCCCCCC;
/**
* 分割线的颜色
*/
private int linesColor = 0xFFCCCCCC;
/**
* 密码圆点的半径
*/
private int circleRadius;
/**
* 内容块底色
*/
private int chunkColor = Color.WHITE;
public PasswordEditText(Context context) {
super(context);
}
public PasswordEditText(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.PasswordEditText, 0, 0);
defultCount = a.getInteger(R.styleable.PasswordEditText_pe_count, defultCount);
borderWidth = a.getDimension(R.styleable.PasswordEditText_pe_lineWidth, linesWidth);
linesWidth = a.getDimension(R.styleable.PasswordEditText_pe_cuttingLineWidth, borderWidth);
borderColor = a.getColor(R.styleable.PasswordEditText_pe_lineColor, this.borderColor);
linesColor = a.getColor(R.styleable.PasswordEditText_pe_cuttingLineColor, linesColor);
chunkColor = a.getColor(R.styleable.PasswordEditText_pe_chunkColor, chunkColor);
a.recycle();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//获取控件的宽
int width = getWidth();
//获取控件的高
int height = getHeight();
//分割线的宽度
linesWidth = getLinesWidth() - 3;
//边线的宽度
borderWidth = getLinesWidth() - 1;
/* 大家可以看到我获取分割线的宽度和边线的宽度的代码是写在onDraw方法里的,这样做会使在布局中设置的宽度不起作用,但是如果不这么写的话我不知道要给一个多宽的默认值,所以就只能先这样了,大家如果有好的方法和思路记得给我说呀,谢谢。 */
//画背景
RectF bgRect = new RectF(0, 0, width, height);
//设置背景的颜色
bgPaint.setColor(borderColor);
canvas.drawRect(bgRect, bgPaint);
//画内容区
RectF contentRect = new RectF(bgRect.left + borderWidth, bgRect.top + borderWidth, bgRect.right - borderWidth, bgRect.bottom - borderWidth);
rectPaint.setColor(chunkColor);
canvas.drawRect(contentRect, rectPaint);
//画分割线
bgPaint.setStrokeWidth(linesWidth);
bgPaint.setColor(linesColor);
for (int i = 0; i < defultCount; i++) {
float x = width / defultCount * i;
canvas.drawLine(x, borderWidth, x, height - borderWidth, bgPaint);
}
if (textLength > 0) {
//画密码
int j = getWidth() / defultCount / 2;
for (int i = 0; i < textLength; i++) {
int cx = width / defultCount * i + j;
circleRadius = height / 6;
canvas.drawCircle(cx, getHeight() / 2, circleRadius, bgPaint);
}
}
}
@Override
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
super.onTextChanged(text, start, lengthBefore, lengthAfter);
textLength = text.toString().length();
invalidate();
if (textLength == defultCount) {
if (onInputFinishListener != null) {
onInputFinishListener.inputFinish(text.toString());
}
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
private float getLinesWidth() {
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) getLayoutParams();
//获取控件左边的margin值
int leftMargin = lp.leftMargin;
//获取控件右边的margin值
int rightMargin = lp.rightMargin;
//边框及分割线的宽度
return (leftMargin + rightMargin + getWidth()) / 200;
}
private OnInputFinishListener onInputFinishListener;
public void setOnInputFinishListener(OnInputFinishListener onInputFinishListener) {
this.onInputFinishListener = onInputFinishListener;
}
public interface OnInputFinishListener {
void inputFinish(String text);
}
}
这里还有一个需要你copy的,这个是自定以的一些属性:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="PasswordEditText">
<attr name="pe_count" format="integer" />
<attr name="pe_lineWidth" format="dimension" />
<attr name="pe_cuttingLineWidth" format="dimension" />
<attr name="pe_lineColor" format="color" />
<attr name="pe_cuttingLineColor" format="color" />
<attr name="pe_passwordColor" format="color" />
<attr name="pe_chunkColor" format="color" />
</declare-styleable>
</resources>
文章的最后给大家看一下,这个密码输入框的效果图
当输入完成时会回调OnInputFinishListener 接口中的inputFinish方法获取输入的内容。
文章到此结束,希望能给大家带来帮助