Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically-added RadioButtons refuse to obey LayoutParams weighting

I'm trying to create a RadioGroup within an Android layout where the child RadioButtons are stretched to evenly fill the entire width of the RadioGroup. However, I've encountered some unexpected behaviour when trying to do this with RadioButtons which have been added programmatically from code. First some background...

What does work

I started with a simple layout based on a RelativeLayout which contains a large TextView and a RadioGroup at the bottom.

The main.xml layout file looks like this:

<?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="fill_parent" >
    <TextView android:text="Some text"
        android:layout_height="wrap_content"
        android:layout_width="fill_parent"
        android:layout_alignParentTop="true"
        android:layout_above="@+id/radio_group"
        android:gravity="center"
        android:background="@android:color/holo_green_dark"
        />      
    <RadioGroup android:id="@+id/radio_group"
        android:layout_height="wrap_content"
        android:layout_width="fill_parent"
        android:layout_alignParentBottom="true"
        android:orientation="horizontal"
        android:background="@android:color/holo_blue_dark">         
        <RadioButton android:text="Option 1"
            android:layout_height="wrap_content"
            android:layout_width="wrap_content"
            android:layout_weight="1"
            android:background="@android:color/darker_gray"
            android:button="@android:color/transparent"
            android:padding="10dp"
            android:gravity="center"
            android:layout_margin="2dp"/>   
        <RadioButton android:text="Option 2"
            android:layout_height="wrap_content"
            android:layout_width="wrap_content"
            android:layout_weight="1"
            android:background="@android:color/darker_gray"
            android:button="@android:color/transparent"
            android:padding="10dp"
            android:gravity="center"
            android:layout_margin="2dp"/> 
    </RadioGroup>       
</RelativeLayout>

which produces the following layout at runtime:

Evenly distributed radio buttons

You can see that the use of android:layout_width="wrap_content" and android:layout_weight="1" in both RadioButtons stretches them to evenly fill half of the enclosing RadioGroup each. So far so good.

What doesn't work

However, the requirement I have is to dynamically create RadioButtons within this layout at runtime based on business logic rather than always using the the two statically included in the layout - sometimes I might need two buttons, sometimes four etc.

To implement this I removed the RadioButtons from my main.xml layout:

<?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="fill_parent" >
    <TextView android:text="Some text"
        android:layout_height="wrap_content"
        android:layout_width="fill_parent"
        android:layout_alignParentTop="true"
        android:layout_above="@+id/radio_group"
        android:gravity="center"
        android:background="@android:color/holo_green_dark"
        />      
    <RadioGroup android:id="@+id/radio_group"
        android:layout_height="wrap_content"
        android:layout_width="fill_parent"
        android:layout_alignParentBottom="true"
        android:orientation="horizontal"
        android:background="@android:color/holo_blue_dark"/>
</RelativeLayout>

...and created a separate _radio_button.xml_ layout for my RadioButton:

<?xml version="1.0" encoding="utf-8"?>
<RadioButton xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="2dp"
    android:layout_weight="1"
    android:background="@android:color/darker_gray"
    android:button="@android:color/transparent"
    android:gravity="center"
    android:padding="10dp" />

In my activity I now add the RadioButtons programmatically:

public class TestRadioActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // Create an inflater to inflate our buttons            
        LayoutInflater inflater = 
            (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        // Create the layout params for our buttons
        LinearLayout.LayoutParams layoutParams = new LayoutParams(
            LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 1f);

        RadioGroup group = (RadioGroup) findViewById(R.id.radio_group);

        // Add button one
        RadioButton button = (RadioButton) inflater.inflate(R.layout.radio_button, null);
        button.setText("Option 1");
        group.addView(button, layoutParams);

        // Add button two
        button = (RadioButton) inflater.inflate(R.layout.radio_button, null);
        button.setText("Option 2");
        group.addView(button, layoutParams);

    }
}

Note how both the _radio_button.xml_ file and the activity specify a layout width of WRAP_CONTENT and a layout weight of 1 to evenly distribute the buttons as in the original main.xml.

