先上效果:
说明:
图中的EditText能够在失去焦点后验证输入框中的文本是否与正则表达式匹配,这里我设置的是5位整数(\d{5}),当输入110时,不匹配,边框变红并抖动,文本清除(gif中白色文本是因为录制的问题,实际文本已清除);输入12306,匹配,边框变绿。
实现方式
继承EditText,实现构造方法
注意构造方法中要传入官方的属性值,否则很多EditText属性不能在XML里面定义,并且EditText获取焦点后不会弹出软键盘。
public WarnningEditText(Context context) {
this(context, null);
}
public WarnningEditText(Context context, AttributeSet attrs) {
//这里构造方法也很重要,不加这个很多属性不能在XML里面定义
this(context, attrs, android.R.attr.editTextStyle);
}
public WarnningEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
//获取属性值
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.WarnningEditText);
borderColor = ta.getColor(R.styleable.WarnningEditText_borderColor, Color.GRAY);
correctBorderColor = ta.getColor(R.styleable.WarnningEditText_correctBorderColor, Color.GREEN);
warinningBorderColor = ta.getColor(R.styleable.WarnningEditText_warinningBorderColor, Color.RED);
borderWidth = ta.getDimensionPixelSize(R.styleable.WarnningEditText_borderWidth, 2);
angleRadius = ta.getDimensionPixelSize(R.styleable.WarnningEditText_angleRadius, 5);
ta.recycle();
init();
}
重写onDraw,绘制边框
注意边框的颜色不要设置常量
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//确定View宽高
width = getWidth();
height = getHeight();
//边框的坐标范围
r = new RectF(dp2px(borderWidth), dp2px(borderWidth), width - dp2px(borderWidth), height - dp2px(borderWidth));
//设置画布绘图无锯齿
canvas.setDrawFilter(mPaintFlagsDrawFilter);
drawBorder(canvas);
}
/**
* 绘制边框
*/
private void drawBorder(Canvas canvas) {
canvas.save();
canvas.drawRoundRect(r, dp2px(angleRadius), dp2px(angleRadius), borderPaint);//绘制圆角矩形
canvas.restore();
}
重写onFocusChanged,监听焦点变化
获取焦点后,边框就设置为默认的颜色(灰色),失去焦点后,会判断是否匹配正则表达式。
/**
* 焦点变化
*/
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
super.onFocusChanged(focused, direction, previouslyFocusedRect);
if (focused) {
borderPaint.setColor(borderColor);
postInvalidate();
} else {
if (!this.getText().toString().equals("")) {
if (regex != null) {
if (!this.getText().toString().matches(regex)) {
inputError();
onInputMatchListener.onInputWrong();
Log.v(TAG, "wrong input");
} else {
borderPaint.setColor(correctBorderColor);
postInvalidate();
onInputMatchListener.onInputCorrect();
Log.v(TAG, "good input");
}
} else {
Log.e(TAG, "no regex");
}
} else {
Log.e(TAG, "no input");
}
}
}
创建接口
创建一个OnInputMatchListener的接口,内含onInputWrong和onInputCorrect两个抽象方法,分别在判断文本不匹配正则表达式和匹配表达式时回调,回调地址在上面的代码中。
public interface OnInputMatchListener {
void onInputWrong();
void onInputCorrect();
}
使用
在布局文件中使用:
<com.example.ast.dashboard.WarnningEditText
android:id="@+id/warnning_et2"
android:layout_width="200dp"
android:layout_height="40dp"
android:background="@null"
android:layout_centerHorizontal="true"
android:paddingLeft="10dp"
android:textCursorDrawable="@drawable/color_cursor" />
设置接口:
WarnningEditText warnningEditText = (WarnningEditText) findViewById(R.id.warnning_et);
warnningEditText.setRegex("^\\d{5}$");
warnningEditText.setOnInputMatchListener(new WarnningEditText.OnInputMatchListener() {
@Override
public void onInputWrong() {
Toast.makeText(MainActivity.this, "输入错误", Toast.LENGTH_SHORT).show();
}
@Override
public void onInputCorrect() {
Toast.makeText(MainActivity.this, "输入正确", Toast.LENGTH_SHORT).show();
}
});
要注意的是:
-
android:paddingLeft="10dp"
让文本不是从左边框开始,而是左边框靠左一点。
- 组件的父布局可以加上
android:focusable="true"
android:focusableInTouchMode="true"
这样可以避免EditText默认获取焦点。
3.重中之重:要加上android:background="@null"
。
我们知道android:background="@null"可以去掉EditText默认样式的下划线:
但在我自定义EditText的时候,我的边框是根据组件的宽高贴着边缘画的,当组件高度大于42dp时,一切正常:
当高度小于42时,比如30dp,边框上部就会缺失,或者说边框绘制
就会从组件外部开始:
想要解决问题就是要在布局文件加入:
android:background="@null
至于为什么这样我也不知道,还请大神指点一番。
这个组件的不太好用,不过还是贴一下源码: