概述
先描述一下具体需求吧,我们在项目中可能会遇到修改用户名及密码的需求,为保证一定的完全性,服务端一般会接入短信验证码的功能。我们需要将接受到的验证码返回给服务端进行验证。可能会有以下的界面让用户输入验证码:
1. 特性
- 支持设置框数量
- 支持设置框的风格样式
- 支持根据状态区分框颜色
- 基于EditText实现,更优雅
2. 效果图 3. 属性
4. 代码
- attrs.xml
- SplitEditText.java
public class SplitEditText extends AppCompatEditText {
/**
* 画笔
*/
private Paint mPaint;
/**
* 画笔宽度
*/
private float mStrokeWidth;
/**
* 边框颜色
*/
private int mBorderColor = 0xFF666666;
/**
* 输入的边框颜色
*/
private int mInputBorderColor = 0xFF1E90FF;
/**
* 焦点的边框颜色
*/
private int mFocusBorderColor;
/**
* 框的背景颜色
*/
private int mBoxBackgroundColor;
/**
* 框的圆角大小
*/
private float mBorderCornerRadius;
/**
* 框与框之间的间距大小
*/
private float mBorderSpacing;
/**
* 输入框宽度
*/
private float mBoxWidth;
/**
* 输入框高度
*/
private float mBoxHeight;
/**
* 允许输入的最大长度
*/
private int mMaxLength = 6;
/**
* 文本长度
*/
private int mTextLength;
/**
* 路径
*/
private Path mPath;
private RectF mRectF;
private float[] mRadiusFirstArray;
private float[] mRadiusLastArray;
/**
* 边框风格
*/
private @BorderStyle int mBorderStyle = BorderStyle.BOX;
/**
* 边框风格
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef({BorderStyle.BOX, BorderStyle.LINE})
public @interface BorderStyle {
/**
* 框
*/
int BOX = 0;
/**
* 线
*/
int LINE = 1;
}
/**
* 文本风格
*/
private @TextStyle int mTextStyle = TextStyle.PLAIN_TEXT;
/**
* 文本风格
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef({TextStyle.PLAIN_TEXT, TextStyle.CIPHER_TEXT})
public @interface TextStyle {
/**
* 明文
*/
int PLAIN_TEXT = 0;
/**
* 密文
*/
int CIPHER_TEXT = 1;
}
/**
* 密文掩码
*/
private String mCipherMask;
/**
* 是否是粗体
*/
private boolean isFakeBoldText;
private static final String DEFAULT_CIPHER_MASK = "*";
private boolean isDraw;
private OnTextInputListener mOnTextInputListener;
public SplitEditText(@NonNull Context context) {
this(context,null);
}
public SplitEditText(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs,android.R.attr.editTextStyle);
}
public SplitEditText(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context,attrs);
}
private void init(@NonNull Context context, @Nullable AttributeSet attrs){
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
mStrokeWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,1f,displayMetrics);
mBorderSpacing = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,8f,displayMetrics);
setPadding(0,0,0,0);
TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.SplitEditText);
final int count = a.getIndexCount();
for (int i = 0; i 1){
mCipherMask = mCipherMask.substring(0,1);
}
setBackground(null);
setCursorVisible(false);
setFilters(new InputFilter[]{new InputFilter.LengthFilter(mMaxLength)});
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
int width = w - getPaddingLeft() - getPaddingRight();
int height = h - getPaddingTop() - getPaddingBottom();
updateSizeChanged(width,height);
}
private void updateSizeChanged(int width,int height){
//如果框与框之间的间距小于0或者总间距大于控件可用宽度则将间距重置为0
if(mBorderSpacing width){
mBorderSpacing = 0;
}
//计算出每个框的宽度
mBoxWidth = (width - (mMaxLength - 1) * mBorderSpacing) / mMaxLength - mStrokeWidth;
mBoxHeight = height - mStrokeWidth;
}
@Override
protected void onDraw(Canvas canvas) {
//移除super.onDraw(canvas);不绘制EditText相关的
//绘制边框
drawBorders(canvas);
}
private void drawBorders(Canvas canvas){
isDraw = true;
//遍历绘制未输入文本的框边界
for(int i = mTextLength; i
//设置监听
splitEditText.setOnTextInputListener(new SplitEditText.OnTextInputListener(){
@Override
public void onTextInputChanged(String text, int length) {
//TODO 文本输入改变
}
@Override
public void onTextInputCompleted(String text) {
//TODO 文本输入完成
}
});