How to group a 3x3 grid of radio buttons?
Asked Answered
G

11

46

As the title describes, I'm trying to group up a grid of 3x3 radio buttons into a single radio group. In a previous question asked I learned that for radio buttons to correspond to a single group they had to be the immediate children of the radio group to which they will correspond. I learned this the hard way when I attempted to encapsulate an entire table layout (with the radio buttons in the table rows) in a radio group.

Running into that wall, I tried the following:

<TableLayout android:id="@+id/table_radButtons" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content"
        android:layout_below="@+id/title_radGroup_buffer">

        <TableRow>
            <RadioGroup android:layout_width="fill_parent" 
                android:layout_height="wrap_content" 
                android:orientation="horizontal"
                android:id="@+id/radGroup1">  

                <RadioButton android:id="@+id/rad1" 
                    android:text="Button1" 
                    android:layout_width="105px" 
                    android:layout_height="wrap_content" 
                    android:textSize="13px"></RadioButton>
                <RadioButton android:id="@+id/rad2" 
                    android:text="Button2" 
                    android:layout_width="105px" 
                    android:textSize="13px" 
                    android:layout_height="wrap_content"></RadioButton>
                <RadioButton android:id="@+id/rad3" 
                    android:text="Button3" 
                    android:layout_width="105px" 
                    android:textSize="13px" 
                    android:layout_height="wrap_content"></RadioButton>
            </RadioGroup>
        </TableRow>
        <TableRow>
            <RadioGroup android:layout_width="fill_parent" 
                android:layout_height="wrap_content" 
                android:orientation="horizontal"
                android:id="@+id/radGroup1">
                  <!-- snippet -->
        </TableRow>
        <!-- snippet --->
</TableLayout>

Obviously I didn't learn the first time because I ran into a wall again. I was hoping that the radio buttons in different table rows would notice that they were part of the same radio group (gave each group the same ID) but this didn't work.

Is there any way I can group all of these buttons into a single radio group and still maintain my 3x3 structure (3 rows, 3 radio buttons in each row)?

Gingery answered 4/3, 2010 at 17:59 Comment(0)
C
72

Actually it's not that hard if you subclass TableLayout like in this example

/**
 * 
 */
package com.codtech.android.view;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.RadioButton;
import android.widget.TableLayout;
import android.widget.TableRow;

/**
 * @author diego
 *
 */
public class ToggleButtonGroupTableLayout extends TableLayout  implements OnClickListener {

    private static final String TAG = "ToggleButtonGroupTableLayout";
    private RadioButton activeRadioButton;

    /** 
     * @param context
     */
    public ToggleButtonGroupTableLayout(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
    }

    /**
     * @param context
     * @param attrs
     */
    public ToggleButtonGroupTableLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
    }

    @Override
    public void onClick(View v) {
        final RadioButton rb = (RadioButton) v;
        if ( activeRadioButton != null ) {
            activeRadioButton.setChecked(false);
        }
        rb.setChecked(true);
        activeRadioButton = rb;
    }

    /* (non-Javadoc)
     * @see android.widget.TableLayout#addView(android.view.View, int, android.view.ViewGroup.LayoutParams)
     */
    @Override
    public void addView(View child, int index,
            android.view.ViewGroup.LayoutParams params) {
        super.addView(child, index, params);
        setChildrenOnClickListener((TableRow)child);
    }


    /* (non-Javadoc)
     * @see android.widget.TableLayout#addView(android.view.View, android.view.ViewGroup.LayoutParams)
     */
    @Override
    public void addView(View child, android.view.ViewGroup.LayoutParams params) {
        super.addView(child, params);
        setChildrenOnClickListener((TableRow)child);
    }


    private void setChildrenOnClickListener(TableRow tr) {
        final int c = tr.getChildCount();
        for (int i=0; i < c; i++) {
            final View v = tr.getChildAt(i);
            if ( v instanceof RadioButton ) {
                v.setOnClickListener(this);
            }
        }
    }

    public int getCheckedRadioButtonId() {
        if ( activeRadioButton != null ) {
            return activeRadioButton.getId();
        }

        return -1;
    }
}

and create a layout like this (of course you need to clean it up but you got the idea)

