本文主要介绍SearchView的使用、即时搜索提示功能的实现,以及一些设置。
具体代码可见SearchViewDemo@Github,可实现效果如下:
Demo APK 可以方便的查看效果,在各大应用商店搜索 trinea android 下载即可,如:Google Play。
1. layout文件
<?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" > <SearchView android:id="@+id/search_view" android:layout_width="match_parent" android:layout_height="match_parent" android:iconifiedByDefault="true" android:inputType="textCapWords" android:imeOptions="actionSearch" android:queryHint="" /> </RelativeLayout>
xml中主要配置有四个属性,如下:
android:iconifiedByDefault表示搜索图标是否在输入框内。true效果更加
android:imeOptions设置IME options,即输入法的回车键的功能,可以是搜索、下一个、发送、完成等等。这里actionSearch表示搜索
android:inputType输入框文本类型,可控制输入法键盘样式,如numberPassword即为数字密码样式
android:queryHint输入框默认文本
2. java部分代码
SearchView几个主要函数
setOnCloseListener(SearchView.OnCloseListener listener)表示点击取消按钮listener,默认点击搜索输入框
setOnQueryTextListener(SearchView.OnQueryTextListener listener)表示输入框文字listener,包括public boolean onQueryTextSubmit(String query)开始搜索listener,public boolean onQueryTextChange(String newText)输入框内容变化listener,两个函数,下面代码包含了如何利用延迟执行实现搜索提示
package cn.trinea.android.demo; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import android.app.ActionBar; import android.app.ActionBar.LayoutParams; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; import android.view.WindowManager; import android.widget.SearchView; import android.widget.SearchView.OnCloseListener; import android.widget.Toast; public class SearchViewDemo extends Activity { private SearchView searchView; private Context context; private MyHandler handler; // schedule executor private ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(10); private String currentSearchTip; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.search_view_demo); context = getApplicationContext(); handler = new MyHandler(); ActionBar actionBar = getActionBar(); actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_CUSTOM); setTitle(" "); LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE); View customActionBarView = inflater.inflate(R.layout.search_view_demo_title, null); searchView = (SearchView)customActionBarView.findViewById(R.id.search_view); searchView.setIconified(false); searchView.setOnCloseListener(new OnCloseListener() { @Override public boolean onClose() { // to avoid click x button and the edittext hidden return true; } }); searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { public boolean onQueryTextSubmit(String query) { Toast.makeText(context, "begin search", Toast.LENGTH_SHORT).show(); return true; } public boolean onQueryTextChange(String newText) { if (newText != null && newText.length() > 0) { currentSearchTip = newText; showSearchTip(newText); } return true; } }); LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, Gravity.CENTER_VERTICAL | Gravity.RIGHT); actionBar.setCustomView(customActionBarView, params); // show keyboard getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); } public void showSearchTip(String newText) { // excute after 500ms, and when excute, judge current search tip and newText schedule(new SearchTipThread(newText), 500); } class SearchTipThread implements Runnable { String newText; public SearchTipThread(String newText){ this.newText = newText; } public void run() { // keep only one thread to load current search tip, u can get data from network here if (newText != null && newText.equals(currentSearchTip)) { handler.sendMessage(handler.obtainMessage(1, newText + " search tip")); } } } public ScheduledFuture<?> schedule(Runnable command, long delayTimeMills) { return scheduledExecutor.schedule(command, delayTimeMills, TimeUnit.MILLISECONDS); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: { onBackPressed(); return true; } } return false; } private class MyHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case 1: Toast.makeText(context, (String)msg.obj, Toast.LENGTH_SHORT).show(); break; } } } }
上面代码在onQueryTextChange函数即输入框内容每次变化时将一个数据获取线程SearchTipThread放到ScheduledExecutorService中,500ms后执行,在线程执行时判断当前输入框内容和要搜索内容,若相等则继续执行,否则直接返回,避免不必要的数据获取和多个搜索提示同时出现。
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
| WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
表示默认输入法弹出
编辑框内容为空点击取消的x按钮,编辑框收缩,可在onClose中返回true
searchView.setOnCloseListener(new OnCloseListener() { @Override public boolean onClose() { return true; } });
searchView.onActionViewExpanded();表示在内容为空时不显示取消的x按钮,内容不为空时显示.
searchView.setSubmitButtonEnabled(true);编辑框后显示search按钮,个人建议用android:imeOptions=”actionSearch”代替。
隐藏输入法键盘
InputMethodManager inputMethodManager; inputMethodManager = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); private void hideSoftInput() { if (inputMethodManager != null) { View v = SearchActivity.this.getCurrentFocus(); if (v == null) { return; } inputMethodManager.hideSoftInputFromWindow(v.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); searchView.clearFocus(); } }
其中SearchActivity为Activity的类名
Thank you
实现一个智能提示功能需要ajax、数据库、jsp/php、算法等很多知识,
如果数据量大,还需要特殊优化
一个小功能,花费太大精力很不划算
我使用了92find.c-o-m的搜索框智能提示功能托管服务,
只要一行javascript代码就可以实现百度、淘宝搜索框提示的全部功能
比如:汉字拼音匹配、拼音前缀匹配、模糊搜索、智能容错,还可以自定义提示词汇及其排序权重
花五分钟我的网站就可以部署同百度、淘宝一样强大好用的输入提示功能
同时兼容IE、Firefox、Safari、Chrome、Opera各种浏览器
兼容ios、Android、Windows
给延迟搜索提个小建议。
比如我清空了SearchView中的文字,本来根据Listener中的判断要执行其他操作(比如显示一个新的fragmentA),结果因为操作很快,500ms的那个指令在前者执行完后才到达(比如显示一个fragmentB),就把刚才的在SearchView中监听到无文字时的操作给覆盖了。这时候可以加个boolean来判断下,如果为空就不允许再在handler中执行其他指令。
是的,代码里有一部分后来没有提交,在返回处理时同样需要判断
if (currentSearchTip != null && currentSearchTip.equals(newText))
请问左边的返回箭头是如何设置的。
searchView.onActionViewExpanded();表示在内容为空时不显示取消的x按钮,内容不为空时显示.我发现没有这段代码,x按钮默认就是有内容才显示的。这个不对啊,mSearchView.onActionViewCollapsed(); mSearchView.onActionViewExpanded();它们分别是设置SearchView默认是展开还是收缩的啊
现在做的项目正好有这个需求,受教了~
没有见到ListUtils这个类啊
https://github.com/Trinea/android-common
https://github.com/Trinea/android-demo