自定义的一个App搜索框
来源:互联网 发布:全国电视台直播软件 编辑:程序博客网 时间:2024/06/05 13:32
模仿风行App实现的一个自定义搜索框类库,实现了监听文本框输入的变化,清空文本框内容,提示列表,热搜列表、自动保存搜索记录等功能。
实现效果如下:
类库的主要代码如下:
分别是
- CharacterParser:汉字转换为拼音的工具类
- CommonAdapter:热搜列表和搜索历史列表的Adapter
- HintAdapter:提示列表的Adapter
- NoScrollGridView:自定义的GridView,解决只显示一行的问题
- SearchALG:搜索匹配的算法
- SearchView:自定义的View,继承LinearLayout,实现了搜索的功能
下面将主要代码粘出来,文档最后会附上下载地址
//继承LinearLayout,实现构造方法 public SearchView(Context context, AttributeSet attrs) { super(context, attrs); this.context = context; LayoutInflater.from(context).inflate(R.layout.search_view, this); initView(); }
搜索的历史纪录用sp保存
/** * 用SP存储保存搜索的历史纪录 */ if (sp == null) { sp = context.getSharedPreferences("config", Context.MODE_PRIVATE); }
外部可通过keepSearchHistory(true/false)方法设置是否保存搜索记录
/** * 设置是否自动保存搜索记录 * * @param isAutoKeep */public void keepSearchHistory(boolean isAutoKeep) { this.isAutoKeep = isAutoKeep; //如果没有设为自动保存,则返回 if (!isAutoKeep) { return; } String history_search_datas = sp.getString("history_search_datas", ""); if (!TextUtils.isEmpty(history_search_datas)) {//不为空 historySearchDatas = new Gson().fromJson(history_search_datas, List.class); } else {//SP中没有数据,直接返回 return; } if (historyAdapter == null && isAutoKeep) { ll_search_history.setVisibility(VISIBLE); historyAdapter = new CommonAdapter(context, historySearchDatas); gv_search_history.setAdapter(historyAdapter); }}
外部可设置历史纪录的最大保存个数,默认为6
private int maxHistoryRecordCount = 6;/** * 设置最大的历史纪录数,默认为6条 * * @param maxHistoryRecordCount */public void setMaxHistoryRecordCount(int maxHistoryRecordCount) { this.maxHistoryRecordCount = maxHistoryRecordCount;}
在执行搜索时保存记录,最新搜索的记录放在首位,如果该条记录已经有包含在列表中,则移除原来位置的记录并重新保存在首位,当超过maxHistoryRecordCount 的值时,删除最先保存的历史纪录
/** * 保存历史纪录 * * @param text */private void keepSearchRecord(String text) { if (historySearchDatas == null) { historySearchDatas = new ArrayList<>(maxHistoryRecordCount); historySearchDatas.add(0, text); } else { for (int i = 0; i < historySearchDatas.size(); i++) { if ((historySearchDatas.get(i).equals(text))) {//判断数据是否已在历史记录中 //如果存在就移除 historySearchDatas.remove(i); } } //超过最大值 if (historySearchDatas.size() >= maxHistoryRecordCount) { //移除最老的一条记录 historySearchDatas.remove(maxHistoryRecordCount - 1); } //新添加的记录放在集合的首位 historySearchDatas.add(0, text); //保存搜索的历史记录到sp中 sp.edit().putString("history_search_datas", new Gson().toJson(historySearchDatas)).commit(); } if (historyAdapter == null) { historyAdapter = new CommonAdapter(context, historySearchDatas); gv_search_history.setAdapter(historyAdapter); } else { historyAdapter.updateRecordList(historySearchDatas); }}
当点击“清空”按钮时,删除历史纪录
/** * 清空历史纪录 */private void clearHistoryRecord() { if (historySearchDatas != null && historyAdapter != null) { historySearchDatas.clear();//清空列表 historyAdapter.updateRecordList(historySearchDatas); ll_search_history.setVisibility(GONE); //删除SP存储的历史纪录 sp.edit().putString("history_search_datas", "").commit(); }}
外部通过setHotSearchDatas(List hotSearchDatas)传入热门搜索的数据,如不调用此方法,则不显示热搜列表
/** * 设置热搜的数据集合 * * @param hotSearchDatas */public void setHotSearchDatas(List<String> hotSearchDatas) { this.hotSearchDatas = hotSearchDatas; if (hotSearchDatas != null && hotSearchDatas.size() > 0) { ll_search_hot.setVisibility(VISIBLE); hotAdapter = new CommonAdapter(context, hotSearchDatas); gv_search_hot.setNumColumns(hotNumColumns);//设置列数 gv_search_hot.setAdapter(hotAdapter);//设置热搜数据 } else { ll_search_hot.setVisibility(GONE); }}
设置提示列表的最大显示行数和热搜列表的列表
private int maxHintLines = -1;/** * 设置提示的最大显示行数,默认显示所有 * * @param maxHintLines */public void setMaxHintLines(int maxHintLines) { this.maxHintLines = maxHintLines;}private int hotNumColumns = 2;/** * 设置热搜数据的显示列数,默认为2列 * 需要在setHotSearchDatas()前设置 * * @param hotNumColumns */public void setHotNumColumns(int hotNumColumns) { this.hotNumColumns = hotNumColumns;}
核心方法,添加EditText文本的改变监听,在文本改变后调用自定义的监听的回调方法,在外部实现刷新提示列表的操作
//刷新提示列表的数据
if (onSearchListener != null) {
onSearchListener.onRefreshHintList(s.toString());
}
et_search_content.addTextChangedListener(new SearchTextChangedListener());/** * 监听EditText文本的改变 */class SearchTextChangedListener implements TextWatcher { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } /** * 当文本改变时调用 * * @param s * @param start * @param before * @param count */ @Override public void onTextChanged(CharSequence s, int start, int before, int count) { if (!TextUtils.isEmpty(s.toString().trim())) {//搜索框不为空 ll_search_hot.setVisibility(GONE); ll_search_history.setVisibility(GONE); iv_search_clear.setVisibility(VISIBLE);//显示清除搜索框内容的按钮 lv_search_hint.setVisibility(VISIBLE); } else { iv_search_clear.setVisibility(GONE); lv_search_hint.setVisibility(GONE); if (hotSearchDatas != null && hotSearchDatas.size() > 0) { ll_search_hot.setVisibility(VISIBLE); } if (historyAdapter != null && historySearchDatas.size() > 0 && isAutoKeep) { ll_search_history.setVisibility(VISIBLE); } } //刷新提示列表的数据 if (onSearchListener != null) { onSearchListener.onRefreshHintList(s.toString()); } } @Override public void afterTextChanged(Editable s) { }}
设置自定义监听
/** * 自定义searchview的监听 */public interface OnSearchListener { /** * 当进行搜索时回调此方法 * * @param searchText 进行搜索的文本 */ void onSearch(String searchText); /** * 当输入框文本变化,需刷新提示的ListView时调用 * * @param changedText 改变后的文本 */ void onRefreshHintList(String changedText);}private OnSearchListener onSearchListener;public void setOnSearchListener(OnSearchListener onSearchListener) { this.onSearchListener = onSearchListener;}
设置返回按钮、搜索按钮、清空搜索框按钮、提示列表Item、热搜列表Item、历史列表Item的点击监听
iv_search_back.setOnClickListener(new SearchOnClickListener()); iv_search_clear.setOnClickListener(new SearchOnClickListener()); tv_search_search.setOnClickListener(new SearchOnClickListener()); /** * 热搜列表的Item点击监听 */ gv_search_hot.setOnItemClickListener(new listItemOnClickListener(HOT_ITEM)); /** * 历史纪录的Item点击监听 */ gv_search_history.setOnItemClickListener(new listItemOnClickListener(HISTORY_ITEM)); /** * 提示列表的Item点击监听 */ lv_search_hint.setOnItemClickListener(new listItemOnClickListener(HINT_ITEM)); /** * 监听软键盘的搜索按钮 */ et_search_content.setOnEditorActionListener(new TextView.OnEditorActionListener() { @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { if (actionId == EditorInfo.IME_ACTION_SEARCH) { startSearch(et_search_content.getText().toString()); } return true; } }); ll_item_delete.setOnClickListener(new SearchOnClickListener());
点击监听的回调方法
/** * 点击监听的回调 */class SearchOnClickListener implements OnClickListener { @Override public void onClick(View v) { int i = v.getId(); if (i == R.id.iv_search_back) { ((Activity) context).finish(); } else if (i == R.id.iv_search_clear) { et_search_content.setText(null); } else if (i == R.id.tv_search_search) { startSearch(et_search_content.getText().toString()); } else if (i == R.id.ll_item_delete) { clearHistoryRecord(); } }}private static final int HOT_ITEM = 1;private static final int HINT_ITEM = 2;private static final int HISTORY_ITEM = 3;//Item的点击回调class listItemOnClickListener implements AdapterView.OnItemClickListener { private int tag; private List<String> datas; public listItemOnClickListener(int tag) { this.tag = tag; } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if (tag == HOT_ITEM) { datas = hotSearchDatas; } else if (tag == HINT_ITEM) { datas = hintDatas; } else if (tag == HISTORY_ITEM) { datas = historySearchDatas; } String item = datas.get(position); et_search_content.setText(item); startSearch(item); }}
执行搜索的方法和刷新提示列表和热搜列表的状态
/** * 开始执行搜索方法 * * @param text */private void startSearch(String text) { if (onSearchListener != null) { onSearchListener.onSearch(text); refreshListState(); if (isAutoKeep) { //保存搜索记录 keepSearchRecord(text); } }}/** * 刷新热搜和提示列表的状态 */private void refreshListState() { et_search_content.setSelection(et_search_content.getText().length()); lv_search_hint.setVisibility(GONE); ll_search_hot.setVisibility(GONE); //隐藏软键盘 InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);}
SearchALG类:匹配搜索规则的工具类
搜索规则:支持拼音的首字母搜索和全拼音搜索(注意:不能从中间开始搜索)
eg:爱情买卖
可以通过 aqmm匹配
也可以通过aiqingmaimai匹配
但是不支持直接从中间的字符匹配,如qing…、qmm
也不支持首字母和全拼音的混合搜索,如aqmaim
具体的使用方法如下:
- 关联类库 compile project(':searchview_library')
- 在布局文件中定义
<?xml version="1.0" encoding="utf-8"?> <LinearLayout 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" android:orientation="vertical" tools:context=".MainActivity"> <com.example.searchview_library.SearchView android:id="@+id/searchView" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout>
- 初始化
private SearchView searchView; searchView = (SearchView) findViewById(R.id.searchView);
- 设置数据
//热搜数据 private List<String> hot_datas; //提示列表数据 private List<String> hint_datas; private void initData() { hot_datas = new ArrayList<>(); hint_datas = new ArrayList<>(); searchALG = new SearchALG(this); for (int i = 0; i < 10; i++) { hot_datas.add("Android Hot " + i); } //注:若不需要热搜列表,可以不设置 //设置热搜数据显示的列数 searchView.setHotNumColumns(2); //设置热搜数据 searchView.setHotSearchDatas(hot_datas); /** * 设置提示数据的集合 */ for (int i = 0; i < 10; i++) { hint_datas.add("ts"+"安卓学习" + "Android Hint " + i + " 你好"); } /** * 设置自动保存搜索记录 */ searchView.keepSearchHistory(true); //设置提示列表的最大显示列数 searchView.setMaxHintLines(8); //设置保存搜索记录的个数 searchView.setMaxHistoryRecordCount(6); }
- 设置监听
private SearchALG searchALG; private List<String> changedHintDatas; searchView.setOnSearchListener(new MyOnSearchListener()); /** * 设置searview的监听 */ class MyOnSearchListener implements SearchView.OnSearchListener { /** * 搜索回调 * @param searchText 进行搜索的文本 */ @Override public void onSearch(String searchText) { if (!TextUtils.isEmpty(searchText)) { Toast.makeText(MainActivity.this, "完成搜索" + searchText, Toast.LENGTH_SHORT).show(); } else { Toast.makeText(MainActivity.this, "搜索内容不能为空!", Toast.LENGTH_SHORT).show(); } } /** * 刷新提示列表 * @param changedText 改变后的文本 */ @Override public void onRefreshHintList(String changedText) { if (changedHintDatas == null) { changedHintDatas = new ArrayList<>(); } else { changedHintDatas.clear(); } if (TextUtils.isEmpty(changedText)) { return; } for (int i = 0; i < hint_datas.size(); i++) { String hint_data = hint_datas.get(i); boolean isAdd = searchALG.isAddToHintList(hint_data, changedText); if (isAdd) { changedHintDatas.add(hint_datas.get(i)); } } /** * 根据搜索框文本的变化,动态的改变提示的listView */ searchView.updateHintList(changedHintDatas); } }
demo下载地址:
http://download.csdn.net/detail/benhuo931115/9480849
- 自定义的一个App搜索框
- 自定义协议从一个App打开另一个App的代码
- 自定义协议从自己的一个app打开另一个app
- Android 用EditText加一个ImageButton自定义一个带clear的搜索框
- Android上实现一个简单的天气预报APP(十) 城市列表搜索框
- 自定义搜索框的UI
- 一个搜索文件的APP(2)-搜索功能的实现
- iOS自定义简单的搜索框
- 如何自定义协议从自己的一个app打开另一个app
- 如何自定义协议从自己的一个app打开另一个app
- 网页搜索之后的APP搜索
- android学习笔记(5)-一个搜索文件的APP(2)-搜索功能的实现
- Android客户端之“微服私访”App的系统学习(七)XRecyclerView快速实现列表界面+自定义Search输入框,软键盘搜索按钮监听+TextView部分样式改变
- 自定义iOS搜索框
- 自定义搜索框EditText
- 自定义搜索框
- 自定义搜索框
- WordPress 自定义搜索框
- 八皇后问题-回溯算法
- 杭电2955-0-1背包
- LPS最长回文子序列
- 抽象工厂模式
- 基于socket,实现用户注册,用户登录,以及文件上传的例子
- 自定义的一个App搜索框
- hdoj 1429 胜利大逃亡(续)【bfs好题】
- 匹配极其相关问题(一)
- LeetCode 1 - Two Sum ( JAVA )
- CSP考试 2013年12月第4题 C语言实现
- choice 详解
- gmtime和ctime的区别(补)
- AlertDialog 的简单用法效果图
- zynq的uboot编译问题汇总