自定义EditText :下划线,左侧有可变图标,右侧有可变删除标志


项目要求:1做出包含根据情况可变色的下划线,左侧有可变图标,右侧有可变删除标志的edittext,如图



记录制作过程:

第一版本:


[java] view plain copy
public class LineEditText extends EditText {  
    private Paint mPaint;  
    private int color;  
    public static final int STATUS_FOCUSED = 1;  
    public static final int STATUS_UNFOCUSED = 2;  
    public static final int STATUS_ERROR = 3;  
    private int status = 2;  
    private Drawable del_btn;  
    private Drawable del_btn_down;  
    private int focusedDrawableId = R.drawable.user_select;// 默认的  
    private int unfocusedDrawableId = R.drawable.user;  
    private int errorDrawableId = R.drawable.user_error;  
    Drawable left = null;  
    private Context mContext;  
  
    public LineEditText(Context context) {  
        super(context);  
        mContext = context;  
        init();  
    }  
  
    public LineEditText(Context context, AttributeSet attrs) {  
        super(context, attrs);  
        mContext = context;  
        init();  
  
    }  
  
    public LineEditText(Context context, AttributeSet attrs, int defStryle) {  
        super(context, attrs, defStryle);  
        mContext = context;  
        TypedArray a = context.obtainStyledAttributes(attrs,  
                R.styleable.lineEdittext, defStryle, 0);  
        focusedDrawableId = a.getResourceId(  
                R.styleable.lineEdittext_drawableFocus, R.drawable.user_select);  
        unfocusedDrawableId = a.getResourceId(  
                R.styleable.lineEdittext_drawableUnFocus, R.drawable.user);  
        errorDrawableId = a.getResourceId(  
                R.styleable.lineEdittext_drawableError, R.drawable.user_error);  
        a.recycle();  
        init();  
    }  
  
    /** 
     * 2014/7/31 
     *  
     * @author Aimee.ZHANG 
     */  
    private void init() {  
        mPaint = new Paint();  
        // mPaint.setStyle(Paint.Style.FILL);  
        mPaint.setStrokeWidth(3.0f);  
        color = Color.parseColor("#bfbfbf");  
        setStatus(status);  
        del_btn = mContext.getResources().getDrawable(R.drawable.del_but_bg);  
        del_btn_down = mContext.getResources().getDrawable(R.drawable.del_but_bg_down);  
        addTextChangedListener(new TextWatcher() {  
  
            @Override  
            public void onTextChanged(CharSequence arg0, int arg1, int arg2,  
                    int arg3) {  
            }  
  
            @Override  
            public void beforeTextChanged(CharSequence arg0, int arg1,  
                    int arg2, int arg3) {  
            }  
  
            @Override  
            public void afterTextChanged(Editable arg0) {  
                setDrawable();  
            }  
        });  
        setDrawable();  
    }  
  
    @Override  
    protected void onDraw(Canvas canvas) {  
        super.onDraw(canvas);  
        mPaint.setColor(color);  
        canvas.drawLine(0, this.getHeight() - 1, this.getWidth(),  
                this.getHeight() - 1, mPaint);  
    }  
  
    // 删除图片  
    private void setDrawable() {  
        if (length() < 1) {  
            setCompoundDrawablesWithIntrinsicBounds(left, null, del_btn, null);  
        } else {  
            setCompoundDrawablesWithIntrinsicBounds(left, null, del_btn_down,null);  
        }  
    }  
  
    // 处理删除事件  
    @Override  
    public boolean onTouchEvent(MotionEvent event) {  
        if (del_btn_down != null && event.getAction() == MotionEvent.ACTION_UP) {  
            int eventX = (int) event.getRawX();  
            int eventY = (int) event.getRawY();  
            Log.e("eventXY", "eventX = " + eventX + "; eventY = " + eventY);    
            Rect rect = new Rect();  
            getGlobalVisibleRect(rect);  
            rect.left = rect.right - 50;  
            if (rect.contains(eventX, eventY))  
            setText("");  
        }  
        return super.onTouchEvent(event);  
    }  
  
