Lets begin with the CheckableRelativeLayout.
src/CheckableRelativeLayout.java
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Checkable;
import android.widget.RelativeLayout;
/**
* Extension of a relative layout to provide a checkable behaviour
*
* @author marvinlabs
*/
public class CheckableRelativeLayout extends RelativeLayout implements
Checkable {
private boolean isChecked;
private List<Checkable> checkableViews;
public CheckableRelativeLayout(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
initialise(attrs);
}
public CheckableRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
initialise(attrs);
}
public CheckableRelativeLayout(Context context, int checkableId) {
super(context);
initialise(null);
}
/*
* @see android.widget.Checkable#isChecked()
*/
public boolean isChecked() {
return isChecked;
}
/*
* @see android.widget.Checkable#setChecked(boolean)
*/
public void setChecked(boolean isChecked) {
this.isChecked = isChecked;
for (Checkable c : checkableViews) {
c.setChecked(isChecked);
}
}
/*
* @see android.widget.Checkable#toggle()
*/
public void toggle() {
this.isChecked = !this.isChecked;
for (Checkable c : checkableViews) {
c.toggle();
}
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
final int childCount = this.getChildCount();
for (int i = 0; i < childCount; ++i) {
findCheckableChildren(this.getChildAt(i));
}
}
/**
* Read the custom XML attributes
*/
private void initialise(AttributeSet attrs) {
this.isChecked = false;
this.checkableViews = new ArrayList<Checkable>(5);
}
/**
* Add to our checkable list all the children of the view that implement the
* interface Checkable
*/
private void findCheckableChildren(View v) {
if (v instanceof Checkable) {
this.checkableViews.add((Checkable) v);
}
if (v instanceof ViewGroup) {
final ViewGroup vg = (ViewGroup) v;
final int childCount = vg.getChildCount();
for (int i = 0; i < childCount; ++i) {
findCheckableChildren(vg.getChildAt(i));
}
}
}
}
After that just use it in your XML layout files, make it part of your package and use syntax <org.mypackage.myapp.CheckableRelativeLayout>
Our testclass Team, which we want to populate the ListView with.
src/Team.java
public class Team {
private String teamName;
private int teamWins;
public Team(String name, int wins)
{
teamName = name;
teamWins = wins;
}
public String getTeamName() {
return teamName;
}
public int getTeamWins() {
return teamWins;
}
}
Simple class for testing purposes, next up we build our ListView layout, what each row will look like.
I decided on a CheckBox (the new one as the old one felt big), and two TextViews to display the teamname & team wins. (Remember to look at the CheckableRelativeLayout class above as this isn't working with the normal containers.)
layout/row_team_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<se.adanware.listviewexample.CheckableRelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<!-- We dont want to be able to click the CheckBox -
android:clickable="false" added.
CheckableRelativeLayout takes care of the toggle when clicking the row -->
<CheckBox
android:id="@+id/myCheckBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="false"
android:clickable="false"
android:layout_alignParentLeft="true"
android:background="@drawable/customcheckbox_background"
android:button="@drawable/customcheckbox"
/>
<TextView
android:id="@+id/listview_TeamDescription"
android:focusable="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FFFFFF"
android:textSize="16sp"
android:layout_toRightOf="@id/myCheckBox"
android:layout_centerVertical="true"
/>
<TextView
android:id="@+id/listview_TeamWins"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FFFFFF"
android:textSize="16sp"
android:paddingRight="5dp"
android:layout_centerVertical="true"
android:focusable="false"
android:layout_alignParentRight="true"
/>
</se.adanware.listviewexample.CheckableRelativeLayout>
I'm still targeting the earlier Android version so i've taken the new checkbox from the SDK.
drawable-hdpi/customcheckbox.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="false"
android:drawable="@drawable/btn_check_off_holo_dark" />
<item android:state_checked="true"
android:drawable="@drawable/btn_check_on_holo_dark" />
</selector>
drawable-hdp/customcheckbox_background.xml<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/btn_check_label_background" />
</selector>
btn_check_label_background.9.png |
btn_check_on_holo_dark.png |
btn_check_off_holo_dark.png |
src/TeamListViewAdapter.java
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import java.util.ArrayList;
public class TeamListViewAdapter extends ArrayAdapter<Team>
{
View row;
ArrayList<Team> myTeams;
int resLayout;
Context context;
public TeamListViewAdapter(Context context, int textViewResourceId, ArrayList<Team> myTeams) {
super(context, textViewResourceId, myTeams);
this.myTeams = myTeams;
resLayout = textViewResourceId;
this.context = context;
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
row = convertView;
if(row == null)
{ // inflate our custom layout. resLayout == R.layout.row_team_layout.xml
LayoutInflater ll = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = ll.inflate(resLayout, parent, false);
}
Team item = myTeams.get(position); // Produce a row for each Team.
if(item != null)
{ // Find our widgets and populate them with the Team data.
TextView myTeamDescription = (TextView) row.findViewById(R.id.listview_TeamDe scription);
TextView myTeamWins = (TextView) row.findViewById(R.id.listview_TeamWins);
if(myTeamDescription != null)
myTeamDescription.setText(item.getTeamName());
if(myTeamWins != null)
myTeamWins.setText("Wins: " + String.valueOf(item.getTeamWins()));
}
return row;
}
}
Okay! Now we just need to make the root layout and our start activity! First a simple layout:
res/main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Checkable Listview Example"
/>
<Button android:id="@+id/buttonStart"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:text="Start tournament with selected teams"
/>
<ListView android:id="@+id/myListView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:choiceMode="multipleChoice"/>
</LinearLayout>
Nothing unusual here, android:choiceMode="multipleChoice" cant be omitted.
It can also be set from code with myListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
There's also android:choiceMode="singleChoice" if you just want a single item checked.
If not set the ListView.getCheckedItemPositions() method will return a null SparseBooleanArray.
Finally we come to our startup activity!
src/ListViewExample.java
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.View;
import android.widget.*;
import java.util.ArrayList;
public class ListViewExample extends Activity
{
ArrayList<Team> myTeams;
TeamListViewAdapter myAdapter;
ListView myListView;
Button myButton;
@Override
public void onCreate(Bundle savedInstanceState)
{
myTeams = new ArrayList<Team>();
// Add a few teams to display.
myTeams.add(new Team("Winners", 10));
myTeams.add(new Team("Philidelphia Flyers", 5));
myTeams.add(new Team("Detroit Red Wings", 1));
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
myListView = (ListView) findViewById(R.id.myListView);
myButton = (Button) findViewById(R.id.buttonStart);
// Construct our adapter, using our own layout and myTeams
myAdapter = new TeamListViewAdapter(this, R.layout.row_team_layout, myTeams );
myListView.setAdapter(myAdapter);
myListView.setItemsCanFocus(false);
myButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ArrayList<Team> selectedTeams = new ArrayList<Team>();
final SparseBooleanArray checkedItems = myListView.getCheckedItemPositions();
int checkedItemsCount = checkedItems.size();
for (int i = 0; i < checkedItemsCount; ++i) {
// Item position in adapter
int position = checkedItems.keyAt(i);
// Add team if item is checked == TRUE!
if(checkedItems.valueAt(i))
selectedTeams.add(myAdapter.getItem(position));
}
if(selectedTeams.size() < 2)
Toast.makeText(getBaseContext(), "Need to select two or more teams.", Toast .LENGTH_SHORT).show();
else
{
// Just logging the output.
for(Team t : selectedTeams)
Log.d("SELECTED TEAMS: ", t.getTeamName());
}
}
});
}
}
Thanks goes to http://www.marvinlabs.com/2010/10/custom-listview-ability-check-items/ for the elegant solution!
... Family time, nightie!
Hi Your Tutorial is perfect but i had a small problem whenever i click on the list item nothing is happening how to do that and you mentioned that Checkable interface and CheckableRelativeLayout i did not get what are those so COULD YOU PLEASE SEND THE SOURCE CODE OF ABOVE EXAMPLE to my mail id LAXMANAMAIL@GMAIL.COM waiting for your replay Thanx
SvaraRaderasame problem...unable to load checkableRelativeLayout..please if you could send me the code on snehalpoyrekar@gmail.com...I would really appreciate it..thanks
SvaraRaderaUpdated the blogpost, looks like the page hosting the CheckableRelativeLayout class is doing some rework.
RaderaClass is included at the top of the blogpost, should work after that.
Good luck!
For the android new comers like me...
SvaraRaderaDo not forget to set the package in the CheckableRelativeLayout !
hi
SvaraRaderai am using a custom row including a Spinner and a Checkbox,
i don't know how , but the spinner seems to intercept the touch and the RelativeLayout above don't do the work
could anyone help plz
Don't really understand what you're trying to do. You have a spinner in each row to select 'something', then a checkbox to select the #s of spinner you want ?
RaderaYes it's like you say ...
RaderaTried it and it's like you said. Google solved it for me. Set tag android:descendantFocusability="blocksDescendants" in your RelativeLayout. You will not be able to focus the spinner with keyboard but clicking the spinner opens it, clicking the row activates the checkbox.
RaderaThe blogpost is currently available in 'The MarvinLabs Blog':
SvaraRaderahttp://blog.marvinlabs.com/2010/10/29/custom-listview-ability-check-items/
Congrats. Nice tutorial
SvaraRaderaI have used instructions, and I'm in position to retrieve my selected values, but my checkboxes are not selected, can someone help me please, I ve spent hours on.
Top 10 casino games, ranked: how to play, tips, bonuses
SvaraRaderaCasino games 양산 출장샵 online are 경산 출장안마 a part of the world of casino gaming. Casino games are 경기도 출장샵 some of the most 충주 출장안마 played 김천 출장샵 casino games in the world