SearchView
Appcompat SearchView with RxBindings watcher
Section titled “Appcompat SearchView with RxBindings watcher”build.gradle:
dependencies { compile 'com.android.support:appcompat-v7:23.3.0' compile 'com.jakewharton.rxbinding:rxbinding-appcompat-v7:0.4.0'}menu/menu.xml:
<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/action_search" android:title="Search" android:icon="@android:drawable/ic_menu_search" app:actionViewClass="android.support.v7.widget.SearchView" app:showAsAction="always"/></menu>MainActivity.java:
@Overridepublic boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu, menu);
MenuItem searchMenuItem = menu.findItem(R.id.action_search); setupSearchView(searchMenuItem );
return true;}
private void setupSearchView(MenuItem searchMenuItem) { SearchView searchView = (SearchView) searchMenuItem.getActionView(); searchView.setQueryHint(getString(R.string.search_hint)); // your hint here
SearchAdapter searchAdapter = new SearchAdapter(this); searchView.setSuggestionsAdapter(searchAdapter);
// optional: set the letters count after which the search will begin to 1 // the default is 2 try { int autoCompleteTextViewID = getResources().getIdentifier("android:id/search_src_text", null, null); AutoCompleteTextView searchAutoCompleteTextView = (AutoCompleteTextView) searchView.findViewById(autoCompleteTextViewID); searchAutoCompleteTextView.setThreshold(1); } catch (Exception e) { Logs.e(TAG, "failed to set search view letters threshold"); }
searchView.setOnSearchClickListener(v -> { // optional actions to search view expand }); searchView.setOnCloseListener(() -> { // optional actions to search view close return false; });
RxSearchView.queryTextChanges(searchView) .doOnEach(notification -> { CharSequence query = (CharSequence) notification.getValue(); searchAdapter.filter(query); }) .debounce(300, TimeUnit.MILLISECONDS) // to skip intermediate letters .flatMap(query -> MyWebService.search(query)) // make a search request .retry(3) .subscribe(results -> { searchAdapter.populateAdapter(results); });
//optional: collapse the searchView on close searchView.setOnQueryTextFocusChangeListener((view, queryTextFocused) -> { if (!queryTextFocused) { collapseSearchView(); } });}SearchAdapter.java
public class SearchAdapter extends CursorAdapter { private List<SearchResult> items = Collections.emptyList();
public SearchAdapter(Activity activity) { super(activity, null, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER); }
public void populateAdapter(List<SearchResult> items) { this.items = items; final MatrixCursor c = new MatrixCursor(new String[]{BaseColumns._ID}); for (int i = 0; i < items.size(); i++) { c.addRow(new Object[]{i}); } changeCursor(c); notifyDataSetChanged(); }
public void filter(CharSequence query) { final MatrixCursor c = new MatrixCursor(new String[]{BaseColumns._ID}); for (int i = 0; i < items.size(); i++) { SearchResult result = items.get(i); if (result.getText().startsWith(query.toString())) { c.addRow(new Object[]{i}); } } changeCursor(c); notifyDataSetChanged(); }
@Override public void bindView(View view, Context context, Cursor cursor) { ViewHolder holder = (ViewHolder) view.getTag(); int position = cursor.getPosition(); if (position < items.size()) { SearchResult result = items.get(position); // bind your view here } }
@Override public View newView(Context context, Cursor cursor, ViewGroup parent) { LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflater.inflate(R.layout.search_list_item, parent, false); ViewHolder holder = new ViewHolder(v);
v.setTag(holder); return v; }
private static class ViewHolder { public final TextView text;
public ViewHolder(View v) { this.text= (TextView) v.findViewById(R.id.text); } }}SearchView in Toolbar with Fragment
Section titled “SearchView in Toolbar with Fragment”menu.xml - (res -> menu)
<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" tools:context=".HomeActivity">
<item android:id="@+id/action_search" android:icon="@android:drawable/ic_menu_search" android:title="Search" app:actionViewClass="android.support.v7.widget.SearchView" app:showAsAction="always" />
</menu>MainFragment.java
public class MainFragment extends Fragment {
private SearchView searchView = null; private SearchView.OnQueryTextListener queryTextListener;
@Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_main, container, false); }
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); }
@Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.menu, menu); MenuItem searchItem = menu.findItem(R.id.action_search); SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE);
if (searchItem != null) { searchView = (SearchView) searchItem.getActionView(); } if (searchView != null) { searchView.setSearchableInfo(searchManager.getSearchableInfo(getActivity().getComponentName()));
queryTextListener = new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextChange(String newText) { Log.i("onQueryTextChange", newText);
return true; } @Override public boolean onQueryTextSubmit(String query) { Log.i("onQueryTextSubmit", query);
return true; } }; searchView.setOnQueryTextListener(queryTextListener); } super.onCreateOptionsMenu(menu, inflater); }
@Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_search: // Not implemented here return false; default: break; } searchView.setOnQueryTextListener(queryTextListener); return super.onOptionsItemSelected(item); }}Reference screenshot:
Setting Theme for SearchView
Section titled “Setting Theme for SearchView”Basically to apply a theme for SearchView extracted as app:actionViewClass from the menu.xml, we need understand that it depends completely on the style applied to the underlying Toolbar. To achieve themeing the Toolbar apply the following steps.
Create a style in the styles.xml
<style name="ActionBarThemeOverlay"> <item name="android:textColorPrimary">@color/prim_color</item> <item name="colorControlNormal">@color/normal_color</item> <item name="colorControlHighlight">@color/high_color</item> <item name="android:textColorHint">@color/hint_color</item></style>Apply the style to the Toolbar.
<android.support.v7.widget.Toolbar android:id="@+id/toolbar" app:theme="@style/ActionBarThemeOverlay" app:popupTheme="@style/ActionBarThemeOverlay" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="@color/colorPrimary" android:title="@string/title" tools:targetApi="m" />This gives the desired color to the all the views corresponding to the Toolbar (back button, Menu icons and SearchView).
