android 仿支付宝密码输入框,仿支付宝密码输入框
先看效果 简要描述通过反射 取到 InputFilter 中android.text.InputFilter$LengthFilter ,此为内部类,查看源码可知,为了取到系统提供的maxLength属性PaintLastAnim为了实现输入框删除|输入 圆点放大和缩小的动画PaintLastAnim.onAnimationEnd() 设置监听 保证动画结束贴代码import android.co
先看效果
简要描述
通过反射 取到 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"/>
###更多笔记请关注公众号,不定期更新###
更多推荐
所有评论(0)