<?xml version="1.0" encoding="utf-8"?>
<com.codtech.android.view.ToggleButtonGroupTableLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content" android:layout_height="wrap_content"
    android:id="@+id/radGroup1">
    <TableRow>
            <RadioButton android:id="@+id/rad1" android:text="Button1"
                android:layout_width="105px" android:layout_height="wrap_content"
                android:textSize="13px" />
            <RadioButton android:id="@+id/rad2" android:text="Button2"
                android:layout_width="105px" android:textSize="13px"
                android:layout_height="wrap_content" />
            <RadioButton android:id="@+id/rad3" android:text="Button3"
                android:layout_width="105px" android:textSize="13px"
                android:layout_height="wrap_content" />
    </TableRow>
    <TableRow>
            <RadioButton android:id="@+id/rad1" android:text="Button1"
                android:layout_width="105px" android:layout_height="wrap_content"
                android:textSize="13px" />
            <RadioButton android:id="@+id/rad2" android:text="Button2"
                android:layout_width="105px" android:textSize="13px"
                android:layout_height="wrap_content" />
            <RadioButton android:id="@+id/rad3" android:text="Button3"
                android:layout_width="105px" android:textSize="13px"
                android:layout_height="wrap_content" />
    </TableRow>
    <TableRow>
            <RadioButton android:id="@+id/rad1" android:text="Button1"
                android:layout_width="105px" android:layout_height="wrap_content"
                android:textSize="13px" />
            <RadioButton android:id="@+id/rad2" android:text="Button2"
                android:layout_width="105px" android:textSize="13px"
                android:layout_height="wrap_content" />
            <RadioButton android:id="@+id/rad3" android:text="Button3"
                android:layout_width="105px" android:textSize="13px"
                android:layout_height="wrap_content" />
    </TableRow>
</com.codtech.android.view.ToggleButtonGroupTableLayout>
Cramoisy answered 5/3, 2010 at 1:32 Comment(12)
I'll have to look over this and see if I can understand exactly what you're doing. Thanks.Gingery
how to get the checked button id whenever it is changed?Selfpreservation
Thanks, this worked perfectly. Copy, paste, done. Great stuff!!Thigmotaxis
@wolverine: User mRadioButtons.getCheckedRadioButtonId() This gives you an int corresponding to R.id.<selectedRadioButton>Thigmotaxis
@dtmilano: In may case I have to set on the first radio button by default. Then your code does not work. I noticed however that if I click on the first radio button, then it starts working. What changes do I need to make the code work in my case?Sonometer
@muetzenflo: it looks like you understand the code very well, so I just want to ask for your help in my case (see my first comment.)Sonometer
Hello! Nobody answers... Perhaps @Selfpreservation could help me? See my first comment.Sonometer
I solved my problem! If initially one radio button is checked (in the layout file) one needs to set the activeRadioButton to this checked radio button in the method setChildrenOnClickListener.Sonometer
@Sonometer how could you manage to set on the first raddio button by default?Olgaolguin
@Olgaolguin I did it in the layout file when I defined the radio button, using android:checked="true"Sonometer
@Sonometer you right and I put the fixed snippet in your question here:https://mcmap.net/q/213186/-regarding-http-stackoverflow-com-questions-2381560-how-to-group-a-3x3-grid-of-radio-buttonsLingo
@dtmilano the solution is working flawlessly but i feel a minor enhancement would help a broader audience i.e. by moving the getCheckedRadioButtonId() to custom onClickListner event I shall suggest an edit for the sameIntonate
M
11

After above https://mcmap.net/q/212871/-how-to-group-a-3x3-grid-of-radio-buttons answer I got another solution for this question, I added some other functionality like, to save the state of the group and also functionality to clear the check functionality like in radio group.

import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.IdRes;
import android.util.AttributeSet;
import android.view.View;
import android.widget.RadioButton;
import android.widget.TableLayout;
import android.widget.TableRow;

public class RadioGridGroup extends TableLayout implements View.OnClickListener {

    private static final String TAG = "ToggleButtonGroupTableLayout";
    private int checkedButtonID = -1;

    /**
     * @param context
     */
    public RadioGridGroup(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
    }

