Как сгруппировать 3x3 сетку радиокнопок? - PullRequest
32 голосов
/ 04 марта 2010

Как следует из названия, я пытаюсь сгруппировать сетку из 3x3 радиокнопок в одну радиогруппу. В предыдущем заданном вопросе я узнал, что для того, чтобы переключатели соответствовали одной группе, они должны быть непосредственными детьми группы радио, которой они будут соответствовать. Я научился этому нелегко, когда попытался инкапсулировать весь макет таблицы (с переключателями в строках таблицы) в группу радиостанций.

Вбежав в эту стену, я попробовал следующее:

<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>

Очевидно, я не учился в первый раз, потому что снова столкнулся со стеной. Я надеялся, что переключатели в разных строках таблицы заметят, что они являются частью одной и той же группы радиостанций (дали каждой группе один и тот же идентификатор), но это не сработало.

Можно ли как-нибудь сгруппировать все эти кнопки в одну радиогруппу и при этом сохранить структуру 3х3 (3 строки, 3 радиокнопки в каждой строке)?

Ответы [ 8 ]

65 голосов
/ 05 марта 2010

На самом деле это не так сложно, если вы подкласс TableLayout, как в этом примере

/**
 * 
 */
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;
    }
}

и создайте макет как этот (конечно, вы должны очистить его, но у вас есть идея)

<?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>
8 голосов
/ 19 ноября 2015

После ответа выше https://stackoverflow.com/a/2383978/5567009 Я получил другое решение для этого вопроса, я добавил некоторые другие функции, такие как, чтобы сохранить состояние группы, а также функцию, чтобы очистить функцию проверки, как в радиогруппе.

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];
                    }
                };
    }
}

и использовать это в XML следующим образом

<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>

Для любых других улучшений, пожалуйста, прокомментируйте.

3 голосов
/ 04 марта 2010

Ваш единственный вариант - захватить исходный код до RadioGroup и попытаться скопировать его функциональность в TableLayout или что-то еще. В противном случае невозможно создать сетку 3x3 RadioButtons. К счастью, класс RadioButton не знает о RadioGroup - вся логика взаимоисключения находится в RadioGroup. Следовательно, должно быть возможно создать RadioGrid или что-то ... но это будет очень много работы.

2 голосов
/ 29 марта 2019

Я написал очень простой GridLayout подкласс, который действует как RadioGroup. Вот как это выглядит:

GridLayout RadioGroup with RadioButton

Чтобы использовать его, сначала добавьте библиотеку GridLayout:

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

Затем скопируйте и вставьте подкласс GridLayout:

**
 * A GridLayout subclass that acts like a RadioGroup. Important: it only accepts RadioButton as children.
 * Inspired by https://stackoverflow.com/a/2383978/4034572
 */
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)
    }

}

Наконец, просто используйте его:

<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>

Стиль:

<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>

Код прост, но у меня работает нормально. Если вы хотите что-то более complete (например, с OnCheckedChangeListener), тогда проверьте эту альтернативную реализацию , которая явно более сложна и на уровне функций с RadioGroup.

2 голосов
/ 24 апреля 2011

Радиогруппа расширяется следующим образом.

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

Если вам нужно расположить переключатель в макете сетки, вам может потребоваться создать собственный код, который расширяется от GridLayout.

0 голосов
/ 30 августа 2018

При этом используется пользовательский GridLayout с функциональностью RadioGroup.Спасибо Сайкришнану Ранганатану за 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>
0 голосов
/ 29 января 2018

Я бы, например, пошел на вложенные радиогруппы.Корневая радиогруппа будет иметь вертикальную ориентацию, а ее дочерние элементы будут тремя радиогруппами с горизонтальной ориентацией.

<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>

Каждая из дочерних радиогрупп будет иметь идентификатор, который будет вызываться объектом RadioGroup внутри метода проверки Java.,Например:

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);

Теперь, просто используя clearCheck() внутри корпуса коммутатора, вы можете отменить проверку двух других радиогрупп.Как это:

case R.id.radioButton_1:
            if (checked) {
                rg_2.clearCheck();
                rg_3.clearCheck();
            }
            break;
0 голосов
/ 09 июля 2014

Это клочок, но почему бы и нет Почему бы просто не использовать девять радиогрупп или три горизонтальные радиогруппы, каждая с тремя кнопками.Затем каждая радиогруппа может быть выровнена с помощью gridView, илиlativeLayout и т.д.1004 * Затем при нажатии любой кнопки RadioButton вы можете использовать группы радиосвязи для отмены выбора радиокнопок.Затем программно выберите переключатель, который был нажат.

Это ужасное решение, но оно работает так, как можно было бы надеяться.

Ниже приведен пример кода, который я использовал для этого с макетом кнопок 2x2.

  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);

    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...