I liked Carlos Sessa solution from his book "50 Android hacks".
my activity_favorites.xml looks like this:
<?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/favContainer"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:choiceMode="singleChoice"/>
</RelativeLayout>
My FavoritesActivity.java looks like this:
package com.myproject;
import java.util.ArrayList;
import com.myproject.R;
import com.myproject.model.Package;
import com.myproject.adapter.FavoritesPackageArrayAdapter;
import com.myproject.utils.DatabaseHelper;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.Window;
import android.widget.ListView;
public class FavoritesActivity extends Activity
{
protected ListView list;
protected String selectedPackage;
protected ArrayList<Package> packages;
protected FavoritesPackageArrayAdapter adapter;
private DatabaseHelper db = new DatabaseHelper(this);
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_favorites);
packages = db.getPackages();
adapter = new FavoritesPackageArrayAdapter(this, -1, packages);
list = (ListView) findViewById(R.id.favContainer);
list.setAdapter(adapter);
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void onSelect(View view)
{
int pos = list.getCheckedItemPosition();
if(ListView.INVALID_POSITION != pos)
selectedPackage = packages.get(pos).getId();
}
}
My ListView adapter (FavoritesPackageArrayAdapter.java) is quite simple:
package com.myproject.adapter;
import java.util.List;
import com.myproject.model.Package;
import com.myproject.view.PackageView;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
public class FavoritesPackageArrayAdapter extends ArrayAdapter<Package>
{
public FavoritesPackageArrayAdapter(Context context, int resource, List<Package> objects)
{
super(context, resource, objects);
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
if(convertView == null)
convertView = new PackageView(getContext());
Package pack = getItem(position);
PackageView packView = (PackageView) convertView;
packView.setPackage(pack);
return convertView;
}
}
In order to have list items checkable, your view has to implement Checkable interface.
My PackageView.java looks like:
package com.myproject.view;
import java.util.ArrayList;
import com.myproject.R;
import com.myproject.model.Package;
import com.myproject.model.PackageEvent;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Checkable;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.CheckBox;
public class PackageView extends LinearLayout implements Checkable
{
private View v;
private TextView tv0;
private TextView tv1;
private TextView tv2;
private TextView tv3;
private CheckBox testCheckBox;
public PackageView(Context context)
{
super(context);
LayoutInflater inflater = LayoutInflater.from(context);
v = inflater.inflate(R.layout.favorites_package, this, true);
tv0 = (TextView) v.findViewById(R.id.favPackageId);
tv1 = (TextView) v.findViewById(R.id.favEventDate);
tv2 = (TextView) v.findViewById(R.id.favEventAddres);
tv3 = (TextView) v.findViewById(R.id.favEventState);
// I don't have checkbox in my layout, but if I had:
// testCheckBox = (CheckBox) v.findViewById(R.id.checkBoxId);
}
public void setPackage(Package pack)
{
// my custom method where I set package id, date, and time
...
}
private Boolean checked = false;
@Override
public boolean isChecked()
{
return checked;
// if I had checkbox in my layout I could
// return testCheckBox.checked();
}
@Override
public void setChecked(boolean checked)
{
this.checked = checked;
// since I choose not to have check box in my layout, I change background color
// according to checked state
if(isChecked())
...
else
...
// if I had checkbox in my layout I could
// testCheckBox.setChecked(checked);
}
@Override
public void toggle()
{
checked = !checked;
// if I had checkbox in my layout I could
// return testCheckBox.toggle();
}
}
And finally xml layout of each list item (favorites_package.xml):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/favPackageId"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<LinearLayout
android:id="@+id/favTimeDateContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weightSum="1">
<TextView
android:id="@+id/favEventDate"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.5"/>
<TextView
android:id="@+id/favEventAddres"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.5"/>
</LinearLayout>
<TextView
android:id="@+id/favEventState"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
If you wanted to have actual checkbox in your layout it's xml should look something like:
<CheckBox
android:id="@+id/checkBoxId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"/>
If you left checkbox clickable, you could only check it only by clicking on checkbox itself.
Also don't make your layout clickable, for some reason it doesn't work with Checkable interface.