Android系统自带的EditText,虽然功能是实现了,但是总是感觉给人是缺胳膊少腿的。你就不能像ios一样,输入框的末尾加个小叉叉吗?通常Android要实现这个功能,很常见的是使用组合布局实现,但是这样不好!原因可见这篇文章Android 性能优化之布局优化。还有就是利用EditText的drawableRight属性添加一张图片实现,但是通常又要UI妹妹切一张图甚是麻烦!于是,我觉得直接用Java代码画出一个叉叉,实现一键清空的EdidText不就好了嘛 。高仿京东首页搜索框!
效果图:
首先说明下我们的思路:自定义一个Drawable类用于画叉叉,然后充当自定义的EditText的drawableRight,最后添加相应的事件监听即可!
1.创造我们需要的Drawable,命明为DeleteDrawable。
public class DeleteDrawable extends Drawable{
@Override
public void draw(Canvas canvas) { }
@Override
public void setAlpha(int alpha) { }
@Override
public void setColorFilter(ColorFilter colorFilter) { }
@Override
public int getOpacity() {return PixelFormat.TRANSLUCENT;}
}
可见继承自Drawable一共必须要实现 上述四个方法,setAlpha和setColorFiler是设置透明度和设置颜色过滤器,通常利用自定义Drawable里面的Paint调用对应的api设置即可。getOpacity()是关于透明度的,通常有PixelFormat.TRANSLUCENT、PixelFormat.TRANSPARENT、PixelFormat.OPAQUE三个值,前两种支持透明度格式,只是一个是支持半透明,一个支持全透明。最后一个不支持透明。这四个方法中最重要的就是draw方法了,它是我们画叉叉的关键。里面的Canvas参数是控件的OnDraw方法里面传下来的!如下DeleteDrawable的全部代码:
class DeleteDrawable extends Drawable{
private float mSize;
private Paint mPaint;
public DeleteDrawable(float size){
mSize=size;
init();
}
private void init(){
mPaint=new Paint();
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
}
@Override
public void draw(Canvas canvas) {
float space=mSize/5;
float centerX=mSize/2;
float centerY=mSize/2;
float width=mSize/10;
mPaint.setColor(mDeleteBgColor);//灰色
canvas.drawCircle(centerX,centerY,centerX,mPaint);
mPaint.setColor(Color.WHITE);
canvas.save();
canvas.rotate(45,centerX,centerY);
canvas.drawRect(centerX-width/2,space,centerX+width/2,mSize-space,mPaint); //画矩形线
canvas.restore();
canvas.rotate(135,centerX,centerY);
canvas.drawRect(centerX-width/2,space,centerX+width/2,mSize-space,mPaint); //画矩形线
}
@Override
public void setAlpha(int alpha) {
mPaint.setAlpha(alpha);
}
@Override
public void setColorFilter(ColorFilter cf) {mPaint.setColorFilter(cf);}
@Override
public int getOpacity() {
return PixelFormat.OPAQUE;
}
}
其中成员变量mSize便是小叉叉圆圈所在的外切正方形的边长,同时也是小叉叉圆圈的直径。灰色圆圈里面的2条叉线是成90度相交的。
canvas.rotate(45,centerX,centerY);
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if(mDeleteDrawable==null){
float length=getHeight()*0.45f;
mDeleteDrawable=new DeleteDrawable(length);
mDeleteDrawable.setBounds(0,0,(int)length,(int)length);
if(textAmount>0){
setCompoundDrawables(null,null,mDeleteDrawable,null);
}
}
}
textAmount表示EdiText中的字符数目。setCompoundDrawables(null,null,mDeleteDrawable,null);给EditText右边缘设置Drawable。
再就是afterTextChanged中的代码:
@Override
public void afterTextChanged(Editable s) {
textAmount=s.toString().trim().length();
//优化渲染,invalidate消耗性能
if((lastTextAmount==0&&textAmount>0)||(lastTextAmount>0&&textAmount==0)){
if(textAmount>0&&mDeleteDrawable!=null){
mCanClean=true;
setCompoundDrawables(null,null,mDeleteDrawable,null);
}else{
mCanClean=false;
setCompoundDrawables(null,null,null,null);
}
invalidate();
}
lastTextAmount=textAmount;
}
mCanClean是Boolean类型的值,表示小叉叉是否出现。setCompoundDrawables(null,null,null,null);小叉叉消失,if((lastTextAmount==0&&textAmount>0)||(lastTextAmount>0&&textAmount==0)),文字从无到有或者从有到无才应该显示或者让小叉叉消失,设置完成之后需要调用invalidate()方法,让控件重绘,进而调用OnDraw方法。invalidate()方法相当的消耗性能所以需要上面的判断来优化渲染。
最后,我们需要给小叉叉提供点击事件:
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
switch (event.getAction()) {
//手指抬起
case MotionEvent.ACTION_UP:{
int x=(int)event.getX();
if(x>(getWidth()-getHeight()*0.9)&&mCanClean){
setText("");
if(mDeleteDrawable!=null){
mDeleteDrawable.setVisible(false,true);
}
}
return true;
}
default:
break;
}
return true;
}
手指抬起的时候清空EditText,为何要乘以0.9,因为小叉叉的外切正方形的边长是getHeight()*0.45,这里设置成其2倍是为了,增大点击区域,提升体验!
到这里自定义一键清空的EditText基本完成,但是一个好的控件是高度支持定制化的,所有我们需要把小叉叉的背景颜色图,以及EditText的背景的颜色,圆角弧度等都抽出去。做成自定义属性,比较简单就不多做赘述了。最后给出了CleanEditText的全部代码,大家可以下载下来看看,欢迎大家,留言批评,共同探讨,共同进步!
CleanEditText的全部代码:CleanEditText