用户点击搜索Action跳转搜索界面,根据用户输入文字,拦截软键盘最后一个键进行搜索,并添加到 历史纪录,搜索编辑框根据文字显示一键删除文字内容按钮,历史纪录列表提供一键清空功能,历史纪录支持item点击搜索,删除单条历史纪录。根据搜索结果展示列表,支持刷新和分页加载更多
根据需求做了一个大概的分析草图(看不清楚还请见谅,了解个大概结构就好),搜索activity嵌入两个碎片HistoryFragment.SearchLisFragment,和一个进度相关的LoadFragment
从实现来说头部头部SearchView控件是一个自定义的LinearLayout,左侧一个ImageView,右侧一个TextView,中间的搜索EditText需要自定义,在自定义EditText时候遇到的第一个坑:无法接受键盘事件,解决方案如下:
setFocusableInTouchMode(true);
setFocusable(true);
根据EditText文字长度改变是否显示delete图标,addTextChangedListener可以满足我们需求,只需要在afterTextChanged方法控制drawable visibility
//设置删除图片
private void setDrawable() {
if(length() < 1)
setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
else
setCompoundDrawablesWithIntrinsicBounds(null, null, deleteDrawable, null);
}
删除图标的显示搞定了,面临的问题点击删除按钮清楚EditText内容,这里可以根据touch范围判断触摸区域选择拦截触摸事件
// 处理删除事件
@Override
public boolean onTouchEvent(MotionEvent event) {
if (deleteDrawable != null && event.getAction() == MotionEvent.ACTION_UP) {
int eventX = (int) event.getRawX();
int eventY = (int) event.getRawY();
Rect rect = new Rect();
getGlobalVisibleRect(rect);
rect.left = rect.right - deleteDrawable.getIntrinsicWidth();
if(rect.contains(eventX, eventY)) {
setText("");
return true;
}
}
return super.onTouchEvent(event);
}
一生二,二生三生万物,透过该控件我们可以学到很多东西,比如密码输入框,带眼的图标点击可以切换密码显示类型,也就是一个InputType的changed,再比如用户账号弹出下拉框选择曾用名,当然这里就不是在空间内部处理事件,需要一个interface回调到Activity里面处理弹出dialog.对于这一块的我们可以整理出一个EditText系列的库,从抽象CustomEditText 到具体的Impl,以便于我们敏捷开发。
扯远了一点,现在回到正题,SearchView的组装又遇到一个问题,软键盘输入完成后监听事件,需求:要显示label搜索,点击后直接搜索,这里用到的知识主要是EditorInfo(EditorInfo更的资料自己百度)
setImeActionLabel("搜索", EditorInfo.IME_ACTION_SEARCH);
setImeOptions(EditorInfo.IME_ACTION_SEARCH);
跟踪源码发现监听事件setOnEditorActionListener方法,根据actionId 选择拦截
searchEditText.setOnEditorActionListener(new OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
String result = searchEditText.getText().toString().trim();
if(result==null||result.equals("")||result.equals("null")){
Toast.makeText(getContext(), "搜索内容不能为空!", Toast.LENGTH_SHORT).show();
}else if(getOnHisterListener()!=null){
searchEditText.setText("");
getOnHisterListener().onSearch(result);
}
}
return false;
}
});
对于搜索我们需要涉及到的功能主要有以下几点:
定义核心接口OnHisterListener
public interface OnHisterListener{
void deleteItem(String searchName);
void clearCacheHistoryRecord();
void onSearch(String searchName);
void addHistoryRecord(String searchName);
void onSearchBack();
}
根据界面展示,历史纪录界面布局ScrollView+ListView(禁止滑动),ForbidScrollListview 诞生
public class ForbidScrollListview extends ListView{
public ForbidScrollListview(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public ForbidScrollListview(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public ForbidScrollListview(Context context) {
this(context,null,0);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
至于进度的实现我采用官方推荐DialogFragment,转圈进度采用github开源项目CircularProgressView,DialogFragment简单说一下基本的参数配置:
setCancelable(false);//外部系统返回键屏蔽
getDialog().setContentView(converView);
getDialog().setCanceledOnTouchOutside(false);//界面外部区域触摸dialog无法消失
getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));//背景边框透明
这个demo 只是一个参考,具体问题具体分析,网络数据请求根据自己需求改写,adapter适配也是如此,另外我的接口设计也有不合理之处,缓存操作和网络请求接口应该分开,不过惫懒的我只能纸上谈兵,EditTextCustom库系列控件没完成是我的遗憾,我也就是几分钟的热度,了解了具体实现原理后就没了激情,如果你有开源类似的库,欢迎推荐,在此鸣谢!