However, the layout seems to get rendered ignoring the layout weight with the buttons butted up on the left of the radio group:

Radio buttons not being evenly distributed

As has been suggested elsewhere, I also tried setting the width of the RadioButtons to 0 in the LayoutParams (apparently this can cause the layout weight to be interpreted slightly differently), but this causes the RadioButtons not even to be rendered:

Radio buttons missing completely

Can any advise how to get RadioButtons to evenly fill the entire width of the containing RadioGroup when added programmatically? Is there anything obvious I'm missing?

like image 958
tomtheguvnor Avatar asked Jan 21 '12 22:01

tomtheguvnor


3 Answers

When you set a layout weight, you should use fill_parent as layout width. Then you shouldn't use LinearLayout.LayoutParams but RadioGroup.LayoutParams, as you're adding radio buttons to a RadioGroup, not to a simple LinearLayout.

Finally, as you use the inflater to "build" the radio button, the XML file of the radio button already has the layout params picked from the XML file, so I think you should just call the addView method that takes only the view to add as parameter (that is addView(View v)) and change the layout_width to fill_parent.

Note that, if you'll need to reference the variable "button" in the code, i.e. add a click listener, you'll add the listener only to the last created button. You'll have to create a RadioButton object for each RadioButton you will add to the RadioGroup (button, button1, button2, etc).

like image 109
Verandi Avatar answered Sep 23 '22 06:09

Verandi


FYI, to do it without any xml at all

    RadioGroup rgrp = new RadioGroup(context);
    rgrp.setLayoutParams(new RadioGroup.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT,
                LinearLayout.LayoutParams.WRAP_CONTENT));
    rgrp.setOrientation(LinearLayout.HORIZONTAL);

        mAccent = new RadioButton(context);
        mAccent.setText("Accent");
        mAccent.setLayoutParams(new RadioGroup.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 1f));
        rgrp.addView(mAccent);

        mGhost = new RadioButton(context);
        mGhost.setText( "Ghost");
        mGhost.setLayoutParams(new RadioGroup.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 1f));
        rgrp.addView(mGhost);

        mFlam = new RadioButton(context);
        mFlam.setText( "Flam");
        mFlam.setLayoutParams(new RadioGroup.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 1f));
        rgrp.addView(mFlam);

    layout.addView(rgrp);
like image 28
steveh Avatar answered Sep 20 '22 06:09

steveh


I ran into this issue too, I used the RadioGroup.LayoutParams with weight defined. However I also found once I'd created programatically the buttons weren't responding to touch so set clickable and enabled to true and that fixed things.

  private RadioButton createMyTypeRadioButton(MyType type){

    //create using this constructor to use some of the style definitions
    RadioButton radio = new RadioButton(this, null, R.style.MyRadioStyle);

    RadioGroup.LayoutParams layoutParams = new RadioGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1f);
    radio.setLayoutParams(layoutParams);
    radio.setGravity(Gravity.CENTER);

    //tag used by the setOnCheckedChangeListener to link the radio button with mytype object
    radio.setTag(type.getId());

    //enforce enabled and clickable status otherwise they ignore clicks
    radio.setClickable(true);
    radio.setEnabled(true);

    radio.setText(type.getTitle());


    return radio;
}

private void updateMyTypesUi() {

    //populate RadioGroup with permitted my types
    for (int i = 0; i < myTypes.size(); i++) {
        MyType type = myTypes.get(i);           
        RadioButton radioButton = createSwapTypeRadioButton(type);
        myRadioGrp.addView(radioButton);

    }

    myRadioGrp.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(RadioGroup group, int checkedId) {
            RadioButton checkedType = (RadioButton) group.findViewById(checkedId);              
            String idOfMyTypeChecked = (String) checkedType.getTag();
            //do something with idOfMyTypeChecked
        }
    });
}
like image 20
scottyab Avatar answered Sep 20 '22 06:09

scottyab