    public void setStatus(int status) {  
        this.status = status;  
          
  
        if (status == STATUS_ERROR) {  
            try {  
                left = getResources().getDrawable(errorDrawableId);  
            } catch (NotFoundException e) {  
                e.printStackTrace();  
            }  
            setColor(Color.parseColor("#f57272"));  
        } else if (status == STATUS_FOCUSED) {  
            try {  
                left = getResources().getDrawable(focusedDrawableId);  
            } catch (NotFoundException e) {  
                e.printStackTrace();  
            }  
            setColor(Color.parseColor("#5e99f3"));  
        } else {  
            try {  
                left = getResources().getDrawable(unfocusedDrawableId);  
            } catch (NotFoundException e) {  
                e.printStackTrace();  
            }  
            setColor(Color.parseColor("#bfbfbf"));  
        }  
        if (left != null) {  
//          left.setBounds(0, 0, 30, 40);  
//          this.setCompoundDrawables(left, null, null, null);  
            setCompoundDrawablesWithIntrinsicBounds(left,null,del_btn,null);  
        }  
        postInvalidate();  
    }  
  
    public void setLeftDrawable(int focusedDrawableId, int unfocusedDrawableId,  
            int errorDrawableId) {  
        this.focusedDrawableId = focusedDrawableId;  
        this.unfocusedDrawableId = unfocusedDrawableId;  
        this.errorDrawableId = errorDrawableId;  
        setStatus(status);  
    }  
  
    @Override  
    protected void onFocusChanged(boolean focused, int direction,  
            Rect previouslyFocusedRect) {  
        super.onFocusChanged(focused, direction, previouslyFocusedRect);  
        if (focused) {  
            setStatus(STATUS_FOCUSED);  
        } else {  
            setStatus(STATUS_UNFOCUSED);  
        }  
    }  
  
    @Override  
    protected void finalize() throws Throwable {  
        super.finalize();  
    };  
  
    public void setColor(int color) {  
        this.color = color;  
        this.setTextColor(color);  
        invalidate();  
    }  
}  
效果图:



代码解释:
 变量名 STATUS_FOCUSED,STATUS_UNFOCUSED,STATUS_ERROR 标示了三种状态,选中状况为蓝色,未选中状态为灰色,错误状态为红色。focusedDrawableId   unfocusedDrawableId  errorDrawableId 存放三种状态的图片,放置于最左侧。

canvas.drawLine(0, this.getHeight() - 1, this.getWidth(),this.getHeight() - 1, mPaint);     //画editText最下方的线
setCompoundDrawablesWithIntrinsicBounds(left, null, del_btn, null);  //放置左边的和右边的图片(左,上,右,下)
相当于 android:drawableLeft=""  android:drawableRight=""  

onTouchEvent  当手机点击时,第一个先走的函数,当点击右侧删除图标是清空edittext
setStatus  更具不同的状态,左边的图片不一样



存在的问题:

这版本虽然基本功能已经实现,但是不符合需求,设计中要求文本框中无文字时,右侧删除按钮不显示,不点击删除按钮,删除按钮要保持灰色,点击时才可以变蓝色。因此有了第二个版本


