In this example, we’ll see how to search filter an android listview.
We’ll use a SearchView component.
GRADLE FILES
We’ll edit the app level build.gadle adding some dependencies.
build.gradle
- Our ListView will comprise cardviews so we add cardview dependency.
apply plugin: 'com.android.application' android { compileSdkVersion 23 buildToolsVersion "23.0.2" defaultConfig { applicationId "com.tutorials.hp.lvfilter" minSdkVersion 15 targetSdkVersion 23 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.2.1' compile 'com.android.support:design:23.2.1' compile 'com.android.support:cardview-v7:23.2.1' }
LAYOUTS
We’ll have these three layouts in our project:
1. activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout android_layout_width="match_parent" android_layout_height="match_parent" android_fitsSystemWindows="true" tools_context="com.tutorials.hp.lvfilter.MainActivity"> <android.support.design.widget.AppBarLayout android_layout_width="match_parent" android_layout_height="wrap_content" android_theme="@style/AppTheme.AppBarOverlay"> <android.support.v7.widget.Toolbar android_id="@+id/toolbar" android_layout_width="match_parent" android_layout_height="?attr/actionBarSize" android_background="?attr/colorPrimary" app_popupTheme="@style/AppTheme.PopupOverlay" /> </android.support.design.widget.AppBarLayout> <include layout="@layout/content_main" /> <android.support.design.widget.FloatingActionButton android_id="@+id/fab" android_layout_width="wrap_content" android_layout_height="wrap_content" android_layout_gravity="bottom|end" android_layout_margin="@dimen/fab_margin" android_src="@android:drawable/ic_dialog_email" /> </android.support.design.widget.CoordinatorLayout>
2. content_main.xml
- This layout will hold our ListView and SearchView.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout android_layout_width="match_parent" android_layout_height="match_parent" android_paddingBottom="@dimen/activity_vertical_margin" android_paddingLeft="@dimen/activity_horizontal_margin" android_paddingRight="@dimen/activity_horizontal_margin" android_paddingTop="@dimen/activity_vertical_margin" app_layout_behavior="@string/appbar_scrolling_view_behavior" tools_context="com.tutorials.hp.lvfilter.MainActivity" tools_showIn="@layout/activity_main"> <android.support.v7.widget.SearchView android_id="@+id/mSearch" android_layout_width="match_parent" android_layout_height="50dp" app_defaultQueryHint="Search.." /> <ListView android_layout_width="wrap_content" android_layout_height="wrap_content" android_id="@+id/lv" android_layout_below="@+id/mSearch" android_layout_alignParentLeft="true" android_layout_alignParentStart="true" /> </RelativeLayout>
3. model.xml
- This layout will define the model for our custom rows.
- Our ListView will have images and text.
<?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.CardView android_orientation="horizontal" android_layout_width="match_parent" android_layout_margin="10dp" card_view_cardCornerRadius="10dp" card_view_cardElevation="10dp" android_layout_height="wrap_content"> <RelativeLayout android_layout_width="match_parent" android_layout_height="match_parent"> <ImageView android_layout_width="wrap_content" android_layout_height="wrap_content" android_id="@+id/movieImage" android_padding="10dp" android_src="@drawable/ghost" /> <TextView android_layout_width="wrap_content" android_layout_height="wrap_content" android_textAppearance="?android:attr/textAppearanceLarge" android_text="Name" android_id="@+id/nameTxt" android_padding="10dp" android_textColor="@color/colorAccent" android_layout_below="@+id/movieImage" android_layout_alignParentLeft="true" /> <TextView android_layout_width="wrap_content" android_layout_height="wrap_content" android_textAppearance="?android:attr/textAppearanceLarge" android_text=" John Doe a former FBI Agent and now Physics teacher .is wrongly accussed of murdering an innocent child.He makes it his business to find the bad guys who did taht.He convinces hacker Aram to join him..... " android_id="@+id/descTxt" android_padding="10dp" android_layout_below="@+id/nameTxt" android_layout_alignParentLeft="true" /> <TextView android_layout_width="wrap_content" android_layout_height="wrap_content" android_textAppearance="?android:attr/textAppearanceMedium" android_text="TV Show" android_id="@+id/posTxt" android_padding="10dp" android_layout_below="@+id/movieImage" android_layout_alignParentRight="true" /> <CheckBox android_layout_width="wrap_content" android_layout_height="wrap_content" android_id="@+id/chk" android_layout_alignParentRight="true" /> </RelativeLayout> </android.support.v7.widget.CardView>
JAVA CLASSES
Here are our Java classes:
1. Movie.java
- Our data object.
- Will represent a single movies.
package com.tutorials.hp.lvfilter; public class Movie { private String name; private int image; public Movie(String name, int image) { this.name = name; this.image = image; } public String getName() { return name; } public int getImage() { return image; } }
2. ItemClickListner
- An interface.
- Defines the signature for our
OnItemClick()
method.
package com.tutorials.hp.lvfilter; import android.view.View; public interface ItemClickListener { void onItemClick(View v); }
3. MyViewHolder.java
- View holder class.
package com.tutorials.hp.lvfilter; import android.view.View; import android.widget.ImageView; import android.widget.TextView; public class MyViewHolder implements View.OnClickListener { ImageView img; TextView nameTxt; ItemClickListener itemClickListener; public MyViewHolder(View v) { img= (ImageView) v.findViewById(R.id.movieImage); nameTxt= (TextView) v.findViewById(R.id.nameTxt); v.setOnClickListener(this); } @Override public void onClick(View v) { this.itemClickListener.onItemClick(v); } public void setItemClickListener(ItemClickListener ic) { this.itemClickListener=ic; } }
4. MyAdapter.java
- Our adapter class.
- Derives from BaseAdapter.
- Implements Filterable.
package com.tutorials.hp.lvfilter; import android.content.Context; 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 android.widget.Toast; import java.util.ArrayList; public class MyAdapter extends BaseAdapter implements Filterable { Context c; ArrayList<Movie> movies; LayoutInflater inflater; ArrayList<Movie> filterList; CustomFilter filter; public MyAdapter(Context c, ArrayList<Movie> movies) { this.c = c; this.movies = movies; this.filterList=movies; } //TOTLA NUM OF MOVIES @Override public int getCount() { return movies.size(); } //GET A SINGLE MOVIE @Override public Object getItem(int position) { return movies.get(position); } //IDENTITDIER @Override public long getItemId(int position) { return position; } @Override public View getView(final int position, View convertView, ViewGroup parent) { if(inflater==null) { inflater= (LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } //PERFORM INFLATION if(convertView==null) { convertView=inflater.inflate(R.layout.model,null); } //BIND DATA TO VIEWS MyViewHolder holder=new MyViewHolder(convertView); holder.nameTxt.setText(movies.get(position).getName()); holder.img.setImageResource(movies.get(position).getImage()); holder.setItemClickListener(new ItemClickListener() { @Override public void onItemClick(View v) { Toast.makeText(c,movies.get(position).getName(),Toast.LENGTH_SHORT).show(); } }); //RETURN A ROW return convertView; } @Override public Filter getFilter() { if(filter==null) { filter=new CustomFilter(filterList,this); } return filter; } }
5. CustomFilter.java
- This class is responsible for our custom filtering.
- Derives from
android.widget.Filter
.
package com.tutorials.hp.lvfilter; import android.widget.Filter; import java.util.ArrayList; public class CustomFilter extends Filter { ArrayList<Movie> filterList; MyAdapter adapter; public CustomFilter(ArrayList<Movie> filterList, MyAdapter adapter) { this.filterList = filterList; this.adapter = adapter; } //FILTERING @Override protected FilterResults performFiltering(CharSequence constraint) { //RESULTS FilterResults results=new FilterResults(); //VALIDATION if(constraint != null && constraint.length()>0) { //CHANGE TO UPPER FOR CONSISTENCY constraint=constraint.toString().toUpperCase(); ArrayList<Movie> filteredMovies=new ArrayList<>(); //LOOP THRU FILTER LIST for(int i=0;i<filterList.size();i++) { //FILTER if(filterList.get(i).getName().toUpperCase().contains(constraint)) { filteredMovies.add(filterList.get(i)); } } results.count=filteredMovies.size(); results.values=filteredMovies; }else { results.count=filterList.size(); results.values=filterList; } return results; } //PUBLISH RESULTS @Override protected void publishResults(CharSequence constraint, FilterResults results) { adapter.movies= (ArrayList<Movie>) results.values; adapter.notifyDataSetChanged(); } }
6. MainActivity.java
- Our launcher activity.
- References both our ListView and SearchView.
- Then sets the adapter to ListView.
- Listens to OnQueryTextChange events on the searchview.
package com.tutorials.hp.lvfilter; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.SearchView; import android.support.v7.widget.Toolbar; import android.view.View; import android.view.Menu; import android.view.MenuItem; import android.widget.AdapterView; import android.widget.ListView; import android.widget.Toast; import java.util.ArrayList; public class MainActivity extends AppCompatActivity { SearchView sv; ListView lv; MyAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); } }); sv= (SearchView) findViewById(R.id.mSearch); lv= (ListView) findViewById(R.id.lv); adapter=new MyAdapter(this,getMovies()); lv.setAdapter(adapter); sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { return false; } @Override public boolean onQueryTextChange(String query) { adapter.getFilter().filter(query); return false; } }); } private ArrayList<Movie> getMovies() { //COLECTION OF CRIME MOVIES ArrayList<Movie> movies=new ArrayList<>(); Movie movie=new Movie("BlackList",R.drawable.red); //ADD ITR TO COLLECTION movies.add(movie); movie=new Movie("Fruts",R.drawable.fruits); movies.add(movie); movie=new Movie("Breaking Bad",R.drawable.breaking); movies.add(movie); movie=new Movie("Crisis",R.drawable.crisis); movies.add(movie); movie=new Movie("Ghost Rider",R.drawable.rider); movies.add(movie); movie=new Movie("Star Wars",R.drawable.starwars); movies.add(movie); movie=new Movie("Shuttle Carrier",R.drawable.shuttlecarrier); movies.add(movie); movie=new Movie("Men In Black",R.drawable.meninblack); movies.add(movie); movie=new Movie("Game Of Thrones",R.drawable.thrones); movies.add(movie); return movies; } }