Implementing ActionBarSherlock Search Collapsible View in Android

In this tutorial, you will learn how to implement ActionBarSherlock Search Collapsible View in your Android application. This way, the user can initiate a search directly from the actionbar and also preserve space in your listview layout. We will be using ActionBarSherlock Library to support lower API devices. The search functionality will filter the listview with a matching string from the users input. We will create a listview with a search collapsible view on the actionbar and on text input will filter the results and by clicking on the listview item will show the selected results on a new activity. So lets begin…

Prepare your project by importing the ActionBarSherlock Library. Refer to Implementing ActionBarSherlock in Android tutorial.

Create a new project in Eclipse File > New > Android Application Project. Fill in the details and name your project ABSSearchView.

Application Name : ABSSearchView

Project Name : ABSSearchView

Package Name : com.androidbegin.abssearchview

Open your MainActivity.java and paste the following code.

MainActivity.java

package com.androidbegin.abssearchview;

import java.util.ArrayList;
import java.util.Locale;

import com.actionbarsherlock.app.SherlockActivity;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.actionbarsherlock.view.MenuItem.OnActionExpandListener;
import com.actionbarsherlock.view.MenuItem.OnMenuItemClickListener;

import android.content.Context;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;

public class MainActivity extends SherlockActivity {

	// Declare Variables
	ListView list;
	ListViewAdapter adapter;
	EditText editsearch;
	String[] rank;
	String[] country;
	String[] population;
	ArrayList<WorldPopulation> arraylist = new ArrayList<WorldPopulation>();

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.listview_main);

		// Generate sample data
		rank = new String[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" };

		country = new String[] { "China", "India", "United States",
				"Indonesia", "Brazil", "Pakistan", "Nigeria", "Bangladesh",
				"Russia", "Japan" };

		population = new String[] { "1,354,040,000", "1,210,193,422",
				"315,761,000", "237,641,326", "193,946,886", "182,912,000",
				"170,901,000", "152,518,015", "143,369,806", "127,360,000" };

		// Locate the ListView in listview_main.xml
		list = (ListView) findViewById(R.id.listview);

		for (int i = 0; i < rank.length; i++) {
			WorldPopulation wp = new WorldPopulation(rank[i], country[i],
					population[i]);
			// Binds all strings into an array
			arraylist.add(wp);
		}

		// Pass results to ListViewAdapter Class
		adapter = new ListViewAdapter(this, arraylist);

		// Binds the Adapter to the ListView
		list.setAdapter(adapter);
	}

	// Create the options menu
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Get the options menu view from menu.xml in menu folder
		getSupportMenuInflater().inflate(R.menu.menu, menu);

		// Locate the EditText in menu.xml
		editsearch = (EditText) menu.findItem(R.id.menu_search).getActionView();

		// Capture Text in EditText
		editsearch.addTextChangedListener(textWatcher);

		// Show the search menu item in menu.xml
		MenuItem menuSearch = menu.findItem(R.id.menu_search);

		menuSearch.setOnActionExpandListener(new OnActionExpandListener() {

			// Menu Action Collapse
			@Override
			public boolean onMenuItemActionCollapse(MenuItem item) {
				// Empty EditText to remove text filtering
				editsearch.setText("");
				editsearch.clearFocus();
				return true;
			}

			// Menu Action Expand
			@Override
			public boolean onMenuItemActionExpand(MenuItem item) {
				// Focus on EditText
				editsearch.requestFocus();

				// Force the keyboard to show on EditText focus
				InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
				imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
				return true;
			}
		});

		// Show the settings menu item in menu.xml
		MenuItem menuSettings = menu.findItem(R.id.menu_settings);

		// Capture menu item clicks
		menuSettings.setOnMenuItemClickListener(new OnMenuItemClickListener() {

			@Override
			public boolean onMenuItemClick(MenuItem item) {
				// TODO Auto-generated method stub
				// Do something here
				Toast.makeText(getApplicationContext(), "Nothing here!",
						Toast.LENGTH_LONG).show();
				return false;
			}

		});

		return true;
	}

	// EditText TextWatcher
	private TextWatcher textWatcher = new TextWatcher() {

		@Override
		public void afterTextChanged(Editable s) {
			// TODO Auto-generated method stub
			String text = editsearch.getText().toString()
					.toLowerCase(Locale.getDefault());
			adapter.filter(text);
		}

		@Override
		public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
				int arg3) {
			// TODO Auto-generated method stub

		}

		@Override
		public void onTextChanged(CharSequence arg0, int arg1, int arg2,
				int arg3) {
			// TODO Auto-generated method stub

		}

	};
}

In this activity, we have created string arrays with sample data and pass it into the ListViewAdapter class. On listview item click will pass the selected position and string arrays to a new activity. An EditText will capture user input as a search parameter and pass it to the filter function in ListViewAdapter. Using OnActionExpandListener allows you to customize the way how the collapsible works on your actionbar.

