Today we will look into Android SearchView widget and develop an application that filters a ListView by the queried text. We’ll be using DataBinding to hook up the layouts in the Activities and Adapters. If you haven’t read about DataBinding refer this tutorial first for a better understanding.
Table of Contents
Android SearchView
Android allows us to use the search functionality in our app by displaying the SearchView widget either in the ToolBar/ActionBar or inserting it into a layout. Android SearchView widget is available from Android 3.0 onwards.
The SearchView is defined in the XML layout as shown below.
<android.support.v7.widget.SearchView
android:id="@+id/search"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
There are many forms for searching in Android such as voice search, suggestions etc. In this tutorial we’ll use SearchView.OnQueryTextListener
and Filterable
interfaces.
The Filterable interface filters the queried text over a ListView and displays the resulted ListView rows.
OnQueryTextListener
interface can detect two events.
onQueryTextChange
is called when the user types each character in the text fieldonQueryTextSubmit
is triggered when the search is pressed
Android SearchView Example
Below image shows the final android SearchView example project.
The project consists of an Activity and an Adapter for the ListView.
Android SearchView Example Code
The activity_main.xml is given below. It consists of a ListView with a SearchView on top.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="https://schemas.android.com/apk/res/android">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<android.support.v7.widget.SearchView
android:id="@+id/search"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true" />
<ListView
android:id="@+id/list_view"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/search" />
</RelativeLayout>
</layout>
The MainActivity.java is given below.
package com.journaldev.searchview;
import android.databinding.DataBindingUtil;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.SearchView;
import com.journaldev.searchview.databinding.ActivityMainBinding;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
ActivityMainBinding activityMainBinding;
ListAdapter adapter;
List<String> arrayList= new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
arrayList.add("January");
arrayList.add("February");
arrayList.add("March");
arrayList.add("April");
arrayList.add("May");
arrayList.add("June");
arrayList.add("July");
arrayList.add("August");
arrayList.add("September");
arrayList.add("October");
arrayList.add("November");
arrayList.add("December");
adapter= new ListAdapter(arrayList);
activityMainBinding.listView.setAdapter(adapter);
activityMainBinding.search.setActivated(true);
activityMainBinding.search.setQueryHint("Type your keyword here");
activityMainBinding.search.onActionViewExpanded();
activityMainBinding.search.setIconified(false);
activityMainBinding.search.clearFocus();
activityMainBinding.search.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
adapter.getFilter().filter(newText);
return false;
}
});
}
}
In the above code, we are passing an ArrayList of Months to the List Adapter.
We’re invoking the filter method that’s defined in the adapter class every time the search query text changes.
The ListAdapter.java class looks like this.
package com.journaldev.searchview;
import android.content.Context;
import android.databinding.DataBindingUtil;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import com.journaldev.searchview.databinding.RowItemBinding;
import java.util.ArrayList;
import java.util.List;
public class ListAdapter extends BaseAdapter implements Filterable {
List<String> mData;
List<String> mStringFilterList;
ValueFilter valueFilter;
private LayoutInflater inflater;
public ListAdapter(List<String> cancel_type) {
mData=cancel_type;
mStringFilterList = cancel_type;
}
@Override
public int getCount() {
return mData.size();
}
@Override
public String getItem(int position) {
return mData.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, final ViewGroup parent) {
if (inflater == null) {
inflater = (LayoutInflater) parent.getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
RowItemBinding rowItemBinding = DataBindingUtil.inflate(inflater, R.layout.row_item, parent, false);
rowItemBinding.stringName.setText(mData.get(position));
return rowItemBinding.getRoot();
}
@Override
public Filter getFilter() {
if (valueFilter == null) {
valueFilter = new ValueFilter();
}
return valueFilter;
}
private class ValueFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if (constraint != null && constraint.length() > 0) {
List<String> filterList = new ArrayList<>();
for (int i = 0; i < mStringFilterList.size(); i++) {
if ((mStringFilterList.get(i).toUpperCase()).contains(constraint.toString().toUpperCase())) {
filterList.add(mStringFilterList.get(i));
}
}
results.count = filterList.size();
results.values = filterList;
} else {
results.count = mStringFilterList.size();
results.values = mStringFilterList;
}
return results;
}
@Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
mData = (List<String>) results.values;
notifyDataSetChanged();
}
}
}
As you can see in the above code we’re performing filtering using an inner class ValueFilter
that extends the Filter class. It filters the list by checking if the search query text matches the strings given in the ArrayList.
The XML layout for the ListView row is given below.
row_item.xml
<layout xmlns:android="https://schemas.android.com/apk/res/android">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/stringName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:padding="@dimen/activity_horizontal_margin"
android:textAllCaps="false"
android:textAppearance="?android:attr/textAppearanceMedium" />
</RelativeLayout>
</layout>
The output of the android search view application in action is given below.
The SearchView shown above requires us to press the search icon to activate the text field. Also, it doesn’t contain any hint/placeholder text.
Add the following code in the MainActivity to enable the SearchView by default and display a hint.
activityMainBinding.search.setActivated(true);
activityMainBinding.search.setQueryHint("Type your keyword here");
activityMainBinding.search.onActionViewExpanded();
activityMainBinding.search.setIconified(false);
activityMainBinding.search.clearFocus();
The SearchView after customising as above looks like this.
This brings an end to android SearchView tutorial. We’ll dive into the advanced features of SearchView in a later tutorial. You can download the Android SearchView Project from the link given below.
Sir, is there anyway to change text color and hint color of searchview?
Please reply.
Can I use this with RecyclerView?
ActivityMainBinding ?
how to add search view webview search any website how to apply ??
Great tutorial!! I would like to know one thing… For E.g..I have two separate lists in separate activities ..months and weekdays.. and implement a searchview as suggested here.. it searches for the months perfectly.. and the other activity searches for weeks perfectly.. what if i want to add a searchview wherein boththe lists (months & weekdays) can be searched.. i.e if the user searches JANUARY or MONDAY the list should filter and show the results.. how to do this when the list are in separate activities… Your reply in this regard… will be greatly appreciated….
thank you for your sharing great information to about DataBinding. its really great post for us. this the good blog site. good job.
Glad it helped you Stacy.
Getting some errors with the ListAdapter section:
“RowItemBinding rowItemBinding = DataBindingUtil.inflate(inflater, R.layout.row_item, parent, false);
rowItemBinding.stringName.setText(mData.get(position));”
> The second sentence with “.get(position)”. Set Text wants to pull a string. Position is an Int. Casting the parameter to Int ‘works’ but when launching the app to test, I get a Fatal Exception stating String cannot be cast to Integer. So it doesn’t work.
Any suggestions here?
Nice observation Chris.
Change this :
rowItemBinding.stringName.setText(mData.get(position));
to:
rowItemBinding.stringName.setText(String.valueOf(mData.get(position)));
How can i make that search result will open new activity when i click on it.
ThanQu… Bro Doing Well.
How can I apply this to a csv adapter that puts the inputs into an arraylist?
Where is code of ActivityMainBinding Class ?
By default, a Binding class will be generated based on the name of the layout file, converting it to Pascal case and suffixing “Binding” to it. The above layout file was activity_main.xml so the generate class was ActivityMainBinding
If your xml name is main_activity.xml than DataBinding class name will be MainActivityBinding.
Take note that data binding is enabled in the build.gradle file.
The tutorial will be updated to mention this explicitly.
Thanks
Can someone pls help me out with where is d code for
ActivityMainBinding
&
databinding.RowItemBinding
??
Not able to complete this tutorial due to this
By default, a Binding class will be generated based on the name of the layout file, converting it to Pascal case and suffixing “Binding” to it. The above layout file was activity_main.xml so the generate class was ActivityMainBinding
If your xml name is main_activity.xml than DataBinding class name will be MainActivityBinding.
Take note that data binding is enabled in the build.gradle file.
The tutorial will be updated to mention this explicitly.
Thanks
Where is the binding class generated
how make project listview with text, image, and when click the listview we can see other activity ?
CAN YOU ADD THE CODE FOR THE MISSING: com.journaldev.searchview.databinding.RowItemBinding
THANK YOU
never-mind I just saw that it was a binding
Can you help me to fix it?
Thaaaaaaaank You , Very helpfull
Glad that it was helpful to you Walid.
Hi, I’m looking for implement this sort of searchview but I don’t want to show the original listview’s datas. I just wanna display the results only in the listview. Is it possible to implement that ?
Thank’s.
Hi! Thanks for sharing the code that helps a lot, I have a question is it ossible to add onClickListeners to the every single one of the item in the list?
Inside the onItemClickListener you can add custom behaviours for each row based on the id.
ActivityMainBinding ?
This is fine in XML:
However, this is the correct JAVA
SearchView search = (SearchView) findViewById(R.id.search);
search.setActivated(true);
search.setQueryHint(“Type your keyword here”);
search.onActionViewExpanded();
search.setIconified(false);
search.clearFocus();