    /**
     * @param context
     * @param attrs
     */
    public RadioGridGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
    }

    @Override
    public void onClick(View v) {
        if (v instanceof RadioButton) {
            int id = v.getId();
            check(id);
        }
    }

    private void setCheckedStateForView(int viewId, boolean checked) {
        View checkedView = findViewById(viewId);
        if (checkedView != null && checkedView instanceof RadioButton) {
            ((RadioButton) checkedView).setChecked(checked);
        }
    }

    /* (non-Javadoc)
     * @see android.widget.TableLayout#addView(android.view.View, int, android.view.ViewGroup.LayoutParams)
     */
    @Override
    public void addView(View child, int index,
                        android.view.ViewGroup.LayoutParams params) {
        super.addView(child, index, params);
        setChildrenOnClickListener((TableRow) child);
    }


    /* (non-Javadoc)
     * @see android.widget.TableLayout#addView(android.view.View, android.view.ViewGroup.LayoutParams)
     */
    @Override
    public void addView(View child, android.view.ViewGroup.LayoutParams params) {
        super.addView(child, params);
        setChildrenOnClickListener((TableRow) child);
    }


    private void setChildrenOnClickListener(TableRow tr) {
        final int c = tr.getChildCount();
        for (int i = 0; i < c; i++) {
            final View v = tr.getChildAt(i);
            if (v instanceof RadioButton) {
                v.setOnClickListener(this);
            }
        }
    }


    /**
     * @return the checked button Id
     */
    public int getCheckedRadioButtonId() {
        return checkedButtonID;
    }


    /**
     * Check the id
     *
     * @param id
     */
    public void check(@IdRes int id) {
        // don't even bother
        if (id != -1 && (id == checkedButtonID)) {
            return;
        }
        if (checkedButtonID != -1) {
            setCheckedStateForView(checkedButtonID, false);
        }
        if (id != -1) {
            setCheckedStateForView(id, true);
        }
        setCheckedId(id);
    }

    /**
     * set the checked button Id
     *
     * @param id
     */
    private void setCheckedId(int id) {
        this.checkedButtonID = id;
    }

    public void clearCheck() {
        check(-1);
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        if (!(state instanceof SavedState)) {
            super.onRestoreInstanceState(state);
            return;
        }

        SavedState ss = (SavedState) state;
        super.onRestoreInstanceState(ss.getSuperState());

        this.checkedButtonID = ss.buttonId;
        setCheckedStateForView(checkedButtonID, true);
    }

    @Override
    protected Parcelable onSaveInstanceState() {
        Parcelable superState = super.onSaveInstanceState();
        SavedState savedState = new SavedState(superState);
        savedState.buttonId = checkedButtonID;
        return savedState;
    }

    static class SavedState extends BaseSavedState {
        int buttonId;

        /**
         * Constructor used when reading from a parcel. Reads the state of the superclass.
         *
         * @param source
         */
        public SavedState(Parcel source) {
            super(source);
            buttonId = source.readInt();
        }

        /**
         * Constructor called by derived classes when creating their SavedState objects
         *
         * @param superState The state of the superclass of this view
         */
        public SavedState(Parcelable superState) {
            super(superState);
        }

        @Override
        public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeInt(buttonId);
        }

        public static final Parcelable.Creator<SavedState> CREATOR =
                new Parcelable.Creator<SavedState>() {
                    public SavedState createFromParcel(Parcel in) {
                        return new SavedState(in);
                    }

                    public SavedState[] newArray(int size) {
                        return new SavedState[size];
                    }
                };
    }
}

and use this in XML as follows

<com.test.customviews.RadioGridGroup xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <TableRow android:layout_marginTop="@dimen/preview_five">

        <RadioButton
            android:id="@+id/rad1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button1" />

        <RadioButton
            android:id="@+id/rad2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button2" />
    </TableRow>

    <TableRow android:layout_marginTop="@dimen/preview_five">

        <RadioButton
            android:id="@+id/rad3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button3" />

        <RadioButton
            android:id="@+id/rad4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button4" />
    </TableRow>

    <TableRow android:layout_marginTop="@dimen/preview_five">

        <RadioButton
            android:id="@+id/rad5"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button5" />

        <RadioButton
            android:id="@+id/rad6"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button6" />
    </TableRow>

    <TableRow android:layout_marginTop="@dimen/preview_five">

        <RadioButton
            android:id="@+id/rad7"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button7" />

        <RadioButton
            android:id="@+id/rad8"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button8" />
    </TableRow>
</com.test.customviews.RadioGridGroup>

For any other improvements, please comment.

Matildamatilde answered 19/11, 2015 at 11:5 Comment(5)
In any java package you can place this.Matildamatilde
works well! But it has a small typo in the xml: wrap_contact should be wrap_content.Glacial
I'm trying to add TableRow and RadioButton at run time it's working but also allows multiple selection, any solution for this?Guillen
@Guillen We can do that. But, we need to modify the solutionMatildamatilde
This is working on Android 10. while rajath answer doesn't work with android 10 on my poco x3 nfc.Mcquillin
P
7

This uses a custom GridLayout with the RadioGroup functionality. Thanks to Saikrishnan Ranganathan for saiaspire/RadioGridGroup

<com.sample.RadioGridGroup
        xmlns:grid="http://schemas.android.com/apk/res-auto"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        grid:columnCount="3"
        grid:useDefaultMargins="true">

        <android.support.v7.widget.AppCompatRadioButton
            android:checked="true"
            android:text="Text1"
            grid:layout_columnWeight="1"/>

        <android.support.v7.widget.AppCompatRadioButton
            android:text="Text2"
            grid:layout_columnWeight="1"/>

        <android.support.v7.widget.AppCompatRadioButton
            android:text="Text3"
            grid:layout_columnWeight="1"/>

        <android.support.v7.widget.AppCompatRadioButton
            android:text="Text4"
            grid:layout_columnWeight="1"/>

        <android.support.v7.widget.AppCompatRadioButton
            android:text="Text5"
            grid:layout_columnWeight="1"/>

        <android.support.v7.widget.AppCompatRadioButton
            android:text="Text6"
            grid:layout_columnWeight="1"/>

        <android.support.v7.widget.AppCompatRadioButton
            android:text="Text7"
            grid:layout_columnWeight="1"/>

        <android.support.v7.widget.AppCompatRadioButton
            android:text="Text8"
            grid:layout_columnWeight="1"/>

        <android.support.v7.widget.AppCompatRadioButton
            android:text="Text9"
            grid:layout_columnWeight="1"/>

    </com.sample.RadioGridGroup>
