先看效果

8cb8ed7b84e06bb15daefebc7f75d394.png

简要描述

通过反射 取到 InputFilter 中android.text.InputFilter$LengthFilter ,此为内部类,查看源码可知,为了取到系统提供的maxLength属性

PaintLastAnim为了实现输入框删除|输入 圆点放大和缩小的动画

PaintLastAnim.onAnimationEnd() 设置监听 保证动画结束

贴代码

import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.RectF;

import android.support.annotation.Nullable;

import android.support.v7.widget.AppCompatEditText;

import android.text.InputFilter;

import android.util.AttributeSet;

import android.view.animation.Animation;

import android.view.animation.Transformation;

import java.lang.reflect.Field;

public class PassView extends AppCompatEditText {

public static final String TAG = "PassView";

private Paint mPaint;

private Paint mPaintContent;

private Paint mPaintArc;

private int mMaxLineSize;

private int mPadding = 2;

private int mRadius = 0;

private int mCircleRadius = 0;

/**

* 插速

*/

private float mInterpolatorTime = 6;

/**

* 是否是输入文字,还是删除文字

*/

private boolean mAddText;

/**

* 当前输入的字符数量

*/

private int mCurrentTextLen = 0;

private PaintLastAnim mPaintLastAnim;

private PasswordCallback mPasswordCallback;

public PassView(Context context) {

this(context, null);

}

public PassView(Context context, @Nullable AttributeSet attrs) {

this(context, attrs, 0);

}

public PassView(Context context, @Nullable AttributeSet attrs,

int defStyleAttr) {

super(context, attrs, defStyleAttr);

initPaint();

}

private void initPaint() {

mPaint = new Paint();

mPaint.setAntiAlias(true);

mPaint.setColor(Color.GRAY);

mPaint.setStyle(Paint.Style.STROKE);

mPaintContent = new Paint();

mPaintContent.setAntiAlias(true);

mPaintContent.setColor(Color.WHITE);

mPaintContent.setStyle(Paint.Style.FILL);

mPaintArc = new Paint();

mPaintArc.setAntiAlias(true);

mPaintArc.setColor(Color.BLACK);

mPaintArc.setStyle(Paint.Style.FILL);

mMaxLineSize = getMaxLength();

mRadius = dip2Px(6);

mCircleRadius = dip2Px(6);

mPaintLastAnim = new PaintLastAnim();

mPaintLastAnim.setDuration(200);

mPaintLastAnim.setAnimationListener(new Animation.AnimationListener() {

@Override

public void onAnimationStart(Animation animation) {

}

@Override

public void onAnimationEnd(Animation animation) {

if (mCurrentTextLen == getMaxLength()) {

if (mPasswordCallback != null) {

mPasswordCallback.onComplete(getText());

}

}

}

@Override

public void onAnimationRepeat(Animation animation) {

}

});

}

private int dip2Px(int i) {

float density = getContext().getResources().getDisplayMetrics().density;

return (int) (density * i + 0.5);

}

private int getMaxLength() {

int length = 0;

try {

InputFilter[] filters = getFilters();

for (InputFilter filter : filters) {

Class extends InputFilter> tmpClazz = filter.getClass();

if ("android.text.InputFilter$LengthFilter".equals(tmpClazz.getName())) {

Field maxField = tmpClazz.getDeclaredField("mMax");

maxField.setAccessible(true);

length = (int) maxField.get(filter);

}

}

} catch (Exception e) {

e.printStackTrace();

}

return length;

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

RectF rectF = new RectF(mPadding, mPadding, getMeasuredWidth() - mPadding,

getMeasuredHeight() - mPadding);

//绘制白色背景

canvas.drawRoundRect(rectF, mRadius, mRadius, mPaintContent);

//绘制灰色线

canvas.drawRoundRect(rectF, mRadius, mRadius, mPaint);

mPaint.setStrokeWidth(2f);

for (int i = 1; i < mMaxLineSize; i++) {

float x = getMeasuredWidth() / mMaxLineSize * i;

canvas.drawLine(x, 0, x, getMeasuredHeight(), mPaint);

}

float cy = getMeasuredHeight() / 2;

float half = getMeasuredWidth() / mMaxLineSize / 2;

for (int i = 0; i < mMaxLineSize; i++) {

float x = getMeasuredWidth() / mMaxLineSize * i + half;

if (mAddText) {

if (i < mCurrentTextLen - 1) {

canvas.drawCircle(x, cy, mCircleRadius, mPaintArc);

} else if (i == mCurrentTextLen - 1) {

canvas.drawCircle(x, cy, mCircleRadius * mInterpolatorTime, mPaintArc);

}

} else {

if (i < mCurrentTextLen) {

canvas.drawCircle(x, cy, mCircleRadius, mPaintArc);

} else if (i == mCurrentTextLen) {

canvas.drawCircle(x, cy, mCircleRadius * (1 - mInterpolatorTime), mPaintArc);

}

}

}

}

@Override

protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {

super.onTextChanged(text, start, lengthBefore, lengthAfter);

mAddText = getText().length() > mCurrentTextLen;

if (mCurrentTextLen <= getMaxLength()) {

clearAnimation();

if (mPaintLastAnim != null) {

startAnimation(mPaintLastAnim);

} else {

invalidate();

}

}

mCurrentTextLen = text.length();

}

private class PaintLastAnim extends Animation {

@Override

protected void applyTransformation(float interpolatedTime, Transformation t) {

super.applyTransformation(interpolatedTime, t);

PassView.this.mInterpolatorTime = interpolatedTime;

postInvalidate();

}

}

public PassView setOnPasswordComplete(PasswordCallback passwordCallback) {

mPasswordCallback = passwordCallback;

return this;

}

interface PasswordCallback {

void onComplete(CharSequence text);

}

}

xml 代码

android:layout_width="300dp"

android:layout_height="50dp"

android:layout_centerInParent="true"

android:cursorVisible="false"

android:focusable="true"

android:focusableInTouchMode="true"

android:inputType="number"

android:lines="1"

android:maxLength="6"/>

###更多笔记请关注公众号,不定期更新###

20200601223402386.png

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