Android: Radio button in custom list view

Manoj Fegde picture Manoj Fegde · Jan 25, 2014 · Viewed 65.1k times · Source

I am developing an application in which I need to implement radio buttons in list view. I want to implement a list view having one radio button and two text view in each row. And one button "Ok" below listview.

What I have done is I created a list view and a custom adapter. The code of listview is as:

<ListView
    android:id="@+id/listview"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:cacheColorHint="#00000000"
    android:overScrollMode="never"
    tools:ignore="NestedScrolling"
    android:choiceMode="singleChoice" >
</ListView>

And I created a custom adapter layout as:

<?xml version="1.0" encoding="utf-8"?>
<TableLayout 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" >

    <TableRow
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        tools:ignore="UselessParent" >

        <RadioButton
            android:id="@+id/radiobutton"
            android:layout_width="0sp"
            android:layout_height="wrap_content"
            android:layout_weight=".1" />

        <TextView
            android:id="@+id/textview1"
            android:layout_width="0sp"
            android:layout_height="wrap_content"
            android:layout_weight=".3" />

        <TextView
            android:id="@+id/textview2"
            android:layout_width="0sp"
            android:layout_height="wrap_content"
            android:layout_weight=".3" />

    </TableRow>

</TableLayout>

The java code of fragment is as follows:

ListView listView = (ListView) view.findViewById(R.id.listview);

// values is a StringArray holding some string values.
CustomAdapter customAdapter = new CustomAdapter (getActivity(), values);
listView.setAdapter(customAdapter );
listView.setOnItemClickListener(this);

@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) {}

And the code of adapter is as follows:

public class CustomAdapter extends ArrayAdapter<String> {   
    /** Global declaration of variables. As there scope lies in whole class. */
    private Context context;
    private String[] listOfValues;

    /** Constructor Class */
    public CustomAdapter (Context c,String[] values) {
        super(c,R.layout.adapter_layout,values);
        this.context = c;
        this.listOfValues = values;
    }

    /** Implement getView method for customizing row of list view. */
    public View getView(final int position, View convertView, ViewGroup parent) {
        LayoutInflater inflater = ((Activity)context).getLayoutInflater();
        // Creating a view of row.
        View rowView = inflater.inflate(R.layout.adapter_layout, parent, false);

            TextView textView1 = (TextView)rowView.findViewById(R.id.textview1);
            TextView textView2 = (TextView)rowView.findViewById(R.id.textview2);

            RadioButton radioButton = (RadioButton) rowView.findViewById(R.id.radiobutton);

            radioButton.setOnClickListener(new OnClickListener() {          
            @Override   
            public void onClick(View v) {
                Toast.makeText(context, CustomAdapter[position], Toast.LENGTH_SHORT).show();
            }
        });

        return rowView;
    }
}    

The data of textview1 are populated from SQLite database and on textview2 the data are "Status Closed". And on selection of or by clicking any radio button the text of text view get changed to "Status Open".

The Issue is: The need of application is that only one radio button should get select and data of textview2 get change on selection. And when user click on the other radio button it get select and the previous one should get deselect and text of textview2 get changed to "Status Closed" of a previously selected radio button and clicked radio button to "Status Open".

Edit 1:

And onclick on "OK" button i want to get the position, text of list view textview1 and textview2, as i want to save that text in SQLite database in deview.

Please guide me what steps should I follow. I am in middle of my application. Your valuable guidance is required.

Answer

Brian Attwell picture Brian Attwell · Jan 25, 2014

Here are the key ideas

  • when a RadioButton is checked we must call notifyDataSetChanged(), so that all views get updated.
  • when a RadioButton is checked we must set a selectedPosition, to keep track of which RadioButton is selected
  • Views are recycled inside ListViews. Therefore, their absolute position changes in the ListView. Therefore, inside ListAdapter#getView(), we must call setTag() on each RadioButton. This allows us to determine the current position of the RadioButton in the list when the RadioButton is clicked.
  • RadioButton#setChecked() must be updated inside getView() for new or pre-existing Views.

Here is an example ArrayAdapter I wrote and tested in order to demonstrate these ideas

public class MainActivity extends ListActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // I do no use these values anywhere inside the ArrayAdapter. I could, but don't.
        final Integer[] values = new Integer[] {1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,};

        ArrayAdapter<Integer> adapter = new ArrayAdapter<Integer>(this, R.layout.row, R.id.textview, values) {

            int selectedPosition = 0;

            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                View v = convertView;
                if (v == null) {
                    LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                    v = vi.inflate(R.layout.row, null);
                    RadioButton r = (RadioButton)v.findViewById(R.id.radiobutton);
                }
                TextView tv = (TextView)v.findViewById(R.id.textview);
                tv.setText("Text view #" + position);
                RadioButton r = (RadioButton)v.findViewById(R.id.radiobutton);
                r.setChecked(position == selectedPosition);
                r.setTag(position);
                r.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        selectedPosition = (Integer)view.getTag();
                        notifyDataSetChanged();
                    }
                });
                return v;
            }

        };
        setListAdapter(adapter);
    }
}