Pindling answered 30/8, 2018 at 2:48 Comment(2)
Thanks man. i was using linearlayout insied the group. it was displaying ok but not functioning properly. You saved me man.Jat
This is rendered in Android studio properly but doesn't work on my POCO X3 NFC android 10. The above answer with table layout work.Mcquillin
R
7

I've written a very simple GridLayout subclass that acts like a RadioGroup. This is how it looks:

GridLayout RadioGroup with RadioButton

To use it first add the GridLayout library:

implementation "androidx.gridlayout:gridlayout:1.0.0-beta01"

Then copy-paste the GridLayout subclass:

/**
 * A GridLayout subclass that acts like a RadioGroup. Important: it only accepts RadioButton as children.
 * Inspired by https://mcmap.net/q/212871/-how-to-group-a-3x3-grid-of-radio-buttons
 */
class GridRadioGroup @JvmOverloads constructor(
        context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : GridLayout(context, attrs, defStyleAttr), View.OnClickListener {

    @IdRes var selectedRadioButtonId: Int? = null
    get() = getSelectedRadioButton()?.id
    private set

    private fun getSelectedRadioButton(): RadioButton? {
        for (index in 0 until childCount) {
            val radioButton = getChildAt(index) as RadioButton
            if (radioButton.isChecked) return radioButton
        }
        return null
    }

    override fun onClick(view: View) {
        // While this looks inefficient, it does fix a bug (2 RadioButtons could be selected at the
        // same time) when navigating back by popping-up a fragment from the backstack.
        for (index in 0 until childCount) {
            val radioButton = getChildAt(index) as RadioButton
            radioButton.isChecked = false
        }
        val radioButton = view as RadioButton
        radioButton.isChecked = true
    }

    override fun addView(child: View?, index: Int, params: ViewGroup.LayoutParams?) {
        super.addView(child, index, params)
        child?.setOnClickListener(this)
    }

}

Finally just use it:

<com.example.ui.GridRadioGroup
    android:id="@+id/gridRadioGroup"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:columnCount="2"
    >

    <RadioButton
        android:id="@+id/option_1"
        style="@style/GridRadioButton"
        android:drawableTop="@drawable/option_1"
        android:text="@string/register_choose_goal_option_1"
        app:layout_columnWeight="1"
        app:layout_rowWeight="1"
        />

    <RadioButton
        android:id="@+id/option_2"
        style="@style/GridRadioButton"
        android:drawableTop="@drawable/option_2"
        android:text="@string/option_2"
        app:layout_columnWeight="1"
        app:layout_rowWeight="1"
        tools:checked="true"
        />

    <RadioButton
        android:id="@+id/option_3"
        style="@style/GridRadioButton"
        android:drawableTop="@drawable/option_3"
        android:text="@string/option_3"
        app:layout_columnWeight="1"
        app:layout_rowWeight="1"
        tools:checked="true"
        />

    <RadioButton
        android:id="@+id/option_4"
        style="@style/GridRadioButton"
        android:drawableTop="@drawable/preparar_carrera"
        android:text="@string/option_4"
        app:layout_columnWeight="1"
        app:layout_rowWeight="1"
        />

</com.example.ui.GridRadioGroup>

The style:

<style name="GridRadioButton">
    <item name="android:layout_width">0dp</item>
    <item name="android:layout_height">wrap_content</item>
    <item name="android:layout_margin">10dp</item>
    <item name="android:background">@drawable/button_option_background_selector</item>
    <item name="android:drawablePadding">16dp</item>
    <item name="android:button">@null</item>
    <item name="android:gravity">center_horizontal</item>
    <item name="android:padding">20dp</item>
    <item name="android:textColor">@drawable/text_button_option_color_selector</item>
    <item name="android:textSize">14sp</item>
</style>

The code is simple but it's working fine for me. If you want something more complete (with for example an OnCheckedChangeListener) then check this alternative implementation which is clearly more elaborate and on par feature-wise with a RadioGroup.

Ruddie answered 29/3, 2019 at 17:19 Comment(0)
J
6

I for one would go for nested RadioGroups. The Root RadioGroup will have a Vertical orientation and its children will be three RadioGroups with Horizontal orientation.

<RadioGroup
    android:orientation="vertical">
    <RadioGroup
        android:id="@+id/rg_1"
        android:orientation="horizontal">
        <RadioButton />
        <RadioButton />
        <RadioButton />
    </RadioGroup>
    <RadioGroup
        android:id="@id/rg_2"
        android:orientation="horizontal">
        <RadioButton />
        <RadioButton />
        <RadioButton />
    </RadioGroup>
    <RadioGroup
        android:id="@+id/rg_3"
        android:orientation="horizontal">
        <RadioButton />
        <RadioButton />
        <RadioButton />
    </RadioGroup>
</RadioGroup>

Each of the chield RadioGroups will have an ID which will be called by a RadioGroup object inside the java validation method. Like this:

RadioGroup rg_1 = (RadioGroup) findViewById(R.id.rg_1);
RadioGroup rg_2 = (RadioGroup) findViewById(R.id.rg_2);
RadioGroup rg_3 = (RadioGroup) findViewById(R.id.rg_3);

Now simply by using clearCheck() inside the switch case you can clear the check of the other two RadioGroups. Like this:

case R.id.radioButton_1:
            if (checked) {
                rg_2.clearCheck();
                rg_3.clearCheck();
            }
            break;
Jazzman answered 29/1, 2018 at 20:35 Comment(1)
I found this simpler than other answers here...;DSpectre
K
3

Your only option is to grab the source code to RadioGroup and attempt to replicate its functionality in a TableLayout or something. There is no way to create a 3x3 grid of RadioButtons otherwise. Fortunately, the RadioButton class does not know about RadioGroup -- all of the mutual-exclusion logic is in RadioGroup. Hence, it should be possible to create a RadioGrid or something...but that's going to be an awful lot of work.

Kyrakyriako answered 4/3, 2010 at 19:13 Comment(2)
So there's no way of using something like GridView either?Gingery
Only if you subclass it and give it RadioGroup capabilities.Kyrakyriako
Z
2

RadioGroup extends in the following manner..

java.lang.Object
 ↳  android.view.View
   ↳    android.view.ViewGroup
       ↳    android.widget.LinearLayout
           ↳    android.widget.RadioGroup

If you need to arrange the radio button in a grid layout, you might need to build you own custom code that extends from GridLayout.

Zonked answered 24/4, 2011 at 11:11 Comment(0)
T
0

It's a cludge but why not Why not just use nine RadioGroups, or three horizontal RadioGroups each with three buttons. Each radio group can then be aligned with a gridView, or relativeLayout etc.

The then instead of using the standard OnCheckedChangeListener of RadioButton use the one (of the same name) belonging to the CompoundButton instead.

Then when ever any RadioButton is pressed you can use the radio groups to deselect the radio buttons. Then programmatically select the radio button that was clicked.

It's a horrible solution, but it works as one would hope it to.

Below is some example code I used to do this with a 2x2 layout of buttons.

  public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        updateList(Hurricane.ELEVATION_ALL);

        watermarkAdapter = new WatermarkAdapter(getActivity(), R.layout.watermark_item, 
                           relatedHurricanes);

        setListAdapter(watermarkAdapter);

        this.getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
        this.getView().setBackgroundResource(R.drawable.splash_screen1);


        getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);


        View v = this.getView();
        filterGroup1 = (RadioGroup)v.findViewById(R.id.filter_rg1);
        filterGroup2 = (RadioGroup)v.findViewById(R.id.filter_rg2);
        filterGroup3 = (RadioGroup)v.findViewById(R.id.filter_rg3);
        filterGroup4 = (RadioGroup)v.findViewById(R.id.filter_rg4);


        rb1 = (RadioButton) v.findViewById(R.id.first_radio_button);//All
        rb2 = (RadioButton) v.findViewById(R.id.second_radio_button);//0-6
        rb4 = (RadioButton) v.findViewById(R.id.third_radio_button);//6-12
        rb3 = (RadioButton) v.findViewById(R.id.fourth_radio_button);//>=5

        rb1.setOnCheckedChangeListener(this);
        rb2.setOnCheckedChangeListener(this);
        rb3.setOnCheckedChangeListener(this);
        rb4.setOnCheckedChangeListener(this);


    }






 @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

        filterGroup1.clearCheck();
        filterGroup2.clearCheck();
        filterGroup3.clearCheck();
        filterGroup4.clearCheck();


        SharedPreferences prefs = PreferenceManager
                .getDefaultSharedPreferences(this.getActivity());

       int cid = buttonView.getId();

       Editor editor     = prefs.edit();
       int elevation = Hurricane.ELEVATION_ALL;
        //All
       if(rb1.getId() == cid){
          elevation = Hurricane.ELEVATION_ALL;
       }  
       //0-6
       else if(rb2.getId() == cid){
           elevation = Hurricane.ELEVATION_6to12;
       }
       //6-12
       else if(rb3.getId() == cid){       
           elevation = Hurricane.ELEVATION_0to6;
       }
       //>=12
       else if(rb4.getId() == cid){
           elevation = Hurricane.ELEVATION_GT12;
       }

       update(StormFragment.NORMAL, elevation);

    }
