序
在实际项目中我们经常看到这样的效果:
这就是我们常说的一键清除功能,Android并没有自带的API供我们使用,所以我们需要自己来编写,下面我将介绍常见实现方式.
1.常见的实现方式
目前主要实现的方式有2种:
EditText和Button的组合:
作者:yayun0516
标题:TextWatcher实现一键清空EditText
CSDN地址:http://blog.csdn.net/yayun0516/article/details/45953347在EditText的基础上进行拓展,俗称自定义View
作者:tangqing
标题:自定义View登录注册界面EditText-实现一键清空
地址:http://www.tqcto.com/article/mobile/2899.html
2种方式的优劣:
- 第一种方式:实现的方式简单,容易上手,但是增加了布局的复杂度
- 第二种方式:拓展EditText有一定的难度,可以使用起来会方便很多
2.自定义EditText实现一键清除功能
这里我会基于第二种实现方式一步步实现一键清除的EditText控件,相信你也会选择第二种实现方式吧,毕竟一切为了优化(偷懒)。
步骤1:创建一个控件继承于EditText并实现其构造方法
public class OneKeyClearEditText extends AppCompatEditText {
public OneKeyClearEditText(Context context) {
this(context, null);
}
public OneKeyClearEditText(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.editTextStyle);
}
public OneKeyClearEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
特别说明:R.attr.editTextStyle是源码中AppCompatEditText,由于使用了AppCompatEditText,所以我们需要依赖V7包,如果没有可以简信我,主题也需要是Theme.AppCompat,我这里为了看的清楚在AndroidManifest.xml中使用的主题是:Theme.AppCompat.Light。
步骤2:利用EditText的CompoundDrawables设置删除图标
private Drawable mClearDrawable;// 一键删除的按钮
private int colorAccent;//获得主题的颜色
@SuppressLint("InlinedApi")
public OneKeyClearEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray array = context.getTheme()
.obtainStyledAttributes(new int[] {android.R.attr.colorAccent});
colorAccent = array.getColor(0, 0xFF00FF);
array.recycle();
initClearDrawable(context);
}
@SuppressLint("NewApi")
private void initClearDrawable(Context context) {
mClearDrawable = getCompoundDrawables()[2];// 获取EditText的DrawableRight,假如没有设置我们就使用默认的图片
if (mClearDrawable == null) {
mClearDrawable = getResources().getDrawable(R.drawable.ic_delete_01, context.getTheme());
}
DrawableCompat.setTint(mClearDrawable, colorAccent);//设置删除按钮的颜色和TextColor的颜色一致
mClearDrawable.setBounds(0, 0, (int) getTextSize(), (int) getTextSize());//设置Drawable的宽高和TextSize的大小一致
setClearIconVisible(true);
}
/**
* 设置清除图标的显示与隐藏,调用setCompoundDrawables为EditText绘制上去
*
* @param visible
*/
private void setClearIconVisible(boolean visible) {
Drawable right = visible ? mClearDrawable : null;
setCompoundDrawables(getCompoundDrawables()[0], getCompoundDrawables()[1], right, getCompoundDrawables()[3]);
}
这一步主要是为了设置删除的图标,图标的颜色和colorAccent颜色一致,大小和TextSize一致,解决适配的问题。
先在布局设置colorAccent为红色
下面我们看看效果图:
效果还是不错的,到这里基本的UI样式就完成了,目前的控件还只是个“花瓶”,点击的方法还没有实现,接下来我们来实现点击的事件。
步骤3:实现删除图标的点击事件
我们知道Drawable本身没有点击事件,那么怎么办呢?这里从写了onTouch事件,然后模拟点击的区域(图标大小)来现实点击事件:
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mClearDrawable != null && event.getAction() == MotionEvent.ACTION_UP) {
int x = (int) event.getX();
// 判断触摸点是否在水平范围内
boolean isInnerWidth = (x > (getWidth() - getTotalPaddingRight()))
&& (x < (getWidth() - getPaddingRight()));
// 获取删除图标的边界,返回一个Rect对象
Rect rect = mClearDrawable.getBounds();
// 获取删除图标的高度
int height = rect.height();
int y = (int) event.getY();
// 计算图标底部到控件底部的距离
int distance = (getHeight() - height) / 2;
// 判断触摸点是否在竖直范围内(可能会有点误差)
// 触摸点的纵坐标在distance到(distance+图标自身的高度)之内,则视为点中删除图标
boolean isInnerHeight = (y > distance) && (y < (distance + height));
if (isInnerHeight && isInnerWidth) {
this.setText("");
Toast.makeText(getContext(), "一键清除", Toast.LENGTH_SHORT).show();//为了看清效果,测试
}
}
return super.onTouchEvent(event);
}
如果在EditText的范围和图标的范围之类,则表示有效。
下面看看效果:
到现在已经实现了一键清除功能了,可是功能还不够完善,我们需要在获取焦点并且有文字内容的时候才显示删除图标,下面继续开始优化。
步骤4: 对获取焦点已经文字输入进行监听优化体验
private boolean hasFocus;// 控件是否有焦点
private void initClearDrawable(Context context) {
...
setClearIconVisible(true);
// 设置焦点改变的监听
setOnFocusChangeListener(this);
// 设置输入框里面内容发生改变的监听
addTextChangedListener(this);
}
@Override
public void onFocusChange(View v, boolean hasFocus) {
this.hasFocus = hasFocus;
if (hasFocus) {
setClearIconVisible(getText().length() > 0);
} else {
setClearIconVisible(false);
}
}
/**
* 当输入框里面内容发生变化的时候回调的方法
*/
@Override
public void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
if (hasFocus) {
setClearIconVisible(text.length() > 0);
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// TODO Auto-generated method stub
}
@Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
}
基本代码就是这样,在获取焦点和文字输入之前判断是否有文字,从而决定是否显示图标。
** 效果:**
3.优化OneKeyClearEditText(一键删除控件)
上面基本是实现了一键清除的功能,对于图标的颜色,有些人可能需要自己定义,这里补充一个方法,
添加自定义属性
TypedArray array2 = context.obtainStyledAttributes(attrs,R.styleable.OneKeyClearEditText);
DrawableColor = array2.getColor(R.styleable.OneKeyClearEditText_deletecolor, colorAccent);
array2.recycle();
...
DrawableCompat.setTint(mClearDrawable, DrawableColor);// 设置删除按钮的颜色和TextColor的颜色一致
values-attrs.xml
使用
最后修改了游标的颜色,下面展示效果:(修改游标颜色:http://www.jianshu.com/p/660e93e1064f)
4.源码地址
http://download.csdn.net/detail/android_yh/9555816
5.感谢
参考地址:
- 作者:tangqing
标题:自定义View登录注册界面EditText-实现一键清空
地址:http://www.tqcto.com/article/mobile/2899.html - 作者:wikiday
标题:Android获取Theme的背景颜色
地址:http://blog.csdn.net/wikiday/article/details/8775837
6.总结
核心技术:
- 通过对CompoundDrawables的设置来确定删除图标
- 通过获得系统的Theme来关联删除图标和警告字体的颜色
- 通过DrawableCompat来渲染删除图标
- 通过对onTouch()的监听来模拟点击区域
- 通过对View.OnFocusChangeListener, TextWatcher的监听来优化用户体验
这是EditText系列的第三篇:
EditText(第1章)-游标位置和样式
EditText(第2章)-对hint进行整容
接下来我将实现EditText的密码可见与隐藏的功能。
如有侵权,麻烦简信我,我会及时修改。
如果这篇文章对你有帮助,请点下“喜欢”~