Reputation: 18746
I want to show a single select option in my list. I am using RadioButton
in my listView
row. I know that RadioGroup
is used for single selection.
But problem is that I have added the RadioButton
in my ListRowView
. Now I want to add all my list items in one RadioButton
. I am using Custom Adapter
and in getView()
. I get the RadioButton
in getView()
, but when want to add it in RadioGroup
it say
"view already have parent , call removeView() in parent before"
And I know its true, but if I remove it from the view. Then it is not visible.
I also try to create and add RadioButton
programmatically. And then add it in RadioGrop
. And then to view of list row. But this time as the parent is RadioGroup
, so again it say
"view already have parent , call removeView() in parent before"
What I want to do is to select only one item in list at a time. My code is as follows.
public class MyAdapter extends ArrayAdapter < MyMenuItem > {
private LayoutInflater mInflater ;
int mResource ;
List < MyMenuItem > mData ;
Context context;
public MyAdapter ( Context context , int resource , int textViewResourceId , List < MyMenuItem > data ) {
super ( context , resource , textViewResourceId , data ) ;
this.context = context;
mData = data ;
mResource = resource ;
mInflater = ( LayoutInflater ) getSystemService ( Context.LAYOUT_INFLATER_SERVICE ) ;
}
@ Override
public View getView ( int position , View convertView , ViewGroup parent ) {
ViewHolder holder = null ;
if ( convertView == null ) {
convertView = mInflater.inflate ( mResource , null ) ;
holder = new ViewHolder ( ) ;
holder.icon = ( ImageView ) convertView.findViewById ( R.id.icon ) ;
holder.text = ( TextView ) convertView.findViewById ( R.id.text ) ;
holder.comment = ( TextView ) convertView.findViewById ( R.id.comment ) ;
LinearLayout lin = ( LinearLayout ) convertView.findViewById ( R.id.linerList ) ;
RadioButton rbtn = new RadioButton ( context );
LayoutParams lparam = new LayoutParams ( LayoutParams.WRAP_CONTENT , LayoutParams.WRAP_CONTENT );
rbtn.setSelected ( false );
holder.check = rbtn;
//radioGroup.addView ( rbtn );
lin.addView ( rbtn , 0 );
convertView.setTag ( holder ) ;
} else {
holder = ( ViewHolder ) convertView.getTag ( ) ;
}
holder.text.setText ( mData.get ( position ).getText ( ) ) ;
holder.comment.setText ( mData.get ( position ).getComment ( ) ) ;
holder.icon.setImageResource ( getApplicationContext ( ).getResources ( ).getIdentifier ( mData.get ( position ).getIcon ( ) ,
"drawable" , getPackageName ( ) )
) ;
return convertView ;
}
}
My XML for the row
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:padding="6dip">
<LinearLayout
android:id = "@+id/linerList"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="6dip" />
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_height="fill_parent">
<TextView
android:id="@+id/text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_vertical"
android:text="My Application"
android:textSize="20sp"
android:singleLine="true"
android:ellipsize="marquee"
android:textColor="@color/white" />
<TextView
android:id="@+id/comment"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
android:ellipsize="marquee"
android:text="Simple application that shows how to use RelativeLayout"
android:textSize="14sp"
android:textColor="@color/light_gray" />
</LinearLayout>
Upvotes: 45
Views: 68181
Reputation: 167
You can try this solution. Define a variable to get the currently selected position and do the following inside the custom adapter.
singleRadio.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
checkedButtonPosition = position;
notifyDataSetChanged();
}
});
if (checkedButtonPosition == position){
singleRadio.setChecked(true);
}else {
singleRadio.setChecked(false);
}
Upvotes: 0
Reputation: 955
to add to the answers already given, for a more modular approach, have all list items inherit from the same class/interface that have a message function that would allow you to pass massages to them via the adapter.
The adapter registers itself with every item that is added to it, so every list item can call the adapter to send a message.
then, in the RadioButton listener you can send a message to all the other radio buttons to turn off, turn the pressed one on, then finally notify dataset changed on the adapter.
I have an ListAdapter class, and a ListItem abstract class that are fairly robust; I'll send to anyone who needs it.
Multiple list item types supported.
Upvotes: 0
Reputation: 965
This solution works and it's pretty clean, but there might be some better solutions out there.
You should use your adapter to manage the radio buttons state.
You must keep a reference to the last checked radio button, and then upon RadioButton.onClick
you set the last checked radio button setChecked(false)
.
also remember to set the newly selected radio button as the last selected radio button.
see example:
private class MyAdapter extends ArrayAdapter<String>{
private int mResourceId = 0;
private LayoutInflater mLayoutInflater;
private RadioButton mSelectedRB;
private int mSelectedPosition = -1;
public MyAdapter(Context context, int resource, int textViewResourceId, List<String> objects) {
super(context, resource, textViewResourceId, objects);
mResourceId = resource;
mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view = convertView;
ViewHolder holder;
if(view == null){
view = mLayoutInflater.inflate(mResourceId, parent, false);
holder = new ViewHolder();
holder.name = (TextView)view.findViewById(R.id.text);
holder.radioBtn = (RadioButton)view.findViewById(R.id.radioButton1);
view.setTag(holder);
}else{
holder = (ViewHolder)view.getTag();
}
holder.radioBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(position != mSelectedPosition && mSelectedRB != null){
mSelectedRB.setChecked(false);
}
mSelectedPosition = position;
mSelectedRB = (RadioButton)v;
}
});
if(mSelectedPosition != position){
holder.radioBtn.setChecked(false);
}else{
holder.radioBtn.setChecked(true);
if(mSelectedRB != null && holder.radioBtn != mSelectedRB){
mSelectedRB = holder.radioBtn;
}
}
holder.name.setText(getItem(position));
return view;
}
private class ViewHolder{
TextView name;
RadioButton radioBtn;
}
}
Hope it does it for you.
Upvotes: 39
Reputation: 7759
This is my solution. Its pretty easy.
my_radio_adapter_item.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
... />
<RadioButton
android:id="@+id/radio"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:focusable="false"
... />
</LinearLayout>
MyRadioAdapter.java
public class MyRadioAdapter extends BaseAdapter
{
private Context mContext;
private ArrayList<Variation> mVariations;
private int mSelectedVariation;
public MyRadioAdapter(Context context, ArrayList<Variation> variations, int selectedVariation)
{
mContext = context;
mVariations = variations;
mSelectedVariation = selectedVariation;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent)
{
View view = convertView;
if(view==null)
{
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.my_radio_adapter_item, null);
}
final Variation variation = mVariations.get(position);
TextView name = (TextView) view.findViewById(R.id.name);
RadioButton radio = (RadioButton) view.findViewById(R.id.radio);
name.setText(variation.getName());
if(position==mSelectedVariation) radio.setChecked(true);
else radio.setChecked(false);
view.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
mSelectedVariation = position;
MyRadioAdapter.this.notifyDataSetChanged();
}
});
return view;
}
...
}
Upvotes: 15
Reputation: 93123
You need to do two things:
mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
Checkable
. (More info about this here).Upvotes: 46
Reputation: 1373
You could put a
private int selectedIndex = -1;
then, in the getView-code you could check
if (position == selectedIndex) {
rbtn.setSelected ( true );
}
else {
rbtn.setSelected ( false );
}
and add a method in your custom adapter:
public void setSelectedIndex(int index) {
//some range-checks, maybe
selectedIndex = index;
//invalidate
}
Then, in your onItemClickedListener you call setSelectedIndex on the position.
Upvotes: 2
Reputation: 3473
You need to use the CheckedTextView instead of the normal one. http://developer.android.com/reference/android/widget/CheckedTextView.html
I never used it, but the AlertDialog uses it for the SingleChoice items. So it definitively will work :)
Edit: don't forget to call
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
Upvotes: 1
Reputation: 255
you need the same output or different...
What i mean is you have select only one of the language from the list. Is it right?
conform it. So that i will give one example for that
Upvotes: -1