Therewith answered 8/7, 2014 at 23:19 Comment(0)
I
0

A simpler approach of my point of view is to use a RecyclerView.
The ViewHolder will contains only one RadioButton.
The data class will contain a string attribute to display, and an additional boolean attribute to switch the isChecked state.
Inside the ViewHolder, we will switch the state inside an onClickListener.
The RecyclerViewAdapter will contain an additional function to get the selected item.

Code Example

BloodType.kt

data class BloodType(val name: String, var isChecked: Boolean)

item_blood_type.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <RadioButton
        android:id="@+id/rb_item_blood_type"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        tools:text="RadioButton"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

BloodTypeAdapter.kt

class BloodTypeAdapter(val data: List<BloodType>) :
    RecyclerView.Adapter<BloodTypeAdapter.BloodTypeHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BloodTypeHolder {
        val view =
            LayoutInflater.from(parent.context).inflate(R.layout.item_blood_type, parent, false)
        return BloodTypeHolder(view)
    }

    override fun onBindViewHolder(holder: BloodTypeHolder, position: Int) {
        holder.itemView.rb_item_blood_type.isChecked = data[position].isChecked
        holder.itemView.rb_item_blood_type.text = data[position].name
    }

    override fun getItemCount(): Int {
        return data.size
    }

    /**
     * @return The selected item from the list.
     */
    fun getCheckedItem(): BloodType {
        data.forEach {
            if (it.isChecked) {
                return it
            }
        }
        return data[0]
    }

    inner class BloodTypeHolder(view: View) : RecyclerView.ViewHolder(view) {
        init {
            itemView.rb_item_blood_type.setOnClickListener {
                data.forEachIndexed { index, bloodType ->
                    bloodType.isChecked = index == adapterPosition
                }
                notifyDataSetChanged()
            }
        }
    }
}

