需求
最近项目里需要一个搜索框,其需求是这样的:当用户输入字符,将自动进行搜索,且搜索框中有字符时,显示一个删除icon,点击可以清空输入框。
分析
在这两个功能我们都需要监听EditText中输入字符的变化
1. 自动搜索:
这里我们可以采用接口回调的机制来完成。
2. 清空按钮:
首先判断EditText中的字符长度,如果字符的长度大于0且有焦点的时候让图标显示。
代码
- 布局文件 activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.dd.test.MainActivity" >
<com.dd.test.AutoSearchClearEditText
android:id="@+id/et"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_centerInParent="true"
android:layout_margin="5dp"
android:drawableRight="@drawable/delete"
android:padding="2dp" />
</RelativeLayout>
布局文件很简单,添加一个自定义的EditText,让其居中显示。其中android:drawleRight=”@drawable/delete”这里是为EditText的右侧显示一张清空图标。
- MainActivity.class
public class MainActivity extends Activity implements OnAutoSearchListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AutoSearchClearEditText et = (AutoSearchClearEditText) findViewById(R.id.et);
et.setOnAutoSearchListener(this);
}
@Override
public void search(String s) {
Toast.makeText(this, s, Toast.LENGTH_SHORT).show();
}
}
在这里MainActivity实现了一个叫OnAutoSearchListener的接口,这是自定义的一个回调接口,去实现自动搜索功能。search(String s) 是具体的实现方法,这里用了Toast来做测试。
- AutoSearchClearEditText.class
public class AutoSearchClearEditText extends EditText implements
OnFocusChangeListener, TextWatcher {
/** 清空图标 **/
private Drawable mClearDrawable;
/** 是否获得焦点 **/
private boolean hasFocus;
private OnAutoSearchListener onAutoSearchListener;
public interface OnAutoSearchListener {
public void search(String s);
}
public void setOnAutoSearchListener(
OnAutoSearchListener onAutoSearchListener) {
this.onAutoSearchListener = onAutoSearchListener;
}
public AutoSearchClearEditText(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
init();
}
public AutoSearchClearEditText(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.editTextStyle);
}
public AutoSearchClearEditText(Context context) {
this(context, null);
}
private void init() {
// 获取EditText最右侧的删除图标
mClearDrawable = this.getCompoundDrawables()[2];
if (mClearDrawable == null) {
mClearDrawable = getResources().getDrawable(R.drawable.delete);
}
mClearDrawable.setBounds(0, 0, mClearDrawable.getIntrinsicWidth(),
mClearDrawable.getIntrinsicHeight());
// 默认右侧删除图标不可见
setClearIconVisible(false);
setOnFocusChangeListener(this);
addTextChangedListener(this);
}
/**
*
* 设置右侧的删除图标是否可见
*
* @param visible
*/
public void setClearIconVisible(boolean visible) {
Drawable drawable = visible ? mClearDrawable : null;
setCompoundDrawables(getCompoundDrawables()[0],
getCompoundDrawables()[1], drawable, getCompoundDrawables()[3]);
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
@Override
public void afterTextChanged(Editable s) {
onAutoSearchListener.search(s.toString());
}
@Override
public void onFocusChange(View v, boolean hasFocus) {
this.hasFocus = hasFocus;
if (hasFocus) {
// 有焦点时焦点,当EditText里的内容长度>0时,显示图标,否则隐藏图标
setClearIconVisible(getText().length() > 0);
} else {
// 失去焦点,不显示清空图标
setClearIconVisible(false);
}
}
@Override
public void onTextChanged(CharSequence text, int start, int lengthBefore,
int lengthAfter) {
Log.i("tag", "textChanged");
if (hasFocus) {
setClearIconVisible(getText().length() > 0);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
if (getCompoundDrawables()[2] != null) {
// 判断是否触摸的为右侧图标
boolean touchable = event.getX() > (getWidth() - getTotalPaddingRight())
&& (event.getX() < (getWidth() + getTotalPaddingRight()));
if (touchable) {
// 如果触摸了右侧图标,清空文字
setText("");
}
}
}
return super.onTouchEvent(event);
}
}
从上图可以看出在init()方法中,mClearDrawable=getCompoundDrawables()[2]这一行是获取右侧图标,在这里我们看见getCompoundDrawables()是属于TextView的,而我们是继承EditText,为什么也可以这样用呢?
java.lang.Object
android.view.View
android.widget.TextView
android.widget.EditText
可以看出EditText是TextView的直接子类,所以可以直接用这个方法。
如何监听清空按钮是否被点击?这里覆盖了onTouchEvent(MotionEvent event)方法,通过判断touch的位置,去处理清空EditText
boolean touchable = event.getX() > (getWidth() - getTotalPaddingRight())
&& (event.getX() < (getWidth() + getTotalPaddingRight()));
getWidth()返回EditText的宽度,getTotalPaddingRight()返回的是EditText所有的右内边距,在这里我们只做了X轴上的判断。