Android 具有两列且有十个单选按钮的RadioGroup

Android 具有两列且有十个单选按钮的RadioGroup,android,radio-button,radio-group,Android,Radio Button,Radio Group,我有一个RadioGroup,我想在两列五行中对齐相邻的按钮,但我无法实现。我尝试过的事情: RelativeLayout->外部RadioGroup->内部RadioGroup。 所有单选按钮都已选择,但我只希望选择一个 RadioGroup:方向 跨度,伸缩柱 TableRow TableLayout 请告诉我如何创建一个RadioGroup,并在其中包含两列和多个单选按钮。该RadioGroup是从LinearLayout扩展而来的 linearlayout无法执行此操作,因此RadioG

我有一个
RadioGroup
,我想在两列五行中对齐相邻的按钮,但我无法实现。我尝试过的事情:

  • RelativeLayout
    ->外部
    RadioGroup
    ->内部
    RadioGroup
    。 所有
    单选按钮都已选择,但我只希望选择一个
  • RadioGroup
    :方向
  • 跨度,伸缩柱
  • TableRow
  • TableLayout

  • 请告诉我如何创建一个
    RadioGroup
    ,并在其中包含两列和多个
    单选按钮。

    该RadioGroup是从LinearLayout扩展而来的

    linearlayout无法执行此操作,因此RadioGroup无法执行此操作

    为什么不自己实施呢

    使用RelativeLayout布局子视图。 并记录子视图的状态。 使用setLevel控制状态


    祝你好运

    您可以模拟
    RadioGroup
    ,使其看起来像只有一个。例如,您有
    rg1
    rg2
    radiogroup
    ,方向设置为
    vertical
    (两列))。要设置这些
    射线组

    rg1 = (RadioGroup) findViewById(R.id.radioGroup1);
    rg2 = (RadioGroup) findViewById(R.id.radioGroup2);
    rg1.clearCheck(); // this is so we can start fresh, with no selection on both RadioGroups
    rg2.clearCheck();
    rg1.setOnCheckedChangeListener(listener1);
    rg2.setOnCheckedChangeListener(listener2);
    
    要在这些
    radiogroup
    中仅选择一个
    RadioButton
    ,上述侦听器将为:

    private OnCheckedChangeListener listener1 = new OnCheckedChangeListener() {
    
            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                if (checkedId != -1) {
                    rg2.setOnCheckedChangeListener(null); // remove the listener before clearing so we don't throw that stackoverflow exception(like Vladimir Volodin pointed out)
                    rg2.clearCheck(); // clear the second RadioGroup!
                    rg2.setOnCheckedChangeListener(listener2); //reset the listener
                    Log.e("XXX2", "do the work");
                }
            }
        };
    
        private OnCheckedChangeListener listener2 = new OnCheckedChangeListener() {
    
            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                if (checkedId != -1) {
                    rg1.setOnCheckedChangeListener(null);
                    rg1.clearCheck();
                    rg1.setOnCheckedChangeListener(listener1);
                    Log.e("XXX2", "do the work");
                }
            }
        };
    
    要从
    radiogroup
    中获取选中的
    单选按钮
    ,您可以执行以下操作:

    int chkId1 = rg1.getCheckedRadioButtonId();
    int chkId2 = rg2.getCheckedRadioButtonId();
    int realCheck = chkId1 == -1 ? chkId2 : chkId1;
    

    如果您使用
    RadioGroup
    check()
    方法,您必须记住在另一个
    RadioGroup
    上调用
    clearCheck()
    ,我必须做同样的事情,并将一个TableLayout和一个RadioButtonGroup组合起来。我将单选按钮动态添加到TableRows。下面是课堂:

    public class RadioGroupColumns extends TableLayout implements OnClickListener {
    
    private static final String TAG = "RadioGroupColumns";
    private RadioButton activeRadioButton;
    private int mCheckedId = -1;
    // tracks children radio buttons checked state
    private CompoundButton.OnCheckedChangeListener mChildOnCheckedChangeListener;
    // when true, mOnCheckedChangeListener discards events
    private boolean mProtectFromCheckedChange = false;
    private OnCheckedChangeListener mOnCheckedChangeListener;
    private PassThroughHierarchyChangeListener mPassThroughListener;
    
    public RadioGroupColumns(Context context) {
        super(context);
        setOrientation(VERTICAL);
        init();
    }
    
    public RadioGroupColumns(Context context, AttributeSet attrs) {
                super(context, attrs);
                Resources res = Resources.getSystem();
                int value = 0;
                // retrieve selected radio button as requested by the user in the
                // XML layout file
    
                TypedArray attributes = null;
                try {
                    attributes = context.obtainStyledAttributes(attrs, getAttributes(context), R.attr.radioButtonStyle, 0);
                    value = attributes.getResourceId(getAttribute(context), View.NO_ID);
                } catch (IllegalAccessException e) {
                    // TODO Auto-generated catch block
                    Log.d("Exception RadioGroupColumns Construct",e.toString());
                    e.printStackTrace();
                }
                catch (ClassNotFoundException e) { 
                    Log.d("Exception RadioGroupColumns Construct",e.toString());
                    e.printStackTrace();
                }  
    
    
                if (value != View.NO_ID) {
                    mCheckedId = value;
                }
    
                //hardcode it to vertical
                //final int index = attributes.getInt(com.android.internal.R.styleable.RadioGroup_orientation, VERTICAL);
                //setOrientation(index);
    
                attributes.recycle();
    
                setOrientation(VERTICAL);
                init();
    }
    
    @Override
    public void onClick(View v) {
        if (v instanceof TableRow) {
            TableRow row = (TableRow)v;
            for (int j=0;j<row.getChildCount();j++) { 
                if (RadioButton.class.isAssignableFrom(row.getChildAt(j).getClass())) {
    
                    ((RadioButton) row.getChildAt(j)).setChecked(true);
                    activeRadioButton = (RadioButton) row.getChildAt(j);
                }
            }
        }
        else { 
            final RadioButton rb = (RadioButton) v;
    
            if (activeRadioButton != null) {
                activeRadioButton.setChecked(false);
            }
            rb.setChecked(true);
            activeRadioButton = rb;
        }
    
    }
    
    private void init() {
        mChildOnCheckedChangeListener = new CheckedStateTracker();
        mPassThroughListener = new PassThroughHierarchyChangeListener();
        super.setOnHierarchyChangeListener(mPassThroughListener);
    }
    
    private int getAttribute(Context con) throws ClassNotFoundException, IllegalArgumentException, IllegalAccessException { 
    //use reflect to get styleable class.
    Field[] alFields = null; 
    ArrayList<Integer> alInts = new ArrayList<Integer>();
    int R_ID = 0;
    
    for (Class c : android.R.class.getClasses()) { 
         if (c.getName().indexOf("styleable") >= 0) { 
             alFields = Class.forName( con.getPackageName() + ".R$styleable" ).getFields();
    
         } 
     }
    for (Field f : alFields) { 
        Log.d("field name",f.getName());
        if (f.getName().equals("RadioGroup_checkedButton")) { 
            int[] ret = (int[])f.get(null);
            R_ID = ret[0];
        }
    
    }
    return R_ID;
    
    
    }
    
    //gets all RadioGroup R,android.internal.styleable.RadioGroup values
    private int[] getAttributes(Context con) throws IllegalAccessException, ClassNotFoundException { 
        //use reflect to get styleable class.
        Field[] alFields = null; 
        ArrayList<Integer> alInts = new ArrayList<Integer>();
        int[] ints = null;
        int count = 0;
        try {
            for (Class c : android.R.class.getClasses()) { 
                 if (c.getName().indexOf("styleable") >= 0) { 
                     Log.d("get Class Name Outer", c.getName());
                    //use reflection to access the resource class
                     alFields = Class.forName( con.getPackageName() + ".R$styleable" ).getFields();          
                 } 
    
             }
             if (alFields != null) 
                 {
                    Log.d("field numbers size", String.valueOf(alFields.length));
    
                    for (Field field : alFields) { 
    
                     Class<?> targetType = field.getType();
                     Log.d("field type", field.getType().toString());
                     if (targetType.equals(Integer.TYPE) && targetType.isPrimitive()) { 
                         //alInts.add((Integer)field);
                         Object objectValue = (Integer)field.getInt(null);
                         //Object objectValue = (Integer)targetType.newInstance(); 
                         alInts.add((Integer)objectValue);
                         count++;
                     }
                     ints = new int[count];
                     for (int i=0;i<alInts.size();i++) { 
                         ints[i] = alInts.get(i);
                     }
                 }
    
             }
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (ClassNotFoundException e) { 
            e.printStackTrace();
        }
        return ints;
    
    
        }
    
    public void check(int id) {
        // don't even bother
        if (id != -1 && (id == mCheckedId)) {
            return;
        }
        if (mCheckedId != -1) {
            setCheckedStateForView(mCheckedId, false);
        }
        if (id != -1) {
            setCheckedStateForView(id, true);
        }
        activeRadioButton = (RadioButton) findViewById(id);
        activeRadioButton.setChecked(true);
        setCheckedId(id);
    }
    
    public void setOnCheckedChangeListener(RadioGroupColumns.OnCheckedChangeListener onCheckedChangeListener) {
        mOnCheckedChangeListener = (OnCheckedChangeListener) onCheckedChangeListener;
    }
    
    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 (!RadioButton.class.isAssignableFrom(checkedView.getClass()) && checkedView != null) { 
            TableRow row = (TableRow) checkedView;
            for (int j=0;j<row.getChildCount();j++) { 
                RadioButton button = (RadioButton) row.getChildAt(j);
                if (button.isChecked() && button != null) { 
                    button.setChecked(checked);
                }
            }
        }
        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);
            }
        }
    }
    
    public int getCheckedRadioButtonId() {
        if (activeRadioButton != null) {
            return activeRadioButton.getId();
        }
    
        return -1;
    }
    
    public interface OnCheckedChangeListener {
    
        public void onCheckedChanged(RadioGroupColumns group, int checkedId);
    }
    
    private class CheckedStateTracker implements CompoundButton.OnCheckedChangeListener {
        public void onCheckedChanged(CompoundButton buttonView,
                boolean isChecked) {
            // prevents from infinite recursion
            if (mProtectFromCheckedChange) {
                return;
            }
    
            mProtectFromCheckedChange = true;
            if (mCheckedId != -1) {
                setCheckedStateForView(mCheckedId, false);
            }
            mProtectFromCheckedChange = false;
            int id = buttonView.getId();
            setCheckedId(id);
        }
    }
    
    private class PassThroughHierarchyChangeListener implements android.view.ViewGroup.OnHierarchyChangeListener {
        private android.view.ViewGroup.OnHierarchyChangeListener mOnHierarchyChangeListener;
    
        /**
         * {@inheritDoc}
         */
        @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
        public void onChildViewAdded(View parent, View child) {
            if (parent == RadioGroupColumns.this
                    && child instanceof RadioButton) {
                int id = child.getId();
                // generates an id if it's missing
                if (id == View.NO_ID) {
                    id = View.generateViewId();
                    child.setId(id);
                }
                ((RadioButton) child).setOnCheckedChangeListener((com.assistek.ediary.RadioButton.OnCheckedChangeListener) mChildOnCheckedChangeListener);
            }
    
            if (mOnHierarchyChangeListener != null) {
                mOnHierarchyChangeListener.onChildViewAdded(parent, child);
            }
        }
    
        /**
         * {@inheritDoc}
         */
        public void onChildViewRemoved(View parent, View child) {
            if (parent == RadioGroupColumns.this
                    && child instanceof RadioButton) {
                ((RadioButton) child).setOnCheckedChangeListener(null);
            }
    
            if (mOnHierarchyChangeListener != null) {
                mOnHierarchyChangeListener.onChildViewRemoved(parent, child);
            }
        }
    }
    
     }
    
    公共类RadioGroupColumns扩展TableLayout实现OnClickListener{
    私有静态最终字符串TAG=“RadioGroupColumns”;
    专用单选按钮活动单选按钮;
    private int mCheckedId=-1;
    //跟踪选中状态下的儿童单选按钮
    private CompoundButton.OnCheckedChangeListener mChildOnCheckedChangeListener;
    //如果为true,mOnCheckedChangeListener将丢弃事件
    私有布尔mProtectFromCheckedChange=false;
    private OnCheckedChangeListener mOnCheckedChangeListener;
    私有直通HierarchyChangeListener mPassThroughListener;
    公共列(上下文){
    超级(上下文);
    设置方向(垂直);
    init();
    }
    公共列(上下文、属性集属性){
    超级(上下文,attrs);
    Resources res=Resources.getSystem();
    int值=0;
    //根据用户在中的请求检索所选单选按钮
    //XML布局文件
    TypedArray属性=空;
    试一试{
    attributes=context.obtainStyledAttributes(attrs,getAttributes(context),R.attr.radioButtonStyle,0);
    value=attributes.getResourceId(getAttribute(context),View.NO\u ID);
    }捕获(非法访问例外e){
    //TODO自动生成的捕捉块
    d(“异常组列构造”,例如toString());
    e、 printStackTrace();
    }
    catch(classnotfound异常){
    d(“异常组列构造”,例如toString());
    e、 printStackTrace();
    }  
    if(值!=视图。无\u ID){
    mCheckedId=值;
    }
    //将其硬编码为垂直
    //最终int索引=attributes.getInt(com.android.internal.R.styleable.RadioGroup\u方向,垂直);
    //方向(索引);
    attributes.recycle();
    设置方向(垂直);
    init();
    }
    @凌驾
    公共void onClick(视图v){
    if(v instanceof TableRow){
    TableRow row=(TableRow)v;
    对于(int j=0;j=0){
    alFields=Class.forName(con.getPackageName()+“.R$styleable”).getFields();
    } 
    }
    对于(字段f:alFields){
    Log.d(“字段名”,f.getName());
    如果(f.getName().equals(“RadioGroup_checkedButton”){
    int[]ret=(int[])f.get(null);
    R_ID=ret[0];
    }
    }
    返回R_ID;
    }
    //获取所有RadioGroup R、android.internal.styleable.RadioGroup值
    private int[]getAttributes(Context con)抛出IllegaAccessException,ClassNotFoundException{
    //使用reflect获得可设置样式的类。
    字段[]alFields=null;
    ArrayList alInts=新的ArrayList();
    int[]int=null;
    整数计数=0;
    试一试{
    对于(类c:android.R.Class.getClasses()){
    如果(c.getName().indexOf(“styleable”)>=0{
    d(“获取外部类名”,c.getName());
    //使用反射来访问资源类
    alFields=Class.forName(con.getPackageName()+“.R$styleable”).getFields();
    } 
    }
    if(alFields!=null)
    {
    Log.d(“字段号大小”,String.valueOf(alFields.length));
    对于(字段:alFields){
    类targetType=field.getType();
    Log.d(“字段类型”,field.getType().toString());
    if(targetType.equals(Integer.TYPE)&&targetType.isPrimitive()){
    //alInts.add((整数)字段);
    objectValue=(整型)field.getInt(null);
    //Object objectValue=(整数)targetType.newInstance();
    add((整数)objectValue);
    计数++;
    }
    整数=新整数[计数];
    对于(int i=0;i 0)
    NumberInColumns++;
    for(int i=0;i    private void setupRadioButtonAnswers() {
        ArrayList<HolderAnswer> listAnswers = GlobalVars.questionHolders[GlobalVars.arrayRowNumber]
                .getListAnswers();
        ArrayList<ArrayList<HolderAnswer>> listAnswersSorted = new ArrayList<ArrayList<HolderAnswer>>();
        ArrayList<TableRow> alTableRows = new ArrayList<TableRow>();
    
        int NumberInColumns = (int) Math.floor(listAnswers.size() / NUMBER_OF_COLUMNS);
        // make higher number of answers on the right
        if (listAnswers.size() % NUMBER_OF_COLUMNS > 0)
            NumberInColumns++;
    
        for (int i = 0; i < NumberInColumns; i++) {
            TableRow row = new TableRow(this);
            TableRow.LayoutParams lp = new TableRow.LayoutParams(
                    TableRow.LayoutParams.WRAP_CONTENT);
            row.setLayoutParams(lp);
            alTableRows.add(row);
        }
    
        int count = 0;
    
        // sort by row
        /*
         * a[0] = "Question 1"
           a[1] = "Question 2"
           a[2] = "Question 3"
           a[3] = "Question 4"
           a[4] = "Question 5"
           a[5] = "Question 6"
           a[6] = "Question 7"
    
           sorted to:
    
           a[0] = "Question 1"   a[1] = "Question 5"
           a[2] = "Question 2"   a[3] = "Question 6"
           a[4] = "Question 3"   a[5] = "Question 7"
           a[6] = "Question 4"
         */
    
        // initialize the ArrayLists in listAnswersSorted
        int numRows = listAnswers.size() / NUMBER_OF_COLUMNS + 1;
        for (int i = 0; i < numRows; i += 1) {
            listAnswersSorted.add(new ArrayList<HolderAnswer>());
        }
    
        // calculate column index where the "step" happens
        int step = listAnswers.size() % NUMBER_OF_COLUMNS;
    
        // loop through and add elements to listAnswersSorted
        int index = 0;
        int row = 0;
        int col = 0;
        while (index < listAnswers.size()) {
            listAnswersSorted.get(row).add(listAnswers.get(index));
    
            int rows = col < step ? numRows : numRows - 1;
            row += 1;
            if (row == rows) {
            row = 0;
            col += 1;
            }
            index += 1;
        }
    
    
        row = 0;
        int columncount = 1;
        for (ArrayList<HolderAnswer> sortedArrayList : listAnswersSorted) {
            for (HolderAnswer answer : sortedArrayList) {
    
                final RadioButton button = new RadioButton(this);
                button.setTag(answer.getRecID());
                button.setId(GlobalVars.getLatestId());
                button.setTextColor(Color.BLACK);
                GlobalVars.setupText(con, button, answer.getTextID());
    
                button.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        button.setEnabled(false);
                        handlerReenableView.sendEmptyMessageDelayed(button.getId(), 1000);
    
                        button.setChecked(true);
                        radioGroup.check(button.getId());
                    }
                });
    
    
                button.setLayoutParams(new TableRow.LayoutParams(columncount));
                alTableRows.get(row).addView(button);
    
                if (columncount==NUMBER_OF_COLUMNS) { 
                    columncount = 1;
                    radioGroup.addView(alTableRows.get(row));
                    alTableRows.get(row).setOnClickListener(new View.OnClickListener() {
    
                        @Override
                        public void onClick(View v) {
    
                            for(int k=0;k<((TableRow) v).getChildCount();k++) { 
                                TableRow row = (TableRow) v;
                                for (int l=0;l<row.getChildCount();l++) { 
                                    RadioButton tableButton =  (RadioButton) row.getChildAt(l);
                                    if (tableButton.isChecked) { 
                                        radioGroup.check(tableButton.getId());
                                    }
                                }
                            }
                        }
    
                    });
    
                }
    
                else { 
                    columncount++;
                }
                //if (row=NumberInColumns)
                count++;
    
            }
    
            if (count == listAnswers.size()) { 
                radioGroup.addView(alTableRows.get(row));
            }
            row++;
    
        }
    
    
    
        radioGroup.setOnCheckedChangeListener(new RadioGroupColumns.OnCheckedChangeListener() {
                    @Override
                    public void onCheckedChanged(RadioGroupColumns group, int checkedId) {
                        Log.d("We're here",String.valueOf(checkedId));
                        if (checkedId == -1) {
                            for (int i = 0; i < radioGroup.getChildCount(); i++) {
                                TableRow row = (TableRow)radioGroup.getChildAt(i); 
                                for (int j=0;j<row.getChildCount();j++) { 
                                    if (RadioButton.class.isAssignableFrom(row.getChildAt(j).getClass())) {
                                        ((RadioButton) row.getChildAt(j)).setChecked(false);
                                    }
                                }
                            }
                        } else {
                            for (int i = 0; i < radioGroup.getChildCount(); i++) {
                                TableRow row = (TableRow)radioGroup.getChildAt(i); 
                                for (int j=0;j<row.getChildCount();j++) { 
                                    if (RadioButton.class.isAssignableFrom(row.getChildAt(j).getClass()) 
                                            && row.getChildAt(j).getId() != -1) {
                                        ((RadioButton) row.getChildAt(j)).setChecked(false);
                                    }
                                }
    
                            }
    
                            RadioButton checkedRadioButton = (RadioButton) radioGroup.findViewById(checkedId);
                            checkedRadioButton.setChecked(true);
                            Log.d("checkedID onchecked Change()", String.valueOf(radioGroup.getCheckedRadioButtonId()));
                        }
                    }
    
                });
    
    }
    
    rg1 = (RadioGroup) findViewById(R.id.radiogroup1);
    rg2 = (RadioGroup) findViewById(R.id.radiogroup2);
    rg1.clearCheck();//this is so we can start fresh, with no selection on both RadioGroups
    rg2.clearCheck();
    rg1.setOnCheckedChangeListener(new OnCheckedChangeListener() {
    
            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                // TODO Auto-generated method stub
                if (checkedId != -1) {
                    fun2();
                }
            }
        });
    
        rg2.setOnCheckedChangeListener(new OnCheckedChangeListener() {
    
            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                // TODO Auto-generated method stub
                if (checkedId != -1) {
                    fun1();
                }
            }
        });
    
    public void fun1() {
         rg1.setOnCheckedChangeListener(null);
         rg1.clearCheck();
         rg1.setOnCheckedChangeListener(new OnCheckedChangeListener() {
    
            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                fun2();
                Log.v("Inside fun1","fun2");
            }
        });
    }
    
    public void fun2() {
         rg2.setOnCheckedChangeListener(null);
         rg2.clearCheck();
         rg2.setOnCheckedChangeListener(new OnCheckedChangeListener() {
    
            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                // TODO Auto-generated method stub
                fun1();
                Log.v("Inside fun2","fun1");
    
            }
        });
    }
    
    android:onClick="handleCombinedClick"
    
    public void handleCombinedClick(View view) {
        // Clear any checks from both groups:
        rg1.clearCheck();
        rg2.clearCheck();
    
        // Manually set the check in the newly clicked radio button:
        ((RadioButton) view).setChecked(true);
    
        // Perform any action desired for the new selection:
        switch (view.getId()) {
            case R.id.radio_button_1:
                // do something
                break;
    
            case R.id.radio_button_2:
                // do something
                break;
    
            ...
        }
    }
    
                <RadioGroup
                    android:id="@+id/radio_group"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:layout_marginBottom="4dp"
                    android:layout_marginTop="4dp"
                    android:orientation="vertical">
    
                    <RelativeLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content">
    
                        <android.support.v7.widget.AppCompatRadioButton
                            android:id="@+id/r1c1"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_alignParentLeft="true"
                            android:layout_alignParentStart="true"
                            android:layout_alignParentTop="true"
                            android:layout_marginRight="8dp"
                            android:gravity="center"
                            android:text="Row 1 Column1" />
    
                        <android.support.v7.widget.AppCompatRadioButton
                            android:id="@+id/r2c1"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_below="@id/r1c1"
                            android:layout_gravity="left|center_vertical"
                            android:layout_marginRight="8dp"
                            android:layout_weight="1"
                            android:gravity="left|center_vertical"
                            android:text="Row 2 Column 1" />
    
                        <android.support.v7.widget.AppCompatRadioButton
                            android:id="@+id/r1c2"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_marginRight="8dp"
                            android:layout_toRightOf="@id/r1c1"
                            android:gravity="center"
                            android:text="Row 1 Column 2"/>
    
                        <android.support.v7.widget.AppCompatRadioButton
                            android:id="@+id/r1c3"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_marginRight="8dp"
                            android:layout_toRightOf="@id/r1c2"
                            android:gravity="center"
                            android:text="Row 1 Column 3" />
                    </RelativeLayout>
                </RadioGroup>
    
    /**
     * Layout that arranges radio buttons in multiple lines.
     * Only one radio button can be checked at the same time.
     * <p>
     * XML Attributes:
     * <p>
     * max_in_row:
     * A non-negative number that represents the maximum radio buttons in a row,
     * 0 for all in one line.
     * <p>
     * radio_buttons:
     * String-array resource reference that represents the texts of the desired radio buttons.
     * <p>
     * default_button:
     * String that represents the text or the index of the radio button to be checked by default.
     * The string should be in the following format:
     * for text: "text:[text-of-button]" where text-of-button is the text of the button to check.
     * for index: "index:[index-of-button]" where index-of-button is the index of the button to check.
     * when the prefix omitted, "text:" inserted implicitly.
     */
    public class MultiLineRadioGroup extends RadioGroup {
    
        private static final String XML_DEFAULT_BUTTON_PREFIX_INDEX = "index:";
        private static final String XML_DEFAULT_BUTTON_PREFIX_TEXT = "text:";
    
        private static final int DEF_VAL_MAX_IN_ROW = 0;
    
        private OnCheckedChangeListener mOnCheckedChangeListener;
    
        private int mMaxInRow;
    
        // all buttons are stored in table layout
        private TableLayout mTableLayout;
    
        // list to store all the buttons
        private List<RadioButton> mRadioButtons;
    
        // the checked button
        private RadioButton checkedButton;
    
        /**
         * Creates a new MultiLineRadioGroup for the given context.
         *
         * @param context the application environment
         */
        public MultiLineRadioGroup(Context context) {
            super(context);
            init(null);
        }
    
        /**
         * Creates a new MultiLineRadioGroup for the given context
         * and with the specified set attributes.
         *
         * @param context the application environment
         * @param attrs   a collection of attributes
         */
        public MultiLineRadioGroup(Context context, AttributeSet attrs) {
            super(context, attrs);
            init(attrs);
        }
    
        // initializes the layout
        private void init(AttributeSet attrs) {
            mRadioButtons = new ArrayList<>();
    
            mTableLayout = getTableLayout();
            addView(mTableLayout);
    
            if (attrs != null)
                initAttrs(attrs);
        }
    
        // initializes the layout with the specified attributes
        private void initAttrs(AttributeSet attrs) {
            TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(
                    attrs, R.styleable.multi_line_radio_group,
                    0, 0);
            try {
                // gets and sets the max in row.
                setMaxInRow(typedArray.getInt(R.styleable.multi_line_radio_group_max_in_row,
                        DEF_VAL_MAX_IN_ROW));
    
                // gets and adds the starting buttons
                CharSequence[] radioButtonStrings = typedArray.getTextArray(
                        R.styleable.multi_line_radio_group_radio_buttons);
                addButtons(radioButtonStrings);
    
                // gets the default button and checks it if presents.
                String string = typedArray.getString(R.styleable.multi_line_radio_group_default_button);
                if (string != null)
                    setDefaultButton(string);
    
            } finally {
                typedArray.recycle();
            }
        }
    
        // checks the default button based on the passed string
        private void setDefaultButton(String string) {
            final int START_OF_INDEX = 6;
            final int START_OF_TEXT = 5;
    
            // the text of the button to check
            String buttonToCheck;
    
            if (string.startsWith(XML_DEFAULT_BUTTON_PREFIX_INDEX)) {
                String indexString = string.substring(START_OF_INDEX, string.length());
                int index = Integer.parseInt(indexString);
                if (index < 0 || index >= mRadioButtons.size())
                    throw new IllegalArgumentException("index must be between 0 to getRadioButtonCount() - 1 [" +
                            (getRadioButtonCount() - 1) + "]");
                buttonToCheck = mRadioButtons.get(index).getText().toString();
    
            } else if (string.startsWith(XML_DEFAULT_BUTTON_PREFIX_TEXT)) {
                buttonToCheck = string.substring(START_OF_TEXT, string.length());
    
            } else { // when there is no prefix assumes the string is the text of the button
                buttonToCheck = string;
            }
    
            check(buttonToCheck);
        }
    
        /**
         * Returns the table layout to set to this layout.
         *
         * @return the table layout
         */
        protected TableLayout getTableLayout() {
            return (TableLayout) LayoutInflater.from(getContext())
                    .inflate(R.layout.table_layout, this, false);
        }
    
        /**
         * Returns the table row to set in this layout.
         *
         * @return the table row
         */
        protected TableRow getTableRow() {
            return (TableRow) LayoutInflater.from(getContext())
                    .inflate(R.layout.table_row, mTableLayout, false);
        }
    
        /**
         * Returns the radio button to set in this layout.
         *
         * @return the radio button
         */
        protected RadioButton getRadioButton() {
            return (RadioButton) LayoutInflater.from(getContext())
                    .inflate(R.layout.radio_button, null);
        }
    
        /**
         * Register a callback to be invoked when a radio button is checked.
         *
         * @param onCheckedChangeListener the listener to attach
         */
        public void setOnCheckedChangeListener(OnCheckedChangeListener onCheckedChangeListener) {
            this.mOnCheckedChangeListener = onCheckedChangeListener;
        }
    
        /**
         * Sets the maximum radio buttons in a row, 0 for all in one line
         * and arranges the layout accordingly.
         *
         * @param maxInRow the maximum radio buttons in a row
         * @throws IllegalArgumentException if maxInRow is negative
         */
        public void setMaxInRow(int maxInRow) {
            if (maxInRow < 0)
                throw new IllegalArgumentException("maxInRow must not be negative");
            this.mMaxInRow = maxInRow;
            arrangeButtons();
        }
    
        /**
         * Adds a view to the layout
         * <p>
         * Consider using addButtons() instead
         *
         * @param child the view to add
         */
        @Override
        public void addView(View child) {
            addView(child, -1, child.getLayoutParams());
        }
    
        /**
         * Adds a view to the layout in the specified index
         * <p>
         * Consider using addButtons() instead
         *
         * @param child the view to add
         * @param index the index in which to insert the view
         */
        @Override
        public void addView(View child, int index) {
            addView(child, index, child.getLayoutParams());
        }
    
        /**
         * Adds a view to the layout with the specified width and height.
         * Note that for radio buttons the width and the height are ignored.
         * <p>
         * Consider using addButtons() instead
         *
         * @param child  the view to add
         * @param width  the width of the view
         * @param height the height of the view
         */
        @Override
        public void addView(View child, int width, int height) {
            addView(child, -1, new LinearLayout.LayoutParams(width, height));
        }
    
        /**
         * Adds a view to the layout with the specified layout params.
         * Note that for radio buttons the params are ignored.
         * <p>
         * Consider using addButtons() instead
         *
         * @param child  the view to add
         * @param params the layout params of the view
         */
        @Override
        public void addView(View child, ViewGroup.LayoutParams params) {
            addView(child, -1, params);
        }
    
        /**
         * Adds a view to the layout in the specified index
         * with the specified layout params.
         * Note that for radio buttons the params are ignored.
         * <p>
         * * Consider using addButtons() instead
         *
         * @param child  the view to add
         * @param index  the index in which to insert the view
         * @param params the layout params of the view
         */
        @Override
        public void addView(View child, int index, ViewGroup.LayoutParams params) {
            if (params == null) {
                params = new ViewGroup.LayoutParams(
                        ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
            }
    
            if (child instanceof RadioButton)
                addButtons(index, ((RadioButton) child).getText());
            else
                super.addView(child, index, params);
        }
    
        /**
         * Adds radio buttons to the layout based on the texts in the radioButtons array.
         * Adds them in the last index.
         * If radioButtons is null does nothing.
         *
         * @param radioButtons the texts of the buttons to add
         */
        public void addButtons(CharSequence... radioButtons) {
            addButtons(-1, radioButtons);
        }
    
        /**
         * Adds radio buttons to the layout based on the texts in the radioButtons array.
         * Adds them in the specified index, -1 for the last index.
         * If radioButtons is null does nothing.
         *
         * @param index        the index in which to insert the radio buttons
         * @param radioButtons the texts of the buttons to add
         * @throws IllegalArgumentException if index is less than -1 or greater than the number of radio buttons
         */
        public void addButtons(int index, CharSequence... radioButtons) {
            if (index < -1 || index > mRadioButtons.size())
                throw new IllegalArgumentException("index must be between -1 to getRadioButtonCount() [" +
                        getRadioButtonCount() + "]");
    
            if (radioButtons == null)
                return;
    
            int realIndex = (index != -1) ? index : mRadioButtons.size();
    
            // adds the buttons to the list
            for (CharSequence text : radioButtons)
                mRadioButtons.add(realIndex++, createRadioButton(text));
    
            arrangeButtons();
        }
    
        // creates a radio button with the specified text
        private RadioButton createRadioButton(CharSequence text) {
            RadioButton radioButton = getRadioButton();
            radioButton.setText(text);
            radioButton.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    checkButton((RadioButton) v);
    
                    if (mOnCheckedChangeListener != null)
                        mOnCheckedChangeListener.onCheckedChanged(MultiLineRadioGroup.this, checkedButton);
                }
            });
            return radioButton;
        }
    
        /**
         * Removes a view from the layout.
         * <p>
         * Consider using removeButton().
         *
         * @param view the view to remove
         */
        @Override
        public void removeView(View view) {
            super.removeView(view);
        }
    
        /**
         * Removes a view from the layout in the specified index.
         * <p>
         * Consider using removeButton().
         *
         * @param index the index from which to remove the view
         */
        @Override
        public void removeViewAt(int index) {
            super.removeViewAt(index);
        }
    
        /**
         * Removes the specified range of views from the layout.
         * <p>
         * Consider using removeButtons().
         *
         * @param start the start index to remove
         * @param count the number of views to remove
         */
        @Override
        public void removeViews(int start, int count) {
            super.removeViews(start, count);
        }
    
        /**
         * Removes all the views from the layout.
         * <p>
         * Consider using removeAllButtons().
         */
        @Override
        public void removeAllViews() {
            super.removeAllViews();
        }
    
        /**
         * Removes a radio button from the layout.
         * If the radio button is null does nothing.
         *
         * @param radioButton the radio button to remove
         */
        public void removeButton(RadioButton radioButton) {
            if (radioButton == null)
                return;
    
            removeButton(radioButton.getText());
        }
    
        /**
         * Removes a radio button from the layout based on its text.
         * Removes the first occurrence.
         * If the text is null does nothing.
         *
         * @param text the text of the radio button to remove
         */
        public void removeButton(CharSequence text) {
            if (text == null)
                return;
    
            int index = -1;
    
            for (int i = 0, len = mRadioButtons.size(); i < len; i++) {
                // checks if the texts are equal
                if (mRadioButtons.get(i).getText().equals(text)) {
                    index = i;
                    break;
                }
            }
    
            // removes just if the index was found
            if (index != -1)
                removeButton(index);
        }
    
        /**
         * Removes the radio button in the specified index from the layout.
         *
         * @param index the index from which to remove the radio button
         * @throws IllegalArgumentException if index is less than 0
         *                                  or greater than the number of radio buttons - 1
         */
        public void removeButton(int index) {
            removeButtons(index, 1);
        }
    
        /**
         * Removes all the radio buttons in the specified range from the layout.
         * Count can be any non-negative number.
         *
         * @param start the start index to remove
         * @param count the number of radio buttons to remove
         * @throws IllegalArgumentException if index is less than 0
         *                                  or greater than the number of radio buttons - 1
         *                                  or count is negative
         */
        public void removeButtons(int start, int count) {
            if (start < 0 || start >= mRadioButtons.size())
                throw new IllegalArgumentException("remove index must be between 0 to getRadioButtonCount() - 1 [" +
                        (getRadioButtonCount() - 1) + "]");
    
            if (count < 0)
                throw new IllegalArgumentException("count must not be negative");
    
            if (count == 0)
                return;
    
            int endIndex = start + count - 1;
            // if endIndex is not in the range of the radio buttons sets it to the last index
            if (endIndex >= mRadioButtons.size())
                endIndex = mRadioButtons.size() - 1;
    
            // iterates over the buttons to remove
            for (int i = endIndex; i >= start; i--) {
                RadioButton radiobutton = mRadioButtons.get(i);
                // if the button to remove is the checked button set checkedButton to null
                if (radiobutton == checkedButton)
                    checkedButton = null;
                // removes the button from the list
                mRadioButtons.remove(i);
            }
    
            arrangeButtons();
        }
    
        /**
         * Removes all the radio buttons from the layout.
         */
        public void removeAllButtons() {
            removeButtons(0, mRadioButtons.size());
        }
    
        // arrange the button in the layout
        private void arrangeButtons() {
            // iterates over each button and puts it in the right place
            for (int i = 0, len = mRadioButtons.size(); i < len; i++) {
                RadioButton radioButtonToPlace = mRadioButtons.get(i);
                int rowToInsert = (mMaxInRow != 0) ? i / mMaxInRow : 0;
                int columnToInsert = (mMaxInRow != 0) ? i % mMaxInRow : i;
                // gets the row to insert. if there is no row create one
                TableRow tableRowToInsert = (mTableLayout.getChildCount() <= rowToInsert)
                        ? addTableRow() : (TableRow) mTableLayout.getChildAt(rowToInsert);
                int tableRowChildCount = tableRowToInsert.getChildCount();
    
                // if there is already a button in the position
                if (tableRowChildCount > columnToInsert) {
                    RadioButton currentButton = (RadioButton) tableRowToInsert.getChildAt(columnToInsert);
    
                    // insert the button just if the current button is different
                    if (currentButton != radioButtonToPlace) {
                        // removes the current button
                        removeButtonFromParent(currentButton, tableRowToInsert);
                        // removes the button to place from its current position
                        removeButtonFromParent(radioButtonToPlace, (ViewGroup) radioButtonToPlace.getParent());
                        // adds the button to the right place
                        tableRowToInsert.addView(radioButtonToPlace, columnToInsert);
                    }
    
                    // if there isn't already a button in the position
                } else {
                    // removes the button to place from its current position
                    removeButtonFromParent(radioButtonToPlace, (ViewGroup) radioButtonToPlace.getParent());
                    // adds the button to the right place
                    tableRowToInsert.addView(radioButtonToPlace, columnToInsert);
                }
            }
    
            removeRedundancies();
        }
    
        // removes the redundant rows and radio buttons
        private void removeRedundancies() {
            // the number of rows to fit the buttons
            int rows;
            if (mRadioButtons.size() == 0)
                rows = 0;
            else if (mMaxInRow == 0)
                rows = 1;
            else
                rows = (mRadioButtons.size() - 1) / mMaxInRow + 1;
    
            int tableChildCount = mTableLayout.getChildCount();
            // if there are redundant rows remove them
            if (tableChildCount > rows)
                mTableLayout.removeViews(rows, tableChildCount - rows);
    
            tableChildCount = mTableLayout.getChildCount();
            int maxInRow = (mMaxInRow != 0) ? mMaxInRow : mRadioButtons.size();
    
            // iterates over the rows
            for (int i = 0; i < tableChildCount; i++) {
                TableRow tableRow = (TableRow) mTableLayout.getChildAt(i);
                int tableRowChildCount = tableRow.getChildCount();
    
                int startIndexToRemove;
                int count;
    
                // if it is the last row removes all redundancies after the last button in the list
                if (i == tableChildCount - 1) {
                    startIndexToRemove = (mRadioButtons.size() - 1) % maxInRow + 1;
                    count = tableRowChildCount - startIndexToRemove;
    
                    // if it is not the last row removes all the buttons after maxInRow position
                } else {
                    startIndexToRemove = maxInRow;
                    count = tableRowChildCount - maxInRow;
                }
    
                if (count > 0)
                    tableRow.removeViews(startIndexToRemove, count);
            }
        }
    
        // adds and returns a table row
        private TableRow addTableRow() {
            TableRow tableRow = getTableRow();
            mTableLayout.addView(tableRow);
            return tableRow;
        }
    
        // removes a radio button from a parent
        private void removeButtonFromParent(RadioButton radioButton, ViewGroup parent) {
            if (radioButton == null || parent == null)
                return;
    
            parent.removeView(radioButton);
        }
    
        /**
         * Returns the number of radio buttons.
         *
         * @return the number of radio buttons
         */
        public int getRadioButtonCount() {
            return mRadioButtons.size();
        }
    
        /**
         * Returns the radio button in the specified index.
         * If the index is out of range returns null.
         *
         * @param index the index of the radio button
         * @return the radio button
         */
        public RadioButton getRadioButtonAt(int index) {
            if (index < 0 || index >= mRadioButtons.size())
                return null;
    
            return mRadioButtons.get(index);
        }
    
        /**
         * Checks the radio button with the specified id.
         * If the specified id is not found does nothing.
         *
         * @param id the radio button's id
         */
        @Override
        public void check(int id) {
            if (id <= 0)
                return;
    
            for (RadioButton radioButton : mRadioButtons) {
                if (radioButton.getId() == id) {
                    checkButton(radioButton);
                    return;
                }
            }
        }
    
        /**
         * Checks the radio button with the specified text.
         * If there is more than one radio button associated with this text
         * checks the first radio button.
         * If the specified text is not found does nothing.
         *
         * @param text the radio button's text
         */
        public void check(CharSequence text) {
            if (text == null)
                return;
    
            for (RadioButton radioButton : mRadioButtons) {
                if (radioButton.getText().equals(text)) {
                    checkButton(radioButton);
                    return;
                }
            }
        }
    
        /**
         * Checks the radio button at the specified index.
         * If the specified index is invalid does nothing.
         *
         * @param index the radio button's index
         */
        public void checkAt(int index) {
            if (index < 0 || index >= mRadioButtons.size())
                return;
    
            checkButton(mRadioButtons.get(index));
        }
    
        // checks and switches the button with the checkedButton
        private void checkButton(RadioButton button) {
            if (button == null)
                return;
    
            // if the button to check is different from the current checked button
            if (button != checkedButton) {
    
                // if exists sets checkedButton to null
                if (checkedButton != null)
                    checkedButton.setChecked(false);
    
                button.setChecked(true);
                checkedButton = button;
            }
        }
    
        /**
         * Clears the checked radio button
         */
        @Override
        public void clearCheck() {
            checkedButton.setChecked(false);
            checkedButton = null;
        }
    
        /**
         * Returns the checked radio button's id.
         * If no radio buttons are checked returns -1.
         *
         * @return the checked radio button's id
         */
        @Override
        public int getCheckedRadioButtonId() {
            if (checkedButton == null)
                return -1;
    
            return checkedButton.getId();
        }
    
        /**
         * Returns the checked radio button's index.
         * If no radio buttons are checked returns -1.
         *
         * @return the checked radio button's index
         */
        public int getCheckedRadioButtonIndex() {
            if (checkedButton == null)
                return -1;
    
            return mRadioButtons.indexOf(checkedButton);
        }
    
        /**
         * Returns the checked radio button's text.
         * If no radio buttons are checked returns null.
         *
         * @return the checked radio buttons's text
         */
        public CharSequence getCheckedRadioButtonText() {
            if (checkedButton == null)
                return null;
    
            return checkedButton.getText();
        }
    
        /**
         * Interface definition for a callback to be invoked when a radio button is checked.
         */
        public interface OnCheckedChangeListener {
            /**
             * Called when a radio button is checked.
             *
             * @param group  the MultiLineRadioGroup that stores the radio button
             * @param button the radio button that was checked
             */
            void onCheckedChanged(MultiLineRadioGroup group, RadioButton button);
        }
    }
    
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="multi_line_radio_group">
            <attr name="max_in_row" format="integer" />
            <attr name="radio_buttons" format="reference" />
            <attr name="default_button" format="string" />
        </declare-styleable>
    </resources>
    
    <?xml version="1.0" encoding="utf-8"?>
    <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/table_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:stretchColumns="*" />
    
    <?xml version="1.0" encoding="utf-8"?>
    <TableRow xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/table_row"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    
    <?xml version="1.0" encoding="utf-8"?>
    <RadioButton xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/radio_button"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:textSize="@dimen/radio_button_text_size" />
    
    <?xml version="1.0" encoding="utf-8"?>
    <[package].MultiLineRadioGroup xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:multi_line_radio_group="http://schemas.android.com/apk/res-auto"
        android:id="@+id/multi_line_radio_group"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        multi_line_radio_group:default_button="@string/defaultText"
        multi_line_radio_group:max_in_row="@integer/radio_button_max_in_row"
        multi_line_radio_group:radio_buttons="@array/radio_buttons" />
    
    public class AdvRadioGroup {
        public interface OnButtonCheckedListener {
            void onButtonChecked(CompoundButton button);
        }
    
        private final List<CompoundButton> buttons;
        private final View.OnClickListener onClick = new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                setChecked((CompoundButton) v);
            }
        };
    
        private OnButtonCheckedListener listener;
        private CompoundButton lastChecked;
    
    
        public AdvRadioGroup(View view) {
            buttons = new ArrayList<>();
            parseView(view);
        }
    
        private void parseView(final View view) {
            if(view instanceof CompoundButton) {
                buttons.add((CompoundButton) view);
                view.setOnClickListener(onClick);
            } else if(view instanceof ViewGroup) {
                final ViewGroup group = (ViewGroup) view;
                for (int i = 0; i < group.getChildCount();i++) {
                    parseView(group.getChildAt(i));
                }
            }
        }
    
        public List<CompoundButton> getButtons() { return buttons; }
    
        public CompoundButton getLastChecked() { return lastChecked; }
    
        public void setChecked(int index) { setChecked(buttons.get(index)); }
    
        public void setChecked(CompoundButton button) {
            if(button == lastChecked) return;
    
            for (CompoundButton btn : buttons) {
                btn.setChecked(false);
            }
    
            button.setChecked(true);
    
            lastChecked = button;
    
            if(listener != null) {
                listener.onButtonChecked(button);
            }
        }
    
        public void setOnButtonCheckedListener(OnButtonCheckedListener listener) { this.listener = listener; }
    }
    
    AdvRadioGroup group = new AdvRadioGroup(findViewById(R.id.YOUR_VIEW));
    group.setOnButtonCheckedListener(new AdvRadioGroup.OnButtonCheckedListener() {
        @Override
        public void onButtonChecked(CompoundButton button) {
            // do fun stuff here!
        }
    });
    
    <resources>
        <declare-styleable name="RadioGridLayout">
            <attr name="checked" format="integer" />
        </declare-styleable>
    </resources>
    
    public class RadioGridLayout extends GridLayout {
    
        private int mCheckedId = -1;
        private CompoundButton.OnCheckedChangeListener mChildOnCheckedChangeListener;
        private boolean mProtectFromCheckedChange = false;
        private OnCheckedChangeListener mOnCheckedChangeListener;
        private PassThroughHierarchyChangeListener mPassThroughListener;
    
        private void setCheckedId(@IdRes int id) {
            mCheckedId = id;
            if (mOnCheckedChangeListener != null) {
                mOnCheckedChangeListener.onCheckedChanged(this, mCheckedId);
            }
            AutofillManager afm = null;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                afm = getContext().getSystemService(AutofillManager.class);
            }
            if (afm != null) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    afm.notifyValueChanged(this);
                }
            }
        }
    
        public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
            mOnCheckedChangeListener = listener;
        }
    
        public interface OnCheckedChangeListener {
            void onCheckedChanged(RadioGridLayout group, @IdRes int checkedId);
        }
    
        private int mInitialCheckedId = View.NO_ID;
    
        public RadioGridLayout(Context context) {
            super(context);
            setOrientation(VERTICAL);
            init();
        }
    
        public RadioGridLayout(Context context, AttributeSet attrs) {
            super(context, attrs);
    
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                if (getImportantForAutofill() == IMPORTANT_FOR_AUTOFILL_AUTO) {
                    setImportantForAutofill(IMPORTANT_FOR_AUTOFILL_YES);
                }
            }
    
            TypedArray attributes = context.obtainStyledAttributes(
                    attrs,
                    R.styleable.RadioGridLayout,
                    R.attr.radioButtonStyle, 0);
    
            int value = attributes.getResourceId(R.styleable.RadioGridLayout_checked, View.NO_ID);
            if (value != View.NO_ID) {
                mCheckedId = value;
                mInitialCheckedId = value;
            }
    
            attributes.recycle();
            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(View child, int index, ViewGroup.LayoutParams params) {
            if (child instanceof RadioButton) {
                final RadioButton button = (RadioButton) 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(@IdRes int id) {
            if (id != -1 && (id == mCheckedId)) {
                return;
            }
    
            if (mCheckedId != -1) {
                setCheckedStateForView(mCheckedId, false);
            }
    
            if (id != -1) {
                setCheckedStateForView(id, true);
            }
    
            setCheckedId(id);
        }
    
        private void setCheckedStateForView(int viewId, boolean checked) {
            View checkedView = findViewById(viewId);
            if (checkedView != null && checkedView instanceof RadioButton) {
                ((RadioButton) checkedView).setChecked(checked);
            }
        }
    
        @IdRes
        public int getCheckedRadioButtonId() {
            return mCheckedId;
        }
    
        public void clearCheck() {
            check(-1);
        }
    
        @Override
        public GridLayout.LayoutParams generateLayoutParams(AttributeSet attrs) {
            return new GridLayout.LayoutParams(getContext(), attrs);
        }
    
        @Override
        protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
            return p instanceof RadioGroup.LayoutParams;
        }
    
        @Override
        protected GridLayout.LayoutParams generateDefaultLayoutParams() {
            return new LayoutParams();
        }
    
        @Override
        public CharSequence getAccessibilityClassName() {
            return RadioGroup.class.getName();
        }
    
        public static class LayoutParams extends GridLayout.LayoutParams {
    
            public LayoutParams(Spec rowSpec, Spec columnSpec) {
                super(rowSpec, columnSpec);
            }
    
            public LayoutParams() {
                super();
            }
    
            public LayoutParams(ViewGroup.LayoutParams params) {
                super(params);
            }
    
            public LayoutParams(MarginLayoutParams params) {
                super(params);
            }
    
            public LayoutParams(GridLayout.LayoutParams source) {
                super(source);
            }
    
            public LayoutParams(Context context, AttributeSet attrs) {
                super(context, attrs);
            }
    
            @Override
            protected void setBaseAttributes(TypedArray a,
                                             int widthAttr, int heightAttr) {
    
                if (a.hasValue(widthAttr)) {
                    width = a.getLayoutDimension(widthAttr, "layout_width");
                } else {
                    width = WRAP_CONTENT;
                }
    
                if (a.hasValue(heightAttr)) {
                    height = a.getLayoutDimension(heightAttr, "layout_height");
                } else {
                    height = WRAP_CONTENT;
                }
            }
        }
    
        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;
    
            @Override
            public void onChildViewAdded(View parent, View child) {
                if (parent == RadioGridLayout.this && child instanceof RadioButton) {
                    int id = child.getId();
                    if (id == View.NO_ID) {
                        id = View.generateViewId();
                        child.setId(id);
                    }
                    ((RadioButton) child).setOnCheckedChangeListener(
                            mChildOnCheckedChangeListener);
                }
    
                if (mOnHierarchyChangeListener != null) {
                    mOnHierarchyChangeListener.onChildViewAdded(parent, child);
                }
            }
    
            @Override
            public void onChildViewRemoved(View parent, View child) {
                if (parent == RadioGridLayout.this && child instanceof RadioButton) {
                    ((RadioButton) child).setOnCheckedChangeListener(null);
                }
    
                if (mOnHierarchyChangeListener != null) {
                    mOnHierarchyChangeListener.onChildViewRemoved(parent, child);
                }
            }
        }
    
        @Override
        public void onProvideAutofillStructure(ViewStructure structure, int flags) {
            super.onProvideAutofillStructure(structure, flags);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                structure.setDataIsSensitive(mCheckedId != mInitialCheckedId);
            }
        }
    
        @Override
        public void autofill(AutofillValue value) {
            if (!isEnabled()) return;
    
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                if (!value.isList()) {
                    Timber.w(value + " could not be autofilled into " + this);
                    return;
                }
            }
    
            int index = 0;
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
                index = value.getListValue();
            }
            final View child = getChildAt(index);
            if (child == null) {
                Timber.w("RadioGroup.autoFill(): no child with index %s", index);
                return;
            }
    
            check(child.getId());
        }
    
        @Override
        public int getAutofillType() {
            return isEnabled() ? AUTOFILL_TYPE_LIST : AUTOFILL_TYPE_NONE;
        }
    
        @Override
        public AutofillValue getAutofillValue() {
            if (!isEnabled()) return null;
    
            final int count = getChildCount();
            for (int i = 0; i < count; i++) {
                final View child = getChildAt(i);
                if (child.getId() == mCheckedId) {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                        return AutofillValue.forList(i);
                    }
                }
            }
            return null;
        }
    }
    
      <RadioGroup
                    android:id="@+id/radioGroup"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="2dp">
    
                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:orientation="horizontal">
    
                    <RadioButton
                        android:id="@+id/radioOwner"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:buttonTint="@color/login_button_color"
                        android:fontFamily="@font/rnhousesans_regular"
                        android:text="Owner"
                        android:textColor="@color/colorPrimary" />
    
                    <RadioButton
                        android:id="@+id/radioLivingParents"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:buttonTint="@color/login_button_color"
                        android:fontFamily="@font/rnhousesans_regular"
                        android:text="Living with parents"
                        android:textColor="@color/colorPrimary" />
    
                    </LinearLayout>
    
                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:orientation="horizontal">
    
                    <RadioButton
                        android:id="@+id/radioTenant"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:buttonTint="@color/login_button_color"
                        android:fontFamily="@font/rnhousesans_regular"
                        android:text="Tenant"
                        android:textColor="@color/colorPrimary" />
    
                    <RadioButton
                        android:id="@+id/radioOther"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:buttonTint="@color/login_button_color"
                        android:fontFamily="@font/rnhousesans_regular"
                        android:text="Other"
                        android:textColor="@color/colorPrimary" />
    
                    </LinearLayout>
                </RadioGroup>
    
    <RadioGroup
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        >
    
        <GridLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:columnCount="2"
            >
    
        <androidx.appcompat.widget.AppCompatRadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Text 1"
            />
    
        <androidx.appcompat.widget.AppCompatRadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Text 2"
            />
    
        <androidx.appcompat.widget.AppCompatRadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Text 3"
            />
    
        <androidx.appcompat.widget.AppCompatRadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Text 4"
            />
    
        <androidx.appcompat.widget.AppCompatRadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Text 5"
            />
    
        </GridLayout>
    </RadioGroup>
    
                 <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:orientation="horizontal"
                            android:weightSum="2">
    
                            <RadioGroup
                                android:id="@+id/radioGroup_action_1"
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_marginStart="16dp"
                                android:layout_marginTop="16dp"
                                android:layout_marginEnd="16dp"
                                android:layout_marginBottom="16dp"
                                android:layout_weight="1"
                                android:orientation="vertical">
    
                                <RadioButton
                                    android:id="@+id/radio_a"
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:text="@string/a"
                                    android:textColor="@color/textColor"
                                     />
    
                                <RadioButton
                                    android:id="@+id/radio_b"
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:text="@string/b"
                                    android:textColor="@color/textColor" />
    
    
                                <RadioButton
                                    android:id="@+id/radio_c"
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:text="@string/c"
                                    android:textColor="@color/textColor" />
                            </RadioGroup>
    
                            <RadioGroup
                                android:id="@+id/radioGroup_action_2"
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_marginStart="16dp"
                                android:layout_marginTop="16dp"
                                android:layout_marginEnd="16dp"
                                android:layout_marginBottom="16dp"
                                android:layout_weight="1"
                                android:orientation="vertical">
    
                                <RadioButton
                                    android:id="@+id/radio_d"
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:checked="true"
                                    android:text="@string/d"
                                    android:textColor="@color/textColor" />
    
                                <RadioButton
                                    android:id="@+id/radio_e"
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:text="@string/e"
                                    android:textColor="@color/textColor" />
    
                                <RadioButton
                                    android:id="@+id/f"
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:text="@string/f"
                                    android:textColor="@color/textColor" />
    
                            </RadioGroup>
                        </LinearLayout>
    
     private var isChecking = true
    
     mBinding.radioGroupAction1.setOnCheckedChangeListener { radioGroup, i ->
            if (i != -1 && isChecking) {
                isChecking = false
                mBinding.radioGroupAction2.clearCheck()
            }
            isChecking = true
            when (i) {
                R.id.a -> {
                   Log.e("radioGroupAction:", "a")
                }
                R.id.b -> {
                   Log.e("radioGroupAction:", "b")
                }
                R.id.c -> {
                   Log.e("radioGroupAction:", "c")
                }
            }
        }
        mBinding.radioGroupAction2.setOnCheckedChangeListener { radioGroup, i ->
            if (i != -1 && isChecking) {
                isChecking = false
                mBinding.radioGroupAction1.clearCheck()
            }
            isChecking = true
            when (i) {
                R.id.d -> {
                   Log.e("radioGroupAction:", "d")
                }
                R.id.e -> {
                   Log.e("radioGroupAction:", "e")
                }
                R.id.f -> {
                   Log.e("radioGroupAction:", "f")
                }
            }
        }