Presenter.kt

//... 
private fun initializeBloodTypeRecyclerView() {
        rvBloodType.layoutManager = GridLayoutManager(context, 2)
        val bloodTypes = mutableListOf<BloodType>()
        bloodTypes.apply {
            add(BloodType("A+", true))
            add(BloodType("A-", false))
            add(BloodType("B+", false))
            //...
        }
        val bloodTypeAdapter = BloodTypeAdapter(bloodTypes)
        rvBloodType.adapter = bloodTypeAdapter
    }
//...
Impel answered 25/5, 2021 at 9:23 Comment(0)
L
0

Here is solution

public class RadioGridGroup extends TableLayout implements View.OnClickListener {

private static final String TAG = "ToggleButtonGroupTableLayout";
private int checkedButtonID = -1;
private RadioGridGroup.OnCheckedChangeListener mOnCheckedChangeListener;
/**
 * @param context
 */
public RadioGridGroup(Context context) {
    super(context);
    // TODO Auto-generated constructor stub
}

/**
 * @param context
 * @param attrs
 */
public RadioGridGroup(Context context, AttributeSet attrs) {
    super(context, attrs);
    // TODO Auto-generated constructor stub
}

@Override
public void onClick(View v) {
    if (v instanceof RadioButton) {
        int id = v.getId();
        check(id);
    }
}

private void setCheckedStateForView(int viewId, boolean checked) {
    View checkedView = findViewById(viewId);
    if (checkedView != null && checkedView instanceof RadioButton) {
        ((RadioButton) checkedView).setChecked(checked);
    }
}

/* (non-Javadoc)
 * @see android.widget.TableLayout#addView(android.view.View, int, android.view.ViewGroup.LayoutParams)
 */
@Override
public void addView(View child, int index,
                    android.view.ViewGroup.LayoutParams params) {
    super.addView(child, index, params);
    setChildrenOnClickListener((TableRow) child);
}


/* (non-Javadoc)
 * @see android.widget.TableLayout#addView(android.view.View, android.view.ViewGroup.LayoutParams)
 */
@Override
public void addView(View child, android.view.ViewGroup.LayoutParams params) {
    super.addView(child, params);
    setChildrenOnClickListener((TableRow) child);
}


private void setChildrenOnClickListener(TableRow tr) {
    final int c = tr.getChildCount();
    for (int i = 0; i < c; i++) {
        final View v = tr.getChildAt(i);
        if (v instanceof RadioButton) {
            v.setOnClickListener(this);
        }
    }
}


/**
 * @return the checked button Id
 */
public int getCheckedRadioButtonId() {
    return checkedButtonID;
}


/**
 * Check the id
 *
 * @param id
 */
public void check(@IdRes int id) {
    // don't even bother
    if (id != -1 && (id == checkedButtonID)) {
        return;
    }
    if (checkedButtonID != -1) {
        setCheckedStateForView(checkedButtonID, false);
    }
    if (id != -1) {
        setCheckedStateForView(id, true);
    }
    setCheckedId(id);
}

/**
 * set the checked button Id
 *
 * @param id
 */
private void setCheckedId(int id) {
    if (mOnCheckedChangeListener != null) {
        mOnCheckedChangeListener.onCheckedChanged(this, id);
    }
    this.checkedButtonID = id;
}

public void clearCheck() {
    check(-1);
}

@Override
protected void onRestoreInstanceState(Parcelable state) {
    if (!(state instanceof SavedState)) {
        super.onRestoreInstanceState(state);
        return;
    }

    SavedState ss = (SavedState) state;
    super.onRestoreInstanceState(ss.getSuperState());

    this.checkedButtonID = ss.buttonId;
    setCheckedStateForView(checkedButtonID, true);
}

@Override
protected Parcelable onSaveInstanceState() {
    Parcelable superState = super.onSaveInstanceState();
    SavedState savedState = new SavedState(superState);
    savedState.buttonId = checkedButtonID;
    return savedState;
}

static class SavedState extends BaseSavedState {
    int buttonId;

