目标 输入关键字,实时显示搜索结果。
作者:木鸟杂记 https://www.qtmuniao.com , 转载请注明出处
过程 从官方文档 入手,由于初入门,相关术语懂得少,而该文档又非代码级实现,导致没能完整搭起搜索的架子。该文档主要讲了以下几点:
两种实现方式,search dialog和search widget;对于Android 3.0 以后的机器,推荐使用后者,较为灵活。
三个主要组件:
搜索配置(a searchable configuration)
搜索容器(a searchable Activity)(困惑点1)
搜索结构(a search interface)
搜索过程:
接受查询(Receive the query) 使用Itent(困惑点2)
查询数据(Search your data)
呈现结果(Present the results)(困惑点3)
我想使用Search Widget方式,主要遇到以下几个困惑点:
如何在Activity
中触发搜索,就是AppBar右上角的搜索图标如何做出来。
如果使用Intent
的查询数据,如示例一般,应该不能做到实时匹配输入字符。我猜想应该有listener之类的,但是例子没给。
如何呈现结果,文档建议让SearchAbleActivity
继承ListView
来实现,但是具体细节,如怎么接受结果,传递给ListView
,都没有提。 等于搜索过程的三个环节都没有搞清楚,一脸懵逼。
于是搜索关键词 SearchView action bar,找到一篇帖子:Implementing SearchView in action bar ,反复琢磨,才弄清楚了以上几个问题。
首先,对于触发搜索,该回答使用的是具有App Bar的Activity作为SearchableActivity,并且在复写onCreateOptionsMenu函数,实例化其参数menu,并且将SearchView作为其一个item。如此一来,SearchableActivity的右上角就会有搜索按钮。相关代码如下:res\menu\search.xml:
1 2 3 4 5 6 7 8 9 <?xml version="1.0" encoding="utf-8" ?> <menu xmlns:android ="http://schemas.android.com/apk/res/android" xmlns:app ="http://schemas.android.com/apk/res-auto" > <item android:id ="@+id/search_menu" android:title ="@string/search_hint" app:showAsAction ="ifRoom|collapseActionView" app:actionViewClass ="android.widget.SearchView" /> </menu >
SearchableActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @Override public boolean onCreateOptionsMenu (Menu menu) { getMenuInflater().inflate(R.menu.search, menu); this .menu = menu; SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE); SearchView searchView = (SearchView) menu.findItem(R.id.search_menu).getActionView(); ComponentName name = getComponentName(); searchView.setSearchableInfo(searchManager.getSearchableInfo(name)); searchView.setIconifiedByDefault(false ); searchView.setOnQueryTextListener(new SearchView .OnQueryTextListener() { @Override public boolean onQueryTextSubmit (String s) { doMySearch(s); return false ; } @Override public boolean onQueryTextChange (String s) { doMySearch(s); return false ; } }); return true ; }
AndroidManifest.xml
1 2 3 4 5 6 7 <activity android:name=".SearchableActivity"> <intent-filter> <action android:name="android.intent.action.SEARCH" /> </intent-filter> <meta-data android:name="android.app.searchable" android:resource="@xml/searchable"/> </activity>
res/xml/searchable.xml
1 2 3 4 5 <?xml version="1.0" encoding="utf-8"?> <searchable xmlns:android="http://schemas.android.com/apk/res/android" android:label="@string/app_label" android:hint="@string/app_label" > </searchable>
其次是实时匹配查询结果;也是在onCreateOptionsMenu
函数中,给SearchView
设置listeners,具体可以见上面代码,但是return true/false暂时有什么区别还没搞清楚。
最后是展示数据;如官方文档所说,利用ListView,具体做法是通过Adapter将数据(比如List)传给利用xml渲染(inflate)的ListView,该答案是用CursorAdaptor(对接数据库数据更合适)。具体代码如下:res/layout/item.xml
1 2 3 4 5 6 7 8 9 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/item" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout>
ResultAdapter.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class ResultAdapter extends CursorAdapter { private List<String> items; private TextView text; public ResultAdapter (Context context, Cursor cursor, List<String> items) { super (context, cursor, false ); this .items = items; } @Override public void bindView (View view, Context context, Cursor cursor) { text.setText(items.get(cursor.getPosition())); } @Override public View newView (Context context, Cursor cursor, ViewGroup parent) { LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); View view = inflater.inflate(R.layout.item, parent, false ); text = view.findViewById(R.id.item); return view; } }
SearchableActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 private void doMySearch (String query) { String[] columns = new String [] { "_id" , "text" }; Object[] temp = new Object [] { 0 , "default" }; MatrixCursor cursor = new MatrixCursor (columns); for (int i = 0 ; i < items.size(); i++) { temp[0 ] = i; temp[1 ] = items.get(i); cursor.addRow(temp); } final SearchView search = (SearchView) menu.findItem(R.id.search_menu).getActionView(); search.setSuggestionsAdapter(new ResultAdapter (this , cursor, items)); }
参考资料:
Android官方文档,https://developer.android.com/guide/topics/search/search-dialog.html
Stack Overflow回答,https://stackoverflow.com/questions/21585326/implementing-searchview-in-action-bar
官方视频,https://www.youtube.com/watch?v=9OWmnYPX1uc
我是青藤木鸟,一个喜欢摄影、专注大规模数据系统的程序员,欢迎关注我的公众号:“木鸟杂记 ”,有更多的分布式系统、存储和数据库相关的文章,欢迎关注。
关注公众号后,回复“资料 ”可以获取我总结一份分布式数据库学习资料。
回复“优惠券 ”可以获取我的大规模数据系统付费专栏《系统日知录 》的八折优惠券。
我们还有相关的分布式系统和数据库的群,可以添加我的微信号:qtmuniao,我拉你入群。加我时记得备注:“分布式系统群”。
另外,如果你不想加群,还有一个分布式系统和数据库的论坛(点这里 ),欢迎来玩耍。