What you learn: You will learn how to create new list adapters with several widgets in it and how you can catch selection events on them.
Difficulty: 2 of 5
What it will look like:
[align=center]
[/align]
Description:
This tutorial grew from another tutorial here which dealt with making lists with icons attached to each list item. (Checkbox Text List tutorial).
The original tutorial had several drawbacks:
* Missing right 'onCLick' handling for containing widgets
* No selection when using the arrow keys
* Checkbox will loose state while scrolling
* Initial values missed sometimes
The next tutorial will fix all those problems. I'll add code because the base code it two tutorials away, so it's useful to get it all.
1.
In order to be able to configure our list we need a class that holds all information each of our rows must have. It's the same taken from the previus tut but with a name change:
Using java Syntax Highlighting
- public class ExtendedCheckBox implements Comparable<ExtendedCheckBox>
- {
- private String mText = "";
- private boolean mChecked;
- public ExtendedCheckBox(String text, boolean checked)
- {
- /* constructor */
- mText = text;
- mChecked = checked;
- }
- public void setChecked(boolean value)
- {
- this.mChecked = value;
- }
- public boolean getChecked()
- {
- return this.mChecked;
- }
- public String getText() {
- return mText;
- }
- public void setText(String text) {
- mText = text;
- }
- /** Make CheckBoxifiedText comparable by its name */
- //@Override
- public int compareTo(ExtendedCheckBox other)
- {
- if(this.mText != null)
- return this.mText.compareTo(other.getText());
- else
- throw new IllegalArgumentException();
- }
- }
Parsed in 0.033 seconds, using GeSHi 1.0.8.4
2.
The next step will be to create our 'View'. The view is responsible to draw a single row in our elemnt list. Also the view handles internally when the checkbox should be toggled. The stuff that needs to be added are 2 OnClickListener's, one for the checkbox and one for the view itself.
The checkboxs listener is used to update our ExtendedCheckBox after the user clicked the checkbox, this way our data inthe checkbox and the ExtendedCheckBox will remein consitent.
The second listener will be used to handle clicks directly in the view, so that we will able to change the checkbox not only by clicking on it.
Here is the code:
Using java Syntax Highlighting
- import android.content.Context;
- import android.view.View;
- import android.widget.CheckBox;
- import android.widget.LinearLayout;
- import android.widget.TextView;
- public class ExtendedCheckBoxListView extends LinearLayout {
- private TextView mText;
- private CheckBox mCheckBox;
- private ExtendedCheckBox mCheckBoxText;
- public ExtendedCheckBoxListView(Context context, ExtendedCheckBox aCheckBoxifiedText) {
- super(context);
- // Set orientation to be horizontal
- this.setOrientation(HORIZONTAL);
- mCheckBoxText = aCheckBoxifiedText;
- mCheckBox = new CheckBox(context);
- mCheckBox.setPadding(0, 0, 20, 0);
- // Set the initial state of the checkbox.
- mCheckBox.setChecked(aCheckBoxifiedText.getChecked());
- // Set the right listener for the checkbox, used to update
- // our data holder to change it's state after a click too
- mCheckBox.setOnClickListener( new OnClickListener()
- {
- /**
- * When clicked change the state of the 'mCheckBoxText' too!
- */
- @Override
- public void onClick(View v) {
- mCheckBoxText.setChecked(getCheckBoxState());
- }
- });
- // Add the checkbox
- addView(mCheckBox, new LinearLayout.LayoutParams(
- LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
- mText = new TextView(context);
- mText.setText(aCheckBoxifiedText.getText());;
- addView(mText, new LinearLayout.LayoutParams(
- LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
- // Remove some controls in order to prevent a strange flickering when clicking on the TextView!
- mText.setClickable(false);
- mText.setFocusable(false);
- mText.setFocusableInTouchMode(false);
- setOnClickListener( new OnClickListener()
- {
- /**
- * Check or unchecked the current checkbox!
- */
- @Override
- public void onClick(View v) {
- toggleCheckBoxState();
- }
- });
- }
- public void setText(String words) {
- mText.setText(words);
- }
- public void toggleCheckBoxState()
- {
- setCheckBoxState(!getCheckBoxState());
- }
- public void setCheckBoxState(boolean bool)
- {
- mCheckBox.setChecked(bool);
- mCheckBoxText.setChecked(bool);
- }
- public boolean getCheckBoxState()
- {
- return mCheckBox.isChecked();
- }
- }
Parsed in 0.041 seconds, using GeSHi 1.0.8.4
3.
Now we need have to create our adapter, which will be the link between the actual data and the layout. The difference bewteen our adapter and the one in the previus tutorial that we never cache the view, we always create a new one. Once a new item is visible our layout will call getView(), the problem is that if we use the old view we could get some problems on data persistence. So the securest way is to build a new view.
Using java Syntax Highlighting
- import java.util.ArrayList;
- import java.util.List;
- import android.content.Context;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.BaseAdapter;
- public class ExtendedCheckBoxListAdapter extends BaseAdapter {
- /** Remember our context so we can use it when constructing views. */
- private Context mContext;
- private List<ExtendedCheckBox> mItems = new ArrayList<ExtendedCheckBox>();
- /**
- *
- * @param context - Render context
- */
- public ExtendedCheckBoxListAdapter(Context context) {
- mContext = context;
- }
- /**
- * Add a new Item at the end of the exiting ones
- * @param it - New item to be added
- */
- public void addItem(ExtendedCheckBox it) {
- mItems.add(it);
- }
- /**
- * Will force to use a list of items
- * @param lit - List of items to be used
- */
- public void setListItems(List<ExtendedCheckBox> lit) {
- mItems = lit;
- }
- /**
- * @return The number of items this adapter offers
- */
- public int getCount() {
- return mItems.size();
- }
- /**
- * Return item at a specific position
- */
- public Object getItem(int position) {
- return mItems.get(position);
- }
- /**
- * Returns the position of an element
- */
- public int GetPosition( ExtendedCheckBox item ) {
- int count = getCount();
- for ( int i = 0; i < count; i++ )
- {
- if ( item.compareTo((ExtendedCheckBox)getItem(i)) == 0 )
- return i;
- }
- return -1;
- }
- /**
- * Set selection of an item
- * @param value - true or false
- * @param position - position
- */
- public void setChecked(boolean value, int position) {
- mItems.get(position).setChecked(value);
- }
- /**
- * Select all elements
- */
- public void selectAll() {
- for(ExtendedCheckBox cboxtxt: mItems)
- cboxtxt.setChecked(true);
- /* Things have changed, do a redraw. */
- this.notifyDataSetInvalidated();
- }
- /**
- * Deselect all elements
- */
- public void deselectAll() {
- for(ExtendedCheckBox cboxtxt: mItems)
- cboxtxt.setChecked(false);
- /* Things have changed, do a redraw. */
- this.notifyDataSetInvalidated();
- }
- /**
- * Decides if all items are selectable
- * @return - true or false
- */
- public boolean areAllItemsSelectable() {
- return false;
- }
- /**
- * Use the array index as a unique id
- */
- public long getItemId(int position) {
- return position;
- }
- /**
- * Do not recycle a view if one is already there, if not the data could get corrupted and
- * the checkbox state could be lost.
- * @param convertView The old view to overwrite
- * @returns a CheckBoxifiedTextView that holds wraps around an CheckBoxifiedText */
- public View getView(int position, View convertView, ViewGroup parent ){
- return new ExtendedCheckBoxListView(mContext, mItems.get(position));
- }
- }
Parsed in 0.043 seconds, using GeSHi 1.0.8.4
4.
The final step (of code) is to build our activity. It's important to build a list activity and to add some functionalty to be able to toggle the checkbox while navigating with the arrows. You could create it as a base class for your lists so you reuse the code.
Every ListActivity has a method that is been called when the user selects a new item in the list by pressing 'enter' or the device 'accept' key (located in the center of the navigation keys). So just implement that methode and toggle the right item.
Using java Syntax Highlighting
- import android.app.ListActivity;
- import android.os.Bundle;
- import android.view.View;
- import android.widget.ListView;
- public class ExtendedCheckBoxList extends ListActivity {
- private ExtendedCheckBoxListAdapter mListAdapter;
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- // Build the list adapter
- mListAdapter = new ExtendedCheckBoxListAdapter(this);
- // Add some items
- for( int i = 1; i < 20; i++ )
- {
- String newItem = "Item " + i;
- mListAdapter.addItem( new ExtendedCheckBox(newItem,false));
- }
- // Bind it to the activity!
- setListAdapter(mListAdapter);
- }
- /**
- * If a list item is clicked
- * we need to toggle the checkbox too!
- */
- @Override
- protected void onListItemClick(ListView l, View v, int position, long id) {
- // Toggle the checkbox state!
- if ( v != null )
- {
- ExtendedCheckBoxListView CurrentView = (ExtendedCheckBoxListView)v;
- if ( CurrentView != null )
- {
- CurrentView.toggleCheckBoxState();
- }
- }
- super.onListItemClick(l, v, position, id);
- }
- }
Parsed in 0.041 seconds, using GeSHi 1.0.8.4
5.
Here you got the layout I used and the localized string
main.xml
Using xml Syntax Highlighting
- <?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">
- <ListView
- android:id="@android:id/list"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- android:scrollbars="vertical" />
- <TextView
- android:id="@android:id/empty"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:text="@string/No_Items"
- android:padding="10px" />
- </LinearLayout>
Parsed in 0.003 seconds, using GeSHi 1.0.8.4
strings.xml
Using xml Syntax Highlighting
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <string name="app_name">Extended Check Box List</string>
- <string name="No_Items">No Items!</string>
- </resources>
Parsed in 0.001 seconds, using GeSHi 1.0.8.4
So we finished, a nice pice of code. Now it's on your own to add more stuff to it. I attached all sources in a eclipse project.
Cheers,
Moss