    /**
     * Constructor used when reading from a parcel. Reads the state of the superclass.
     *
     * @param source
     */
    public SavedState(Parcel source) {
        super(source);
        buttonId = source.readInt();
    }

    /**
     * Constructor called by derived classes when creating their SavedState objects
     *
     * @param superState The state of the superclass of this view
     */
    public SavedState(Parcelable superState) {
        super(superState);
    }

    @Override
    public void writeToParcel(Parcel out, int flags) {
        super.writeToParcel(out, flags);
        out.writeInt(buttonId);
    }

    public static final Parcelable.Creator<SavedState> CREATOR =
            new Parcelable.Creator<SavedState>() {
                public SavedState createFromParcel(Parcel in) {
                    return new SavedState(in);
                }

                public SavedState[] newArray(int size) {
                    return new SavedState[size];
                }
            };
}
public void setOnCheckedChangeListener(RadioGridGroup.OnCheckedChangeListener listener) {
    mOnCheckedChangeListener = listener;
}
public interface OnCheckedChangeListener {

    public void onCheckedChanged(RadioGridGroup group, @IdRes int checkedId);
}}

Click Listener

    RadioGridGroup radioGroup = findViewById(R.id.radioGroup);
   
    radioGroup.setOnCheckedChangeListener(new RadioGridGroup.OnCheckedChangeListener() {

        @Override
        public void onCheckedChanged(RadioGridGroup group, int checkedId) {
            
            if (checkedId == R.id.radio6) {
                
            }
        }

    });

XML

<com.customviews.RadioGridGroup 
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">

<TableRow android:layout_marginTop="@dimen/preview_five">

    <RadioButton
        android:id="@+id/rad1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button1" />

    <RadioButton
        android:id="@+id/rad2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button2" />
</TableRow>

<TableRow android:layout_marginTop="@dimen/preview_five">

    <RadioButton
        android:id="@+id/rad3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button3" />

    <RadioButton
        android:id="@+id/rad4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button4" />
</TableRow>

<TableRow android:layout_marginTop="@dimen/preview_five">

    <RadioButton
        android:id="@+id/rad5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button5" />

    <RadioButton
        android:id="@+id/rad6"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button6" />
</TableRow>

<TableRow android:layout_marginTop="@dimen/preview_five">

    <RadioButton
        android:id="@+id/rad7"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button7" />

    <RadioButton
        android:id="@+id/rad8"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button8" />
</TableRow>
</com.customviews.RadioGridGroup>

Note : Make sure all radio buttons must be under TableRow.

Leinster answered 24/11, 2021 at 7:6 Comment(1)
this solution have an error when set default check radiobutton in the first load, after user click so occur problem.Ilmenite
I
0