[java] view plain copy
public class LineEditText extends EditText  implements TextWatcher,    
OnFocusChangeListener{  
    private Paint mPaint;  
    private int color;  
    public static final int STATUS_FOCUSED = 1;  
    public static final int STATUS_UNFOCUSED = 2;  
    public static final int STATUS_ERROR = 3;  
    private int status = 2;  
    private Drawable del_btn;  
    private Drawable del_btn_down;  
    private int focusedDrawableId = R.drawable.user_select;// 默认的  
    private int unfocusedDrawableId = R.drawable.user;  
    private int errorDrawableId = R.drawable.user_error;  
    Drawable left = null;  
    private Context mContext;  
    /**  
     * 是否获取焦点,默认没有焦点  
     */    
    private boolean hasFocus = false;    
    /**  
     * 手指抬起时的X坐标  
     */    
    private int xUp = 0;    
  
    public LineEditText(Context context) {  
        super(context);  
        mContext = context;  
        init();  
    }  
  
    public LineEditText(Context context, AttributeSet attrs) {  
        super(context, attrs);  
        mContext = context;  
        init();  
  
    }  
  
    public LineEditText(Context context, AttributeSet attrs, int defStryle) {  
        super(context, attrs, defStryle);  
        mContext = context;  
        TypedArray a = context.obtainStyledAttributes(attrs,  
                R.styleable.lineEdittext, defStryle, 0);  
        focusedDrawableId = a.getResourceId(  
                R.styleable.lineEdittext_drawableFocus, R.drawable.user_select);  
        unfocusedDrawableId = a.getResourceId(  
                R.styleable.lineEdittext_drawableUnFocus, R.drawable.user);  
        errorDrawableId = a.getResourceId(  
                R.styleable.lineEdittext_drawableError, R.drawable.user_error);  
        a.recycle();  
        init();  
    }  
  
    /** 
     * 2014/7/31 
     *  
     * @author Aimee.ZHANG 
     */  
    private void init() {  
        mPaint = new Paint();  
        // mPaint.setStyle(Paint.Style.FILL);  
        mPaint.setStrokeWidth(3.0f);  
        color = Color.parseColor("#bfbfbf");  
        setStatus(status);  
        del_btn = mContext.getResources().getDrawable(R.drawable.del_but_bg);  
        del_btn_down = mContext.getResources().getDrawable(R.drawable.del_but_bg_down);  
        addListeners();  
        setCompoundDrawablesWithIntrinsicBounds(left, null, null, null);  
    }  
  
    @Override  
    protected void onDraw(Canvas canvas) {  
        super.onDraw(canvas);  
        mPaint.setColor(color);  
        canvas.drawLine(0, this.getHeight() - 1, this.getWidth(),  
                this.getHeight() - 1, mPaint);  
    }  
  
    // 删除图片  
//  private void setDrawable() {  
//      if (length() < 1) {  
//          setCompoundDrawablesWithIntrinsicBounds(left, null, null, null);  
//      } else {  
//          setCompoundDrawablesWithIntrinsicBounds(left, null, del_btn,null);  
//      }  
//  }  
  
    // 处理删除事件  
    @Override  
    public boolean onTouchEvent(MotionEvent event) {  
        if (del_btn != null && event.getAction() == MotionEvent.ACTION_UP) {  
            // 获取点击时手指抬起的X坐标    
            xUp = (int) event.getX();    
            Log.e("xUp", xUp+"");    
            /*Rect rect = new Rect(); 
            getGlobalVisibleRect(rect); 
            rect.left = rect.right - 50;*/  
              // 当点击的坐标到当前输入框右侧的距离小于等于getCompoundPaddingRight()的距离时,则认为是点击了删除图标    
            if ((getWidth() - xUp) <= getCompoundPaddingRight()) {    
                if (!TextUtils.isEmpty(getText().toString())) {  
                    setText("");    
                }    
            }  
        }else if(del_btn != null && event.getAction() == MotionEvent.ACTION_DOWN && getText().length()!=0){  
            setCompoundDrawablesWithIntrinsicBounds(left,null,del_btn_down,null);  
        }else if(getText().length()!=0){  
            setCompoundDrawablesWithIntrinsicBounds(left,null,del_btn,null);  
        }  
        return super.onTouchEvent(event);  
    }  
  
    public void setStatus(int status) {  
        this.status = status;  
          
  
        if (status == STATUS_ERROR) {  
            try {  
                left = getResources().getDrawable(errorDrawableId);  
            } catch (NotFoundException e) {  
                e.printStackTrace();  
            }  
            setColor(Color.parseColor("#f57272"));  
        } else if (status == STATUS_FOCUSED) {  
            try {  
                left = getResources().getDrawable(focusedDrawableId);  
            } catch (NotFoundException e) {  
                e.printStackTrace();  
            }  
            setColor(Color.parseColor("#5e99f3"));  
        } else {  
            try {  
                left = getResources().getDrawable(unfocusedDrawableId);  
            } catch (NotFoundException e) {  
                e.printStackTrace();  
            }  
            setColor(Color.parseColor("#bfbfbf"));  
        }  
        if (left != null) {  
//          left.setBounds(0, 0, 30, 40);  
//          this.setCompoundDrawables(left, null, null, null);  
            setCompoundDrawablesWithIntrinsicBounds(left,null,null,null);  
        }  
        postInvalidate();  
    }  
  
    public void setLeftDrawable(int focusedDrawableId, int unfocusedDrawableId,  
            int errorDrawableId) {  
        this.focusedDrawableId = focusedDrawableId;  
        this.unfocusedDrawableId = unfocusedDrawableId;  
        this.errorDrawableId = errorDrawableId;  
        setStatus(status);  
    }  
     private void addListeners() {    
            try {    
                setOnFocusChangeListener(this);    
                addTextChangedListener(this);    
            } catch (Exception e) {    
                e.printStackTrace();    
            }    
        }    
    @Override  
    protected void onFocusChanged(boolean focused, int direction,  
            Rect previouslyFocusedRect) {  
        super.onFocusChanged(focused, direction, previouslyFocusedRect);  
        this.hasFocus=focused;  
        if (focused) {  
            setStatus(STATUS_FOCUSED);  
        } else {  
            setStatus(STATUS_UNFOCUSED);  
            setCompoundDrawablesWithIntrinsicBounds(left,null,null,null);  
        }  
    }  
  
    @Override  
    protected void finalize() throws Throwable {  
        super.finalize();  
    };  
  
    public void setColor(int color) {  
        this.color = color;  
        this.setTextColor(color);  
        invalidate();  
    }  
  
      
  
    @Override  
    public void afterTextChanged(Editable arg0) {  
        // TODO Auto-generated method stub  
        postInvalidate();  
    }  
  
    @Override  
    public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,  
            int arg3) {  
        // TODO Auto-generated method stub  
         if (TextUtils.isEmpty(arg0)) {    
             // 如果为空,则不显示删除图标    
             setCompoundDrawablesWithIntrinsicBounds(left, null, null, null);    
         } else {    
             // 如果非空,则要显示删除图标    
             setCompoundDrawablesWithIntrinsicBounds(left, null, del_btn, null);    
         }    
    }  
    @Override  
     public void onTextChanged(CharSequence s, int start, int before, int after) {    
       if (hasFocus) {    
           if (TextUtils.isEmpty(s)) {    
               // 如果为空,则不显示删除图标    
               setCompoundDrawablesWithIntrinsicBounds(left, null, null, null);    
           } else {    
               // 如果非空,则要显示删除图标    
               setCompoundDrawablesWithIntrinsicBounds(left, null, del_btn, null);    
           }    
       }    
   }  
  
    @Override  
    public void onFocusChange(View arg0, boolean arg1) {  
        // TODO Auto-generated method stub  
        try {    
            this.hasFocus = arg1;    
        } catch (Exception e) {    
            e.printStackTrace();    
        }    
    }    
}  

效果图:


比较关键的方法是:onTouchEvent

当进入界面,点击输入框,要判断输入框中是否已有文字,如果有则显示灰色的删除按钮,如果没有则不显示,如果点击了删除按钮,删除按钮变蓝色


存在的问题:

这个版本依旧存在问题,就是输入长度超过输入框,所画的线不会延伸,如图


解决办法:

[java] view plain copy
@Override  
    protected void onDraw(Canvas canvas) {  
        super.onDraw(canvas);  
        mPaint.setColor(color);  
        int x=this.getScrollX();  
        int w=this.getMeasuredWidth();  
        canvas.drawLine(0, this.getHeight() - 1, w+x,  
                this.getHeight() - 1, mPaint);  
    }  

w:获取控件长度
X:延伸后的长度

最终效果:









参考文献:

http://www.oschina.net/question/54100_32466
http://www.oschina.net/android/125/attrs-xml
http://blog.csdn.net/llew2011/article/details/28909193
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2013/0307/986.html

http://blog.csdn.net/zwx622/article/details/38340991#comments 原文链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值