Android: Radio button in custom list view
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 views in each row. And one button "Ok" below listview.
What I have done is 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 the 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 review;
}
}
The data of textview1 are populated from SQLite database and on textview2 the data are "Status Closed". And on the selection of or by clicking any radio button the text of text view gets changed to "Status Open".
The Issue is: The need of application is that only one radio button should get selected and data of textview2 get a change on selection. And when the user clicks on the other radio button it gets select and the previous one should get deselect and the text of textview2 gets changed to "Status Closed" of a previously selected radio button and clicked radio button to "Status Open".
Edit 1:
And click on the "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 the review.
Please guide me on what steps should I follow. I am in the middle of my application. Your valuable guidance is required.
Solution 1:
Here are the key ideas
- when a
RadioButton
is checked we must callnotifyDataSetChanged()
, so that all views get updated. - when a
RadioButton
is checked we must set aselectedPosition
, to keep track of whichRadioButton
is selected -
View
s are recycled insideListView
s. Therefore, their absolute position changes in theListView
. Therefore, insideListAdapter#getView()
, we must callsetTag()
on eachRadioButton
. This allows us to determine the current position of theRadioButton
in the list when theRadioButton
is clicked. -
RadioButton#setChecked()
must be updated insidegetView()
for new or pre-existingView
s.
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);
}
}
Solution 2:
Try below adapter :
public class ChooseAdapter extends ArrayAdapter<LinkedHashMap<String, String>> {
private ArrayList<LinkedHashMap<String, String>> listMenu;
int position_id;
private LayoutInflater inflater;
Context context;
public ChooseAdapter(Activity activity,
ArrayList<LinkedHashMap<String, String>> listMenu, int type) {
super(activity, R.layout.choose_single_item, listMenu);
this.listMenu = listMenu;
context = activity.getApplicationContext();
inflater = LayoutInflater.from(context);
}
public int getCount() {
return listMenu.size();
}
public long getItemId(int position) {
return position;
}
public static class ViewHolder
{
public CheckBox chk;
}
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder view;
if (convertView == null) {
view = new ViewHolder();
convertView = inflater.inflate(R.layout.choose_single_item, null);
view.chk = (CheckBox) convertView
.findViewById(R.id.selection_checkbox);
view.chk.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
// TODO Auto-generated method stub
if (isChecked) {
listMenu.get((Integer) buttonView.getTag()).put(
"checked", "true");
for (int i = 0; i < listMenu.size(); i++) {
if (i != (Integer) buttonView.getTag()) {
if (listMenu.get(i).containsKey("checked"))
listMenu.get(i).remove("checked");
}
}
} else {
listMenu.get((Integer) buttonView.getTag()).remove(
"checked");
}
notifyDataSetChanged();
}
});
convertView.setTag(R.id.selection_checkbox, view.chk);
convertView.setTag(view);
}
else {
view = (ViewHolder) convertView.getTag();
}
view.chk.setTag(position);
view.chk.setText(listMenu.get(position).get("name"));
if (listMenu.get(position).containsKey("checked")) {
view.chk.setChecked(true);
} else
view.chk.setChecked(false);
return convertView;
}
}
And the layout that I am inflating is :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<CheckBox
android:id="@+id/selection_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="abc"
android:textColor="#8C8C8C"
android:textSize="16sp" />
</LinearLayout>
Here, I have used the checkbox, you can also use radiobutton instead of it, nothing else is needed to change.
Hope it helps!