RadioButotn with Grid display include setOnCheckedListener fix error with set default radio button in the first load

  1. Create class RadioGridGroup extends GridLayout

       public class RadioGridGroup extends GridLayout {
     private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
     private int mCheckedId = -1;
     private CompoundButton.OnCheckedChangeListener mChildOnCheckedChangeListener;
     private boolean mProtectFromCheckedChange = false;
     private OnCheckedChangeListener mOnCheckedChangeListener;
     private PassThroughHierarchyChangeListener mPassThroughListener;
    
     public RadioGridGroup(Context context) {
         super(context);
         init();
     }
    
     public RadioGridGroup(Context context, AttributeSet attrs) {
         super(context, attrs);
         init();
     }
    
     private void init() {
         mChildOnCheckedChangeListener = new CheckedStateTracker();
         mPassThroughListener = new PassThroughHierarchyChangeListener();
         super.setOnHierarchyChangeListener(mPassThroughListener);
     }
    
     @Override
     public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
         mPassThroughListener.mOnHierarchyChangeListener = listener;
     }
    
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
    
         if (mCheckedId != -1) {
             mProtectFromCheckedChange = true;
             setCheckedStateForView(mCheckedId, true);
             mProtectFromCheckedChange = false;
             setCheckedId(mCheckedId);
         }
     }
    
     @Override
     public void addView(@NonNull View child, int index, ViewGroup.LayoutParams params) {
         if (child instanceof AppCompatRadioButton) {
             final AppCompatRadioButton button = (AppCompatRadioButton) child;
             if (button.isChecked()) {
                 mProtectFromCheckedChange = true;
                 if (mCheckedId != -1) {
                     setCheckedStateForView(mCheckedId, false);
                 }
                 mProtectFromCheckedChange = false;
                 setCheckedId(button.getId());
             }
         }
    
         super.addView(child, index, params);
     }
    
     public void check(int id) {
         if (id != -1 && (id == mCheckedId)) {
             return;
         }
    
         if (mCheckedId != -1) {
             setCheckedStateForView(mCheckedId, false);
         }
    
         if (id != -1) {
             setCheckedStateForView(id, true);
         }
    
         setCheckedId(id);
     }
    
     private void setCheckedId(int id) {
         mCheckedId = id;
         if (mOnCheckedChangeListener != null) {
             mOnCheckedChangeListener.onCheckedChanged(this, mCheckedId);
         }
     }
    
     private void setCheckedStateForView(int viewId, boolean checked) {
         View checkedView = findViewById(viewId);
         if (checkedView != null && checkedView instanceof AppCompatRadioButton) {
             ((AppCompatRadioButton) checkedView).setChecked(checked);
         }
     }
    
     public int getCheckedCheckableImageButtonId() {
         return mCheckedId;
     }
    
     public void clearCheck() {
         check(-1);
     }
    
     public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
         mOnCheckedChangeListener = listener;
     }
    
     @Override
     public void onInitializeAccessibilityEvent(@NonNull AccessibilityEvent event) {
         super.onInitializeAccessibilityEvent(event);
         event.setClassName(RadioGridGroup.class.getName());
     }
    
     @Override
     public void onInitializeAccessibilityNodeInfo(@NonNull AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(info);
         info.setClassName(RadioGridGroup.class.getName());
     }
    
     public interface OnCheckedChangeListener {
         void onCheckedChanged(RadioGridGroup group, int checkedId);
     }
    
     private class CheckedStateTracker implements CompoundButton.OnCheckedChangeListener {
         @Override
         public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
             if (mProtectFromCheckedChange) {
                 return;
             }
    
             mProtectFromCheckedChange = true;
             if (mCheckedId != -1) {
                 setCheckedStateForView(mCheckedId, false);
             }
             mProtectFromCheckedChange = false;
    
             int id = buttonView.getId();
             setCheckedId(id);
         }
     }
    
     private class PassThroughHierarchyChangeListener implements
             ViewGroup.OnHierarchyChangeListener {
         private ViewGroup.OnHierarchyChangeListener mOnHierarchyChangeListener;
    
         public void onChildViewAdded(View parent, View child) {
             if (parent == RadioGridGroup.this && child instanceof AppCompatRadioButton) {
                 int id = child.getId();
                 // generates an id if it's missing
                 if (id == View.NO_ID) {
                     id = generateViewId();
                     child.setId(id);
                 }
                 ((AppCompatRadioButton) child).setOnCheckedChangeListener(
                         mChildOnCheckedChangeListener);
             }
    
             if (mOnHierarchyChangeListener != null) {
                 mOnHierarchyChangeListener.onChildViewAdded(parent, child);
             }
         }
    
         public void onChildViewRemoved(View parent, View child) {
             if (parent == RadioGridGroup.this && child instanceof AppCompatRadioButton) {
                 ((AppCompatRadioButton) child).setOnCheckedChangeListener(null);
             }
    
             if (mOnHierarchyChangeListener != null) {
                 mOnHierarchyChangeListener.onChildViewRemoved(parent, child);
             }
         }
     }
    
     public static int generateViewId() {
         for (; ; ) {
             final int result = sNextGeneratedId.get();
    
             // aapt-generated IDs have the high byte nonzero; clamp to the range under that.
             int newValue = result + 1;
             if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0.
    
             if (sNextGeneratedId.compareAndSet(result, newValue)) {
                 return result;
             }
         }
     }
    

    }

  2. Step 2: code in XML

<yourpackage.RadioGridGroup android:columnCount="3" android:useDefaultMargins="true" > <androidx.appcompat.widget.AppCompatRadioButton/> <androidx.appcompat.widget.AppCompatRadioButton/> <androidx.appcompat.widget.AppCompatRadioButton/> <androidx.appcompat.widget.AppCompatRadioButton/> <androidx.appcompat.widget.AppCompatRadioButton/>

So you can use setOnCheckChangeListener like normal

Ilmenite answered 19/4 at 17:40 Comment(1)
note: use AppCompatRadioButtonIlmenite

© 2022 - 2024 — McMap. All rights reserved.