自定义的一个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

1 0
原创粉丝点击