I want Radio Group implementation on GridView, so that only single item can be selected among the elements of grid.
Please help.
I want Radio Group implementation on GridView, so that only single item can be selected among the elements of grid.
Please help.
The purpose to restrict the select of element from the grid can be accomplished as follows:
1.Creation of Grid element.
<LinearLayout
android:id="@+id/item_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center">
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher" />
<RadioButton
android:id="@+id/radiobtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Image" />
</LinearLayout>
2.Inflating this xml in the getView() method of customize adapter.
public class MyAdapter extends BaseAdapter {
Context mCtx;
int[] mImg;
LayoutInflater layoutInflater;
RadioGroup rgp;
private RadioButton mSelectedRB;
private int mSelectedPosition = -1;
public MyAdapter(Context context, int[] img) {
this.mCtx = context;
this.mImg = img;
rgp = new RadioGroup(context);
layoutInflater = (LayoutInflater) mCtx
.getSystemService(LAYOUT_INFLATER_SERVICE);
}
@Override
public int getCount() {
return mImg.length;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(final int position, View convertView,
ViewGroup parent) {
View view = convertView;
Holder holder;
if (view == null) {
view = layoutInflater.inflate(R.layout.element, null);
holder = new Holder();
holder.image = (ImageView) view.findViewById(R.id.imageView);
holder.radioButton = (RadioButton) view
.findViewById(R.id.radiobtn);
view.setTag(holder);
} else {
holder = (Holder) view.getTag();
}
holder.radioButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if ((position != mSelectedPosition && mSelectedRB != null)) {
mSelectedRB.setChecked(false);
}
mSelectedPosition = position;
mSelectedRB = (RadioButton) v;
}
});
if (mSelectedPosition != position) {
holder.radioButton.setChecked(false);
} else {
holder.radioButton.setChecked(true);
if (mSelectedRB != null && holder.radioButton != mSelectedRB) {
mSelectedRB = holder.radioButton;
}
}
return view;
}
}
private class Holder {
ImageView image;
RadioButton radioButton;
}
An alternative approach to this is to create your own subclass of RadioButton
which has an extra XML attribute (such as group
). This specifies (as a string) to which group the button belongs. In the subclass, you then ensure that within any particular group, only one radio button is selected.
You can do this as follows:
First create the file res/values/attrs.xml
which contains something like the following:
<resources>
<declare-styleable name="GroupedRadioButton">
<attr name="group" format="string"/>
</declare-styleable>
</resources>
Then create your subclass, GroupedRadioButton
:
public class GroupedRadioButton extends RadioButton {
public GroupedRadioButton(Context context, AttributeSet attrs) {
super(context, attrs);
processAttributes(context, attrs);
setOnClickListener(internalListener, true);
}
...
}
Once fleshed out (see below), you can then use this new class as follows in your layout files:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res/com.example.app"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<com.example.app.GroupedRadioButton
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Option 1"
custom:group="group1" />
<com.example.app.GroupedRadioButton
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Option 2"
custom:group="group1" />
<com.example.app.GroupedRadioButton
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Option 3"
custom:group="group1" />
<com.example.app.GroupedRadioButton
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Option A"
custom:group="group2" />
<com.example.app.GroupedRadioButton
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Option B"
custom:group="group2" />
...
The radio buttons can be anywhere in your layout (e.g. in a GridView
). Note the xmlns:custom
tag is required since we are using a custom attribute.
The layout above will make options 1, 2 and 3 mutually exclusive and options A and B mutually exclusive.
This is achieved by keeping track (statically) of which GroupedRadioButton
is currently selected within each group:
public class GroupedRadioButton extends RadioButton {
private static Map<String, WeakReference<GroupedRadioButton>> buttonMap;
static {
buttonMap = new HashMap<String, WeakReference<GroupedRadioButton>>();
}
...
}
Note that we have to be careful here to ensure that we don't keep strong references to the buttons otherwise they will never be garbage collected.
The processAttributes()
method specified in the constructor above digs out the group
attribute from the XML we specified and sets this as instance data:
private void processAttributes(Context context, AttributeSet attrs) {
TypedArray attributes = context.obtainStyledAttributes(attrs,
R.styleable.GroupedRadioButton);
int attributeCount = attributes.getIndexCount();
for (int i = 0; i < attributeCount; ++i) {
int attr = attributes.getIndex(i);
switch (attr) {
case R.styleable.GroupedRadioButton_group:
this.groupName = attributes.getString(attr);
break;
}
}
attributes.recycle();
}
We define the main OnClickListener
for this class.
private OnClickListener internalListener = new OnClickListener() {
@Override
public void onClick(View view) {
processButtonClick(view);
}
};
which calls:
private void processButtonClick(View view) {
if (!(view instanceof GroupedRadioButton))
return;
GroupedRadioButton clickedButton = (GroupedRadioButton) view;
String groupName = clickedButton.groupName;
WeakReference<GroupedRadioButton> selectedButtonReference = buttonMap.get(groupName);
GroupedRadioButton selectedButton = selectedButtonReference == null ? null : selectedButtonReference.get();
if (selectedButton != clickedButton) {
if (selectedButton != null)
selectedButton.setChecked(false);
clickedButton.setChecked(true);
buttonMap.put(groupName, new WeakReference<GroupedRadioButton>(clickedButton));
}
if (externalListener != null)
externalListener.onClick(view);
}
This does two things. It ensures that it deselects the old group button before selecting the new one (assuming the old and new buttons are different). It then calls onClick()
on an externalListener
which is provided so that users of the class can add their own 'on-click' functionality.
The setOnClickListener()
call in the constructor is to our own method as follows:
private void setOnClickListener(OnClickListener listener, boolean internal) {
if (internal)
super.setOnClickListener(internalListener);
else
this.externalListener = listener;
}
This sets the internalListener
as the official OnClickListener
and sets instance data as appropriate for the external listener. The View.setOnClickListener()
method can then be overridden as follows:
@Override
public void setOnClickListener(OnClickListener listener) {
setOnClickListener(listener, false);
}
Apologies for the length of this answer but I hope it helps you and others trying to do the same thing. It would of course not be needed at all if a RadioGroup
applied recursively to its children!
When you select an element of your grid, check that none of the other elements that you want to be in your radio group aren't selected and if they are deselect them...