Android is a powerful framework. Many of the design decisions and mechanisms are exactly what I would expect/want. However, I recently came across a “rough edge” where the in-built mechanism left something to be desired:
There is no good way to do advanced (read as anything other than a simple LinearLayout) layout techniques with a RadioGroup.
I have seen several posts of people wanting to do rational things like have two columns of RadioButtons for a certain screen orientation. This is not currently possible if you choose to use a RadioGroup:
<RadioGroup ...> <RadioButton android:id="@+id/one" .../> <RadioButton android:id="@+id/two" .../> <RadioButton android:id="@+id/three" .../> <RadioButton android:id="@+id/four" .../> </RadioGroup>
So that is our first step…to step away from the RadioGroup.
Some of you, like I did, will then scream: “But wait! The RadioGroup has all the logic for mutual exclusion of buttons! We can’t do away with that!”
But then I thought about it from my oldschool Win32 perspective and realized that there wasn’t much logic in there to be lost. Certainly nothing that would be missed.
Lets say we have an “Option” enum:
public enum Option
{
One,
Two,
Three,
Four
}
Then we add some special Java enum sauce:
public enum Option
{
One(R.id.one),
Two(R.id.two),
Three(R.id.three),
Four(R.id.four);
int idInLayout;
//enum constructor taking a radio button id//accessor for id
private Option(int idInLayout)
{
this.idInLayout = idInLayout;
}
public int getIdInLayout()
{
return idInLayout;
}
}
Note that R.id.* would reference your app’s (not android’s) generated resource class. Since layout ids can be reused across layouts and are you are unlikely to need your option’s id more than once in a layout…this is pretty handy.
Now we just layout our RadioButtons like we would any other view:
... <TableLayout ...> <TableRow> <RadioButton android:id="@+id/one" .../> <RadioButton android:id="@+id/two" .../> </TableRow> <TableRow> <RadioButton android:id="@+id/three" .../> <RadioButton android:id="@+id/four" .../> </TableRow> </TableLayout> ...
In our Activity, we add some initialization to handle button selection:
@Override
public void onCreate(Bundle savedInstanceState)
{
//Do all the standard init junk and then…
for (Option option : Option.values())
{
RadioButton radio = (RadioButton)
findViewById(option.getIdInLayout());
if (radio != null)
{
radio.setOnClickListener(optionOnClickListener);
radio.setTag(option);
}
}
}
This sets up each radio to call our click listener:
RadioButton.OnClickListener optionOnClickListener =
new RadioButton.OnClickListener()
{
public void onClick(View v)
{
Option option = (Option) v.getTag();
//React to your option selection here
exclusivelySetOption(option);
}
};
Which then uses our exclusivelySetOption method:
private void exclusivelySetOption(Option selectedOption)
{
//Cycle through all options
for (Option option : Option.values())
{
RadioButton radio = (RadioButton)
findViewById(option.getIdInLayout());
if (radio != null)
{
//Check or uncheck as needed
radio.setChecked(option.ordinal()
== selectedOption.ordinal());
}
}
}
For completeness, you would call exclusivelySetOption in your onResume overload to set the initial radio value:
@Override
public void onResume()
{
super.onResume();
Option currentOption = //get what our option should be
exclusivelySetOption(currentOption);
}
And there you have it. We have simulated a RadioGroup, layed out our RadioButtons with new found power, and massaged all the id mapping into our enumeration.
Thx, but strange, that there is no way to have a tableLayout inside a radioGroup, by default.
ReplyDelete