Android: Radio Button in Custom List View

Android: Radio button in custom list view

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);
}
}

Custom ListView with RadioButton single choice

Try like this :

public class CheckedLinearLayout extends RelativeLayout implements
Checkable {

private boolean isChecked;
private List<Checkable> checkableViews;

public CheckedLinearLayout (Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
initialise(attrs);
}

public CheckedLinearLayout (Context context, AttributeSet attrs) {
super(context, attrs);
initialise(attrs);
}

public CheckedLinearLayout (Context context, int checkableId) {
super(context);
initialise(null);
}

public boolean isChecked() {
return isChecked;
}

public void setChecked(boolean isChecked) {
this.isChecked = isChecked;
for (Checkable c : checkableViews) {
c.setChecked(isChecked);
}
}
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));
}
}
}
}

Android ListView with RadioButton in singleChoice mode and a custom row layout

Do bear in mind that in the ListView row items are RECYCLED. This is likely to explain why actions on one row are affecting another. Dig around in Mark's book and you'll find coverage of this.

If you're using an adapter with the list, you can use getView() on an adapter to add a click handler to each row as it's created/recycled, and make sure the state is managed correctly as the row items are created and recycled.

My approach is to store the state in my own data structure, and then use getView() to mirror that in the UI as the user scrolls up and down the ListView. There may be a better solution, but that works for me.



Related Topics



Leave a reply



Submit