I am trying to modify my ListView so that it:
Contains an image
Contains a text description (fileName)
Contains a check box.
The list should be multi selectable. And I should be able to loop through all the checked checkboxes and get the description.
Currently, I can display an ordinary ListView with check boxes.
ArrayAdapter<String> ad = new ArrayAdapter<String>(HelloDropboxActivity.this, android.R.layout.simple_list_item_multiple_choice,fileName);
mTestListOutput.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
mTestListOutput.setAdapter(ad);
Using the onClick of a Button - I can loop through the checked boxes and get the text into an ArrayList like this:
ArrayList<String> dbLinks = new ArrayList<String>();
int cntChoice = mTestListOutput.getCount();
SparseBooleanArray sparseBooleanArray = mTestListOutput.getCheckedItemPositions();
for(int i = 0; i < cntChoice; i++)
{
if(sparseBooleanArray.get(i) == true)
{
dbLinks.add(mTestListOutput.getItemAtPosition(i).toString());
}
}
I am retreving an ArrayList of :
private ArrayList paths;
So how can I tie these together to create a custom ListView?
I have looked at many examples and tried to modify them but I am getting nowhere.
Here I have attampted to create the Layout of a list row in my list_row.xnl:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="5dip" >
<!-- Thumbnail image -->
<LinearLayout android:id="#+id/thumbnail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="3dip"
android:layout_alignParentLeft="true"
android:layout_marginRight="5dip">
<ImageView
android:id="#+id/list_image"
android:layout_width="50dip"
android:layout_height="50dip"
/>
</LinearLayout>
<!-- File Name -->
<TextView
android:id="#+id/filename"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#id/title"
android:textColor="#343434"
android:textSize="10dip"
android:layout_marginTop="1dip"
android:layout_toRightOf="#+id/thumbnail"
android:text="Just gona stand there and ..." />
</RelativeLayout>
I think the problem that are having is that when the listitem is selected, it is actually being selected but you can't see any difference because the root view must implement 'Checkable'. There is way to make this work although its more complicated that I think it should be.
First of all, you need to add a the following class. This is a checkable LinearLayout that should relay the calls from the checkable interface through to the checkbox within it. It should be easy to modify this for whatever view group you want to use.
public class CheckableLinearLayout extends LinearLayout implements Checkable {
private CheckBox _checkbox;
public CheckableLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
// find checked text view
int childCount = getChildCount();
for (int i = 0; i < childCount; ++i) {
View v = getChildAt(i);
if (v instanceof CheckBox) {
_checkbox = (CheckBox) v;
}
}
}
public boolean isChecked() {
return _checkbox != null ? _checkbox.isChecked() : false;
}
public void setChecked(boolean checked) {
if (_checkbox != null) {
_checkbox.setChecked(checked);
}
}
public void toggle() {
if (_checkbox != null) {
_checkbox.toggle();
}
}
}
Next define the layout of that you want to use for each item, using the CheckableLinearLayout above:
<com.myPackage.CheckableLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<CheckBox
android:id="#+id/checkBox1"
android:focusable="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="CheckBox" />
<TextView
android:id="#+id/textView1"
android:focusable="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
<ImageView
android:id="#+id/imageView1"
android:focusable="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/background_iv" />
</com.myPackage.CheckableLinearLayout>
Then, alter the line that creates the Adapter so that the ID of the layout above is used instead.
Related
I am trying to set the checked state of my checkbox in listview, here's the code:
mShalatAdapter = new ArrayAdapter<String>(getActivity(),R.layout.pengaturan_list_item, R.id.label_shalat, waktuShalat);
mListShalat = (ListView) v.findViewById(R.id.pengaturan_checkbox);
mListShalat.setAdapter(mShalatAdapter);
CheckBox cb;
TextView txv;
for (int i = 0; i < mListShalat.getCount(); i++) {
View vListSortOrder = mListShalat.getAdapter().getView(i, null, null);
txv = (TextView) vListSortOrder.findViewById(R.id.label_shalat);
cb = (CheckBox) vListSortOrder.findViewById(R.id.status_shalat);
String labelShalat = txv.getText().toString();
Toast.makeText(getActivity(), labelShalat, Toast.LENGTH_SHORT).show();
if (cb.isChecked() == false) {
cb.setChecked(true);
}
}
And this is my pengaturan_list_item.xml layout:
<?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="match_parent"
android:gravity="center_vertical|center_horizontal"
android:orientation="horizontal"
android:paddingBottom="5dp"
android:paddingTop="5dp" >
<TextView
android:id="#+id/label_shalat"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingLeft="10dp"
android:text="Label Ibadah"
android:textColor="#android:color/white"
android:textSize="20dp" />
<CheckBox
android:id="#+id/status_shalat"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:button="#drawable/ibadah_checkbox_list"
android:visibility="visible" />
</LinearLayout>
I got the value for TextView and CheckBox but I don't know why the CheckBox not showing the true state in device. Please help, thanks in advance.
my ibadah_checkbox_list.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_checked="true"
android:drawable="#drawable/checkbox_ibadah_checked" />
<item android:state_checked="false"
android:drawable="#drawable/checkbox_ibadah_unchecked" />
</selector>
It might be worth altering the way your adapter works.
Instead of creating a stardard ArrayAdapter, try inheriting from it instead, then inflating views from the list_item.xml inside the getView() method.
Once there, you can extract the checkbox from the view like you're doing in the loop & set its value according to what you need. This is the standard way of doing things like this.
My guess for why what you're doing is not working is that the ArrayAdapter is creating the views when it needs to display them, rather than in this loop you're using, so while it generates and gives you the views while you're requesting them, these views won't necessarily be the ones that are displayed.
Here's how I would do it:
public class MyArrayAdapter extends ArrayAdapter<String>
{
public MyArrayAdapter(Context context, int textViewResourceId, List<String> objects)
{
super(context, textViewResourceId, objects);
}
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.pengaturan_list_item, null);
}
TextView tv = (TextView)v.findViewById(R.id.label_shalat);
CheckBox cb = (CheckBox)v.findViewById(R.id.status_shalat);
tv.setText(getItem(position));
if (!cb.isChecked())
cb.setChecked(true);
return v;
}
}
Then, set your adapter like this (objectList is your list of Strings for the labels):
mShalatAdapter = new MyArrayAdapter(this, R.layout.pengaturan_list_item, objectList);
mListShalat = (ListView) v.findViewById(R.id.pengaturan_checkbox);
mListShalat.setAdapter(mShalatAdapter);
Hope this helps :)
I think the problem is that in your layout. Your TextView has a layout_width of match_parent, and in that it covers the CheckBox and fills the whole width layout. So you need to divide the layout properly.
Try the layout below and tell me the effect.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical|center_horizontal"
android:orientation="horizontal"
android:paddingBottom="5dp"
android:weightSum="2"
android:paddingTop="5dp" >
<TextView
android:id="#+id/label_shalat"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingLeft="10dp"
android:text="Label Ibadah"
android:textColor="#android:color/white"
android:background="#android:color/black"
android:textSize="20dp" />
<CheckBox
android:id="#+id/status_shalat"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:button="#drawable/ibadah_checkbox_list"
android:visibility="visible" />
</LinearLayout>
Add android:descendantFocusability="blocksDescendants" in your ListView.Hope it works....
I'm trying to create a list in Android in which each item has one ore more action buttons, as it's shown here with the number 2:
Is there any predefined way or template to do this, or do I have to manually create the views for the items in the list with their separators, action buttons and everything? (if that is the case, I would also appreciate some help with it :))
Thanks!
You'll have to create your own layout for the rows. (You shouldn't need to do the separators.)
I do this in one of my apps. Here's one of the layouts I use for my items:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:contentDescription="#string/contentDescription_itemIcon"
android:src="#drawable/album_placeholder" />
<Button
android:id="#+id/playButton"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:focusable="false"
android:focusableInTouchMode="false" />
<Button
android:id="#+id/queueButton"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_alignParentTop="true"
android:layout_toLeftOf="#id/playButton"
android:focusable="false"
android:focusableInTouchMode="false" />
<TextView
android:id="#+id/mainText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginLeft="4dp"
android:layout_toLeftOf="#id/queueButton"
android:layout_toRightOf="#id/icon"
android:text="#string/placeholder_mainText" />
<TextView
android:id="#+id/rightAdditionalText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="#id/leftAdditionalText"
android:layout_marginRight="4dp"
android:layout_toLeftOf="#id/queueButton"
android:text="#string/placeholder_rightText" />
<TextView
android:id="#+id/leftAdditionalText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#id/mainText"
android:layout_below="#id/mainText"
android:layout_marginTop="0dp"
android:layout_toLeftOf="#id/rightAdditionalText"
android:text="#string/placeholder_leftText" />
</RelativeLayout>
Here's the adapter I use:
private class ItemAdapter extends ArrayAdapter<T> {
private int rowLayoutId;
public ItemAdapter(Context context, int rowLayoutId, T[] items) {
super(context, 0, items);
this.rowLayoutId = rowLayoutId;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(rowLayoutId, null);
v.findViewById(R.id.queueButton).setOnClickListener(onQueueButtonClicked);
v.findViewById(R.id.playButton).setOnClickListener(onPlayButtonClicked);
}
T item = getItem(position);
if (item != null) {
setText(v, R.id.mainText, item.name);
fillRowView(v, item);
}
v.setTag(item);
return v;
}
}
Mine is parameterized with the row layout id for all items, but you may want to do that differently. The setText() and fillRowView() functions are helpers defined in the containing class.
Note that I set the item object into the row view's tag, so I can get it later in the button click handler:
View.OnClickListener onPlayButtonClicked = new View.OnClickListener() {
#Override
public void onClick(View button) {
View listItem = (View)button.getParent();
Object tag = listItem.getTag();
try {
#SuppressWarnings("unchecked")
T item = (T)tag;
// do someting with item
}
catch (ClassCastException e) {
}
}
};
You can see what this looks like here
I use a listview with multiple choice and I override the search method inside. I have a problem with the items in that during scrolling the position of items changed. The problem comes from the layout, I think, because when the layout includes only the listview, it works correctly. But, when I use the layout below, the positions of the items checked during scrolling get changed.
Can anyone help with that please?
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<EditText
android:id="#+id/editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_toLeftOf="#+id/button1" />
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:text="Button" />
<ListView
android:id="#+id/MyListView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="#+id/editText1" />
</RelativeLayout>
You need to set up an object in your adapter to keep track of the state of the checkboxes. You haven't shown your adapter code so I'll just pull an example from some of my code (this is using a cursor, it can be adapted to an ArrayAdapter)
In the custom adapter set an array:
private Cursor c;
public static int[] checked;
In your constructor set your cursor to the local var and call a method:
CursorAdapter_EditText.c = c;
initializeChecked();
The method (using 0 = not checked):
public static void initializeChecked() {
checked = new int[c.getCount()];
int i = 0;
while (i < c.getCount()) {
checked[i] = 0;
i++;
}
}
In your getView use the array to set the checkbox state:
checkBox = (CheckBox) view.findViewById(R.id.CheckBox);
if (checked(position) == 0) {
checkBox.setChecked(false);
} else {
checkBox.setChecked(true);
}
You'll need to add code in checkBox.setOnCheckedChangeListener also to change the state in the array when you change the state of the checkbox.
This is a great tutorial on how to get a Single Choice List in Android to work, but I need one more thing: I want two lines of text instead of one. So, it would look like this:
|-----------------------------|
| FIRST LINE OF TEXT (o) | <- this is a "RadioButton". Ideally,
| second line of text | it would be centered vertically.
|-----------------------------|
This SO question is related, but I'm an Android newb, so it's a little over my head. Can anyone break it down for me so that I can use it in the context of the tutorial I linked above?
You need to create the custom layout for this.
for display list as it like
this is your layout file
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ListView
android:id="#+id/mylistview"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>
this is your custom list view style
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:layout_weight="1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/text1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Text view 1"/>
<TextView
android:id="#+id/text2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Text view 2"/>
</LinearLayout>
<RadioButton android:id="#+id/radiobtn"
android:width="wrap_content" android:height="wrap_content" />
</LinearLayout>
now you have to implement any adapter like BaseAdapter,ArrayAdapter etc.
and use this custom list view in that
like this way
private class CustomAdapter extends ArrayAdapter<Order> {
private ArrayList<Model> items;
public OrderAdapter(Context context, int textViewResourceId, ArrayList<Model> items) {
super(context, textViewResourceId, items);
this.items = items;
}
#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.custom_list, null); // here you have to implement custom_list.xml file
}
Model m = items.get(position);
if (m != null) {
TextView text1 = (TextView) v.findViewById(R.id.text1);
TextView text2 = (TextView) v.findViewById(R.id.text2);
RadioButton rb = (RadioButton) v.findViewById(R.id.radiobtn);
text1.setText(m.text1);
text1.setText(m.text2);
rb.setChecked(m.isChecked);
}
return v;
}
}
here is your Model class for your list item
private class Model{
String text1;
String text2;
boolean isChecked;
}
Reading the source code of simple_list_item_single_choice.xml, we can figure out how to make a custom widget that implements Checkable, like this:
File simple_list_item_2_single_choice.xml
<?xml version="1.0" encoding="utf-8"?>
<customwidgets.CheckedLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
android:paddingBottom="10dp"
android:paddingTop="10dp" >
<TextView
android:id="#+id/text2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:textAppearance="?android:attr/textAppearanceMedium" />
<CheckedTextView
android:id="#+id/text3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:textAppearance="?android:attr/textAppearanceMedium"
android:checkMark="?android:attr/listChoiceIndicatorSingle" />
</customwidgets.CheckedLinearLayout>
That is, we add as many TextViews as we need and make last one to be a CheckedTextView.
Then, in our custom CheckedLinearLayout we find which one is the Checkable child of the layout and dispatch each method of Checkable we implement to that child, like this:
File CheckedLinearLayout.java
package customwidgets;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Checkable;
import android.widget.LinearLayout;
/**
* Useful class inside a ListView that needs to have checkable items,
* such as radio buttons (single_choice) or check boxes (multiple_choice).
*/
public class CheckedLinearLayout extends LinearLayout implements Checkable {
private Checkable checkedView;
public CheckedLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean isChecked() {
return checkedView == null ? false : checkedView.isChecked();
}
#Override
public void setChecked(boolean checked) {
if (checkedView != null) checkedView.setChecked(checked);
}
#Override
public void toggle() {
if (checkedView != null) checkedView.toggle();
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
int count = getChildCount();
for (int i = count - 1; i >= 0; i--) {
View view = getChildAt(i);
if (view instanceof Checkable) {
checkedView = (Checkable) view;
break;
}
}
}
}
Of course, in the desired xml file of the layout, we set the ListView to be single choiced:
<ListView
android:id="#+id/listView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:choiceMode="singleChoice" >
</ListView>
I have a ListView, which is in single-choice mode. All I want is to display a RadioButton to the side, that when clicked highlights to say it is selected, and when a different one is clicked that one goes back to unselected and the new one becomes selected. Why is this so hard? This should not be this complicated. I've spent DAYS looking for an appropriate answer to this and I have found nothing, so I'm asking hopefully clearly and concisely.
My layout for the listview (R.layout.view_orders):
<?xml version="1.0" encoding="utf-8"?>
<ListView
android:choiceMode="singleChoice"
android:id="#android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:divider="#drawable/list_divider"
android:dividerHeight="1px"
android:focusable="false"
android:focusableInTouchMode="false"
android:cacheColorHint="#00000000">
</ListView>
My custom row (R.layout.orders_row):
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:app="http://schemas.android.com/apk/res/com.xxx.xxxxxx"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="6dip">
<com.xxx.xxxxxx.VerticalLabelView
app:text="SHORT"
app:textColor="#666"
app:textSize="14sp"
android:id="#+id/state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true" />
<TextView
android:id="#+id/quantity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/state"
android:layout_centerVertical="true"
android:gravity="center"
android:textSize="40sp"
android:layout_margin="2dip"
android:minWidth="30dip"
android:textColor="#555" />
<RelativeLayout
android:layout_toRightOf="#id/quantity"
android:layout_centerVertical="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/instrument"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textColor="#333"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
/>
<TextView
android:id="#+id/deets"
android:layout_below="#id/instrument"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textColor="#888"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
/>
</RelativeLayout>
<RadioButton
android:id="#+id/selector"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
/>
</RelativeLayout>
My onCreate() method:
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.view_orders);
client = new Client(handler);
ola = new OrdersAdapter(this, R.layout.orders_row, Orders);
setListAdapter(ola);
final RelativeLayout loading = (RelativeLayout) findViewById(R.id.loading);
panel = (PositionsPanel) findViewById(R.id.panel);
Utility.showProgressBar(loading);
client.Connect("orders");
}
Now everything underlying works as expected, you click on a radiobutton, and through its tag, I can appropriately select that item from the list and manipulate it how I want. However, when the first radio button is clicked, the last one will be selected. Click that same radio button again, and it is now selected as well. Click it once more and nothing happens, both the last and the first are selected. Now I click any other one on the list, it gets selected like expected. Click any one of the selected radio buttons and nothing happens, the radio button remains selected.
I have tried using the following in onCreate():
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.view_orders);
client = new Client(handler);
ola = new OrdersAdapter(this, android.R.layout.simple_list_item_single_choice, Orders);
setListAdapter(ola);
final RelativeLayout loading = (RelativeLayout) findViewById(R.id.loading);
panel = (PositionsPanel) findViewById(R.id.panel);
Utility.showProgressBar(loading);
client.Connect("orders");
}
and that just shows no radio buttons at all. AWESOME.
Now maybe (read: most likely), I'm just dense and can't figure this out, but I've seen this question asked a lot with no real answer. Lots of references to other tutorials or the Commonsware guy's book. However, the comments are old now and his repository has changed so much, that those are no longer correct answers.
So, does anyone have any idea how to get the expected functionality out of this? Or failing that, just pass me along with the Gmail app's source code. :)
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.
Simple solution:
Add this line in the RadioButton layout of your xml file:
<RadioButton
...
android:onClick="onClickRadioButton"
...
/>
Then in the activity class that uses the ListView, add the following:
private RadioButton listRadioButton = null;
int listIndex = -1;
public void onClickRadioButton(View v) {
View vMain = ((View) v.getParent());
// getParent() must be added 'n' times,
// where 'n' is the number of RadioButtons' nested parents
// in your case is one.
// uncheck previous checked button.
if (listRadioButton != null) listRadioButton.setChecked(false);
// assign to the variable the new one
listRadioButton = (RadioButton) v;
// find if the new one is checked or not, and set "listIndex"
if (listRadioButton.isChecked()) {
listIndex = ((ViewGroup) vMain.getParent()).indexOfChild(vMain);
} else {
listRadioButton = null;
listIndex = -1;
}
}
With this simple code only one RadioButton is checked.
If you touch the one that is already checked, then it returns to the unchecked mode.
"listIndex" is tracking the checked item, -1 if none.
If you want to keep always one checked, then code in onClickRadioButton should be:
public void onClickRadioButton(View v) {
View vMain = ((View) v.getParent());
int newIndex = ((ViewGroup) vMain.getParent()).indexOfChild(vMain);
if (listIndex == newIndex) return;
if (listRadioButton != null) {
listRadioButton.setChecked(false);
}
listRadioButton = (RadioButton) v;
listIndex = newIndex;
}
My Name Is Gourab Singha. I solved This Issue. I have Written This Code to solve it. I hope this helps you all. Thanks. I require 3 hours for this.
public void add_option_to_list(View v){
LinearLayout ll = (LinearLayout)v.getParent();
LinearLayout ll_helper = null;
LinearLayout ll2 = (LinearLayout)ll.getParent();
LinearLayout ll3 = (LinearLayout)ll2.getParent();
ListView ll4 = (ListView)ll3.getParent();
//RadioButton rb1= (RadioButton)ll.getChildAt(1);
Toast.makeText(getApplicationContext(), ", "+ll4.getChildCount(), Toast.LENGTH_LONG).show();
//ll.findViewById(R.id.radio_option_button)
for(int k=0;k<ll4.getChildCount();k++){
ll3 = (LinearLayout)ll4.getChildAt(k);
ll2 = (LinearLayout)ll3.getChildAt(0);
ll_helper = (LinearLayout)ll2.getChildAt(0);
RadioButton rb1 = (RadioButton)ll_helper.getChildAt(1);
if(rb1.isChecked())
rb1.setChecked(false);
}
RadioButton rb1 = (RadioButton)ll.getChildAt(1);
rb1.setChecked(true);
//Toast.makeText(getApplicationContext(), ""+((TextView)ll.getChildAt(4)).getText().toString(), Toast.LENGTH_LONG).show();
}
The XML:
<?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="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="#+id/id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Category Name"
android:textAppearance="?android:attr/textAppearanceMedium"
android:visibility="gone" />
<RadioButton
android:id="#+id/radio_option_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="add_option_to_list"
android:text="" />
<TextView
android:id="#+id/option_name"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_marginLeft="3dp"
android:layout_weight="5.35"
android:text="Category Name"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="#+id/option_price"
android:layout_width="76dp"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:gravity="right"
android:text="$0.00"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="#+id/option_unit_price"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:gravity="right"
android:text="$0.00"
android:textAppearance="?android:attr/textAppearanceMedium"
android:visibility="gone" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
I've just had a similar problem. It seemed that it was related to views recycling. But I added Log's everywhere and noticed that the recycling handling was fine.
The problem was RadioButtons handling. I was using:
if(answer == DBAdapter.YES){
rbYes.setChecked(true);
rbNo.setChecked(false);
}
else if(answer == DBAdapter.NO){
rbYes.setChecked(false);
rbNo.setChecked(true);
}
else{
rbYes.setChecked(false);
rbNo.setChecked(false);
}
and the correct way of doing it is:
if(answer == DBAdapter.YES){
rbYes.setChecked(true);
}
else if(answer == DBAdapter.NO){
rbNo.setChecked(true);
}
else{
RadioGroup rg = (RadioGroup)(holder.answerView);
rg.clearCheck();
}
You can achieve much more simple, follow this. It was tried in MarshMallow
1)Have a CheckedTextView :
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:checkMark="?android:attr/listChoiceIndicatorSingle"
android:padding="10dp"
android:textAppearance="?android:attr/textAppearanceMedium">
ListChoiceIndicatorSingle will display RadioButton.
ListChoiceIndicatorMultiple will display CheckBox
Don't forgot to put choiceMode:Single in your ListView.
Inside the adapter
viewHolder.radioBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Log.e("called", "called");
if(position != mSelectedPosition && mSelectedRB != null){
mSelectedRB.setChecked(false);
}
mSelectedPosition = position;
mSelectedRB = (RadioButton)v;
}
});
viewHolder.radioBtn.setText(mList[position]);
if(mSelectedPosition != position){
viewHolder.radioBtn.setChecked(false);
}else{
viewHolder.radioBtn.setChecked(true);
if(mSelectedRB != null && viewHolder.radioBtn != mSelectedRB){
mSelectedRB = viewHolder.radioBtn;
}
}
add style to the radio button
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/tick" android:state_checked="true"/>
<item android:drawable="#drawable/untick" android:state_checked="false"/>
</selector>
and in the xml use the radio button style
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<RadioButton
android:id="#+id/radioBtn"
android:layout_width="match_parent"
android:layout_height="50dp"
android:button="#null"
android:checked="true"
android:drawablePadding="30dp"
android:drawableRight="#drawable/checkmark"
android:text="first" />
</RelativeLayout>
On your adapter:
public void setChecked(View v, int position) {
ViewGroup parent = ((ViewGroup) v.getParent()); // linear layout
for (int x = 0; x < parent.getChildCount() ; x++) {
View cv = parent.getChildAt(x);
((RadioButton)cv.findViewById(R.id.checkbox)).setChecked(false); // your checkbox/radiobtt id
}
RadioButton radio = (RadioButton)v.findViewById(R.id.checkbox);
radio.setChecked(true);
}
On your activity/fragment:
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
((ModelNameAdapter)adapter).setChecked(view, position);
}
});