Next, create an XML graphical layout for your search layout. Go to res > layout > Right Click on layout > New > Android XML File
Name your new XML file search_layout.xml and paste the following code.

search_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<EditText xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:cursorVisible="true"
    android:hint="@string/search_hint"
    android:imeOptions="actionDone"
    android:inputType="text" >

</EditText>

Output:

Search Edittext

Next, create an XML graphical layout for your menu. Go to res > menu > Right Click on menu New > Android XML File
Name your new XML file search_layout.xml and paste the following code.

menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:id="@+id/menu_settings"
        android:icon="@drawable/ic_action_settings"
        android:orderInCategory="100"
        android:showAsAction="always"
        android:title="@string/menu_settings"/>
    <item
        android:id="@+id/menu_search"
        android:actionLayout="@layout/search_layout"
        android:icon="@drawable/ic_action_search"
        android:orderInCategory="0"
        android:showAsAction="always|collapseActionView"
        android:title="Search"/>

</menu>

Output:

Menu Items

We have prepared some sample icons for this tutorial. Insert your downloaded sample images into your res > drawable-hdpi.

Sample Icons

[wpfilebase tag=file id=52 tpl=download-button /]

Next, create an array class. Go to File > New > Class and name it WorldPopulation.java. Select your package named com.androidbegin.abssearchview and click Finish.

Open your WorldPopulation.java and paste the following code.

WorldPopulation.java

package com.androidbegin.abssearchview;

public class WorldPopulation {
	private String rank;
	private String country;
	private String population;

	public WorldPopulation(String rank, String country, String population) {
		this.rank = rank;
		this.country = country;
		this.population = population;
	}

	public String getRank() {
		return this.rank;
	}

	public String getCountry() {
		return this.country;
	}

	public String getPopulation() {
		return this.population;
	}
}

Next, create an XML graphical layout for your MainActivity. Go to res > layout > Right Click on layout > New > Android XML File
Name your new XML file listview_main.xml and paste the following code.

listview_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <ListView
        android:id="@+id/listview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

</RelativeLayout>

Next, create a ListViewAdapter class. Go to File > New > Class and name it ListViewAdapter.java. Select your package named com.androidbegin.abssearchview and click Finish.

Open your ListViewAdapter.java and paste the following code.

ListViewAdapter.java

package com.androidbegin.abssearchview;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import android.view.View.OnClickListener;

public class ListViewAdapter extends BaseAdapter {

	// Declare Variables
	Context mContext;
	LayoutInflater inflater;
	private List<WorldPopulation> worldpopulationlist = null;
	private ArrayList<WorldPopulation> arraylist;

	public ListViewAdapter(Context context, List<WorldPopulation> worldpopulationlist) {
		mContext = context;
		this.worldpopulationlist = worldpopulationlist;
		inflater = LayoutInflater.from(mContext);
		this.arraylist = new ArrayList<WorldPopulation>();
		this.arraylist.addAll(worldpopulationlist);
	}

	public class ViewHolder {
		TextView rank;
		TextView country;
		TextView population;
	}

	@Override
	public int getCount() {
		return worldpopulationlist.size();
	}

	@Override
	public WorldPopulation getItem(int position) {
		return worldpopulationlist.get(position);
	}

	@Override
	public long getItemId(int position) {
		return position;
	}

	public View getView(final int position, View view, ViewGroup parent) {
		final ViewHolder holder;
		if (view == null) {
			holder = new ViewHolder();
			view = inflater.inflate(R.layout.listview_item, null);
			// Locate the TextViews in listview_item.xml
			holder.rank = (TextView) view.findViewById(R.id.rank);
			holder.country = (TextView) view.findViewById(R.id.country);
			holder.population = (TextView) view.findViewById(R.id.population);
			view.setTag(holder);
		} else {
			holder = (ViewHolder) view.getTag();
		}
		// Set the results into TextViews
		holder.rank.setText(worldpopulationlist.get(position).getRank());
		holder.country.setText(worldpopulationlist.get(position).getCountry());
		holder.population.setText(worldpopulationlist.get(position).getPopulation());

		// Listen for ListView Item Click
		view.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {
				// Send single item click data to SingleItemView Class
				Intent intent = new Intent(mContext, SingleItemView.class);
				// Pass all data rank
				intent.putExtra("rank",(worldpopulationlist.get(position).getRank()));
				// Pass all data country
				intent.putExtra("country",(worldpopulationlist.get(position).getCountry()));
				// Pass all data population
				intent.putExtra("population",(worldpopulationlist.get(position).getPopulation()));
				// Start SingleItemView Class
				mContext.startActivity(intent);
			}
		});

		return view;
	}

	// Filter Class
	public void filter(String charText) {
		charText = charText.toLowerCase(Locale.getDefault());
		worldpopulationlist.clear();
		if (charText.length() == 0) {
			worldpopulationlist.addAll(arraylist);
		} 
		else 
		{
			for (WorldPopulation wp : arraylist) 
			{
				if (wp.getCountry().toLowerCase(Locale.getDefault()).contains(charText)) 
				{
					worldpopulationlist.add(wp);
				}
			}
		}
		notifyDataSetChanged();
	}

}

In this custom listview adapter class, string arrays are passed into the ListViewAdapter and set into the TextViews followed by the positions. On listview item click will pass the string arrays and position to a new activity. The filter class captures the user input text from the MainActivity and refreshes the listview to show a matched result.

Next, create an XML graphical layout for your listview item. Go to res > layout > Right Click on layout > New > Android XML File

Name your new XML file listview_item.xml and paste the following code.

listview_item.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <TextView
        android:id="@+id/ranklabel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/ranklabel" />

    <TextView
        android:id="@+id/rank"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@+id/ranklabel" />

    <TextView
        android:id="@+id/countrylabel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/ranklabel"
        android:text="@string/countrylabel" />

    <TextView
        android:id="@+id/country"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/rank"
        android:layout_toRightOf="@+id/countrylabel" />

    <TextView
        android:id="@+id/populationlabel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/countrylabel"
        android:text="@string/populationlabel" />

    <TextView
        android:id="@+id/population"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/country"
        android:layout_toRightOf="@+id/populationlabel" />

</RelativeLayout>

Next, create an activity to display results. Go to File > New > Class and name it SingleItemView.java. Select your package named com.androidbegin.abssearchview and click Finish.

Open your SingleItemView.java and paste the following code.

SingleItemView.java

package com.androidbegin.abssearchview;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.inputmethod.InputMethodManager;
import android.widget.TextView;

public class SingleItemView extends Activity {
	// Declare Variables
	TextView txtrank;
	TextView txtcountry;
	TextView txtpopulation;
	String rank;
	String country;
	String population;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.singleitemview);
		// Hide the keyboard
		InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
	    imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);
		// Retrieve data from MainActivity on item click event
		Intent i = getIntent();
		// Get the results of rank
		rank = i.getStringExtra("rank");
		// Get the results of country
		country = i.getStringExtra("country");
		// Get the results of population
		population = i.getStringExtra("population");

		// Locate the TextViews in singleitemview.xml
		txtrank = (TextView) findViewById(R.id.rank);
		txtcountry = (TextView) findViewById(R.id.country);
		txtpopulation = (TextView) findViewById(R.id.population);

		// Load the results into the TextViews
		txtrank.setText(rank);
		txtcountry.setText(country);
		txtpopulation.setText(population);
	}
}

In this activity, strings are retrieved from the ListViewAdapter by using Intent and sets into the TextViews.

Next, create an XML graphical layout for your SingleItemView. Go to res > layout > Right Click on layout > New > Android XML File

Name your new XML file singleitemview.xml and paste the following code.

singleitemview.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <TextView
        android:id="@+id/ranklabel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/ranklabel" />

    <TextView
        android:id="@+id/rank"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@+id/ranklabel" />

    <TextView
        android:id="@+id/countrylabel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/ranklabel"
        android:text="@string/countrylabel" />

    <TextView
        android:id="@+id/country"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/rank"
        android:layout_toRightOf="@+id/countrylabel" />

    <TextView
        android:id="@+id/populationlabel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/countrylabel"
        android:text="@string/populationlabel" />

    <TextView
        android:id="@+id/population"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/country"
        android:layout_toRightOf="@+id/populationlabel" />

</RelativeLayout>

Next, change the application name and texts. Open your strings.xml in your res > values folder and paste the following code.

strings.xml

<resources>

    <string name="app_name">ABS Search View</string>
    <string name="hello_world">Hello world!</string>
    <string name="menu_settings">Settings</string>
    <string name="title_activity_main">ABS Search View</string>
    <string name="search_hint">Search hint</string>
     <string name="ranklabel">"Rank : "</string>
    <string name="countrylabel">"Country : "</string>
    <string name="populationlabel">"Population : "</string>

</resources>

In your AndroidManifest.xml, we need to change the theme style to “Theme.Sherlock” and set your preferable Android minimum SDK version. Open your AndroidManifest.xml and paste the following code.

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.androidbegin.abssearchview"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="7"
        android:targetSdkVersion="15" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/Theme.Sherlock" >
        <activity
            android:name=".MainActivity"
            android:label="@string/title_activity_main" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".SingleItemView" >
        </activity>
    </application>

</manifest>
Output:

ABS Search View ScreenShot

Source Code

[purchase_link id=”7954″ text=”Purchase to Download Source Code” style=”button” color=”green”]

Latest comments

how to make action bar sherlock search data from JSON?

samuel marpaung

Implementing ActionBarSherlock Search Collapsible View in Android

Sorry men but you code generate the error "aapt return error 139"

cc69cc

Implementing ActionBarSherlock Search Collapsible View in Android

thank, it's work :D

cc69cc

Implementing ActionBarSherlock Search Collapsible View in Android

Hi cc69cc, you can use ArrayAdapter if you want to. This tutorial basically just explain how things work. Thanks :)

AndroidBegin

Implementing ActionBarSherlock Search Collapsible View in Android