Android如何自定义EditText下划线?

曾经做过一个项目,其中登录界面的交互令人印象深刻。交互设计师给出了一个非常作的设计,要求做出包含根据情况可变色的下划线,左侧有可变图标,右侧有可变删除标志的输入框,如图

记录制作过程:

第一版本

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=""

1、onTouchEvent 当手机点击时,第一个先执行的函数,当点击右侧删除图标是清空 edittext
2、setStatus 根据不同的状态,左边的图片不一样
存在的问题: 这版本虽然基本功能已经实现,但是不符合需求,设计中要求文本框中无文字时,右侧删除按钮不显示,不点击删除按钮,删除按钮要保持灰色,点击时才可以变蓝色。

因此有了第二个版本

public class LineEditText extends EditText implements TextWatcher, <br /> 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

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

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

解决方法:

@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:延伸后的长度

最终效果:

以上就是Android实现自定义的EditText下划线的方法,希望对大家的学习有所帮助。

时间: 2024-09-20 14:33:06

Android如何自定义EditText下划线?的相关文章

Android如何自定义EditText下划线?_Android

曾经做过一个项目,其中登录界面的交互令人印象深刻.交互设计师给出了一个非常作的设计,要求做出包含根据情况可变色的下划线,左侧有可变图标,右侧有可变删除标志的输入框,如图 记录制作过程: 第一版本 public class LineEditText extends EditText { private Paint mPaint; private int color; public static final int STATUS_FOCUSED = 1; public static final in

Android 如何自定义EditText 下划线?

项目要求:  笔者曾经做过一个项目,其中登录界面的交互令人印象深刻.交互设计师给出了一个非常作的设计,要求做出包含根据情况可变色的下划线,左侧有可变图标,右侧有可变删除标志的输入框,如图  记录制作过程: 第一版本 public class LineEditText extends EditText { private Paint mPaint; private int color; public static final int STATUS_FOCUSED = 1; public stati

Android更改EditText下划线颜色样式的方法

前言 相信大家都知道,当使用AppCompatEditText(Edit Text)时,默认的下划线是跟随系统的#FF4081的颜色值的,通过改变这个值可以改变所有的颜色样式 有时候你想单独定义某一个界面的颜色样式,则可以这样做: 1.在你的build.gradle中添加最新的appcompat库 dependencies { compile 'com.android.support:appcompat-v7:X.X.X' // X.X.X 为最新的版本号 } 2.让你的activity继承an

巧妙利用CSS自定义网页下划线样式

css|网页 CSS为网页设计者们提供了丰富而灵活的页面元素表现形式的控制手段.但是,或许你可能注意到了,对于下划线,CSS提供的可选操作却不是很多.一般情况下,人们看到的下划线基本上都是横直线,缺少生气和灵动.不过,路并不是死的,通过一些绝妙的改造,我们还是可以做出富有创意的下划线来使页面更为美观. 这是一个自定义下划线的例子:自定义的下划线 .是不是很酷呢?除了能让你的网页呈现出一个与众不同的风格之外,它还能对于文档中不同的文字类型给与不同的视觉外观,起到提醒或者着重的作用. 下面我

Android 中美腻的下划线

本文讲的是Android 中美腻的下划线, 在过去两年里,我经常发现一些尝试去如何提高有关在网页中渲染下划线文本修饰的文章和库.此类问题也同样发生在Android(平台):下划线的文本修饰与降部相交.比较下Android当前如何绘制下划线文本(上图)以及它的替代方案(下图): 你更喜欢哪一种? 尽管我完全认可这些努力,但是我从未喜欢过任何公开的解决方法.目前最新的技术(追求艺术般的状态)-毫无疑问地会强迫开发者们受限于CSS-似乎是通过绘制线性渐变以及多重阴影(我见过多达12层的!)来实现的.这

巧用CSS自定义网页下划线样式

CSS为网页设计者们提供了丰富而灵活的页面元素表现形式的控制手段.但是,或许你可能注意到了,对于下划线,CSS提供的可选操作却不是很多.一般情况下,人们看到的下划线基本上都是横直线,缺少生气和灵动.不过,路并不是死的,通过一些绝妙的改造,我们还是可以做出富有创意的下划线来使页面更为美观. 这是一个自定义下划线的例子:自定义的下划线 .是不是很酷呢?除了能让你的网页呈现出一个与众不同的风格之外,它还能对于文档中不同的文字类型给与不同的视觉外观,起到提醒或者着重的作用. 下面我们就来一起学习如何自定

android里TextView加下划线的几种方法总结

如果是在资源文件里: <resources> <string name="hello"><u>phone:0123456</u></string> <string name="app_name">MyLink</string> </resources> 如果是代码里: TextView textView = (TextView)findViewById(R.id.tv_t

Android UI自定义Spinner下拉框(用popuwindow实现)

Android提供的Spinner可能会因为项目的需求而不能使用,这时候我们往往会自己定义一个.最近在做的项目遇到了这种情况,自己用PopuWindow定义了一个下拉框的样式,记录下来留着以后参考~先上效果图~ 点击头部右边的按钮,弹出长度与上方的控件长度一致的下拉框. 下面来说说是如何实现的.定义出第一个图片的布局和弹出框(一个listView)的布局,程序的源码里面有,这里就不在多说了~ListView需要自己定义一个MyspinnerAdapter~做好这些准备之后,就是弹出框的实现了~

Android自定义EditText右侧带图片控件_Android

前言 最近项目做用户登录模块需要一个右边带图片的EditText,图片可以设置点击效果,所以就查资料做了一个自定义EditText出来,方便以后复用. 原理 下面是自定义EditText的代码,具体难点是要实现图片的点击监听,因为谷歌官方至今没有给出一个直接实现EditText里面图片的监听API.我的做法是整个控件绑定一个OnTouchListener,然后监测点击事件,检测点击位置的X坐标是否在图片的覆盖范围内(下面getCompoundDrawables()[2]里面的2是代表图片在Edi