-
Notifications
You must be signed in to change notification settings - Fork 260
MultiChoiceBaseAdapter tutorial
The previous tutorial showed how to create a very simple list using MultiChoiceArrayAdapter. For more complex needs, you'll need the extra flexibility provided by MultiChoiceBaseAdapter. This tutorial will teach you how to use this class to create a list where items have two text fields and a checkbox.
Create a new Android project using Maven or your IDE of choice, and add references to the ActionBarSherlock and MultiChoiceAdapter library projects.
Add a new activity called MainActivity, and make it derive from SherlockActivity. Edit the XML layout for this activity so that it looks like this:
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@android:id/list" />
Now you need an adapter to provide the ListView with items to display. Each item will be an instance of the following class:
public class Building {
public String name;
public String height;
public Building(String name, String height) {
this.name = name;
this.height = height;
}
}
The layout for the items will be the following:
<com.manuelpeinado.multichoiceadapter.CheckableRelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="false"
android:minHeight="64dp"
android:orientation="horizontal"
android:paddingLeft="6dp"
android:paddingRight="6dp" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_toLeftOf="@android:id/checkbox"
android:orientation="vertical" >
<TextView
android:id="@android:id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="@android:id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
<CheckBox
android:id="@android:id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:focusable="false" />
</com.manuelpeinado.multichoiceadapter.CheckableRelativeLayout>
Note that you have to use CheckableRelativeLayout
, which is a version of RelativeLayout
that implements the Checkable interface and has a separate background for the checked state.
Now you have all the pieces you need to implement the adapter:
public class BuildingsAdapter extends MultiChoiceBaseAdapter {
private List<Building> items;
public BuildingsAdapter(Bundle savedInstanceState, List<Building> items) {
super(savedInstanceState);
this.items = items;
}
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.my_action_mode, menu);
return true;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
if (item.getItemId() == R.id.menu_share) {
Toast.makeText(getContext(), "Share", Toast.LENGTH_SHORT).show();
return true;
}
return false;
}
@Override
public int getCount() {
return items.size();
}
@Override
public Building getItem(int position) {
return items.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
@Override
protected View getViewImpl(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
int layout = R.layout.list_item;
LayoutInflater inflater = LayoutInflater.from(getContext());
convertView = inflater.inflate(layout, parent, false);
}
ViewGroup group = (ViewGroup)convertView;
Building building = getItem(position);
((TextView)group.findViewById(android.R.id.text1)).setText(building.name);
((TextView)group.findViewById(android.R.id.text2)).setText(building.height);
return group;
}
}
Now that you have your adapter class ready you can bind it to the ListView. At the end of MainActivity's onCreate method:
ListView listView = (ListView)findViewById(android.R.id.list);
List<Building> items = Arrays.asList(new Building("One World Trade Center", "541 m"), new Building("Empire State Building", "443 m"), new Building("Bank of America Building", "319 m"), new Building("Chrysler Building", "319 m");
adapter = new BuildingsAdapter(savedInstanceState, this, items);
adapter.setAdapterView(listView);
adapter.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
Toast.makeText(this, "Item click: " + adapter.getItem(position), Toast.LENGTH_SHORT).show();
}
});
Finally you shouldn't forget to persist your adapter's state:
@Override
protected void onSaveInstanceState(Bundle outState) {
adapter.save(outState);
}