Làm cách nào để nhóm RadioButton từ các LinearLayouts khác nhau?


93

Tôi đã tự hỏi liệu có thể nhóm từng đĩa đơn RadioButtontrong một duy nhất RadioGroup duy trì cùng một cấu trúc. Cấu trúc của tôi trông như thế này:

  • LinearLayout_main
    • LinearLayout_1
      • RadioButton1
    • LinearLayout_2
      • RadioButton2
    • LinearLayout_3
      • RadioButton3

Như bạn có thể thấy, bây giờ mỗi người RadioButtonlà một đứa trẻ khác nhau LinearLayout. Tôi đã thử sử dụng cấu trúc bên dưới, nhưng nó không hoạt động:

  • Nhóm phóng xạ
    • LinearLayout_main
      • LinearLayout_1
        • RadioButton1
      • LinearLayout_2
        • RadioButton2
      • LinearLayout_3
        • RadioButton3

13
@coding crow, nếu bạn buộc phải hỏi thì bạn chưa bao giờ làm việc với một nhà thiết kế cho luồng giao diện người dùng (và tôi đoán các nút radio của bạn có thể không phức tạp lắm). Hãy tưởng tượng (nếu bạn có thể) một nút radio nằm bên cạnh hai đoạn văn bản, một đoạn là tiêu đề và một đoạn là văn bản phụ. Bây giờ hãy tưởng tượng 5 trong số này chồng lên nhau. Làm thế nào để bạn đạt được điều đó? Ah đúng ... bạn không thể. Thật tốt là không cần thiết phải có gì quá lạ mắt nếu không google sẽ thực sự trông thật ngu ngốc khi bỏ qua chức năng bố cục cơ bản như vậy trong bộ công cụ bố cục toàn diện của họ.
Yevgeny Simkin

3
@ Dr.Dredel wow, mặc dù tôi đồng ý với những gì bạn nói (cách sử dụng radioButtons), nhưng có lẽ phản ứng của bạn quá xúc động? :)
infografnet

14
Nó không phải là cảm xúc quá rõ ràng là khó chịu. Nhận xét đó mang lại điều gì cho OP? Nó cung cấp những gì cho chủ đề nói chung? Nó ngụ ý rằng câu hỏi là không có giá trị và thiếu kiên nhẫn và khó tính. Nếu anh ấy bắt đầu bằng câu "Bạn có thể vui lòng giải thích lý do tại sao bạn muốn làm điều này không" sẽ vừa phù hợp vừa lịch sự. "Tôi buộc phải hỏi" là một lựa chọn thay thế được che đậy mỏng manh cho "loại thằng ngốc nào sẽ cần con kluge lập dị này?". Ít nhất đó là cách tôi đọc nó.
Yevgeny Simkin

1
Tại sao android dev vẫn không cho phép sử dụng LinearLayout bên trong RadioGroup? Marshmallow đã được phát hành.
Shan Xeeshi

1
Vẫn không có câu trả lời thích hợp? Tôi đang tìm kiếm một giải pháp
neena

Câu trả lời:


49

Có vẻ như những người giỏi tại Google / Android cho rằng khi bạn sử dụng RadioButtons, bạn không cần sự linh hoạt đi kèm với mọi khía cạnh khác của hệ thống bố cục / giao diện người dùng Android. Nói một cách đơn giản: họ không muốn bạn lồng ghép các bố cục và nút radio. Thở dài.

Vì vậy, bạn phải giải quyết vấn đề. Điều đó có nghĩa là bạn phải tự triển khai các nút radio.

Điều này thực sự không quá khó. Trong onCreate () của bạn, đặt RadioButtons của bạn với onClick () của riêng chúng để khi chúng được kích hoạt, chúng sẽ setChecked (true) và làm ngược lại với các nút khác. Ví dụ:

class FooActivity {

    RadioButton m_one, m_two, m_three;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        m_one = (RadioButton) findViewById(R.id.first_radio_button);
        m_two = (RadioButton) findViewById(R.id.second_radio_button);
        m_three = (RadioButton) findViewById(R.id.third_radio_button);

        m_one.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                m_one.setChecked(true);
                m_two.setChecked(false);
                m_three.setChecked(false);
            }
        });

        m_two.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                m_one.setChecked(false);
                m_two.setChecked(true);
                m_three.setChecked(false);
            }
        });

        m_three.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                m_one.setChecked(false);
                m_two.setChecked(false);
                m_three.setChecked(true);
            }
        });

        ...     
    } // onCreate() 

}

Vâng, tôi biết - theo cách cũ. Nhưng nó đã có tác dụng. Chúc may mắn!


33
tức giận. đơn giản là không thể tin được rằng đây là mức klugery cần thiết để làm một cái gì đó trần tục như một "nút radio". Thật không thể tin được rằng Google giao cho chúng tôi rất nhiều đường tắt cho những thứ gần như hoàn toàn vô dụng (như 80% tiện ích Hoạt hình) và sau đó để chúng tôi tập hợp các nút radio của riêng mình. (khạc nhổ!).
Yevgeny Simkin

3
@ Dr.Dredel: Vâng, tôi đồng ý rằng rất nhiều lựa chọn giao diện người dùng của họ thật kỳ lạ. Dự đoán duy nhất của tôi về hạn chế này là họ có thể đang nghĩ, "Thực sự không khó để làm điều đó theo cách thủ công." Nhưng sẽ thật tuyệt nếu họ ghi lại sự thiếu tính năng này ít nhất một chút (như một trang hướng dẫn?). Như bạn đã chỉ ra, họ đã đi quá đà vào những thứ gần như vô dụng khác (có lẽ là dự án thú cưng?).
SMBiggs

3
Tôi chỉ có thể đoán, nhưng ấn tượng chung của tôi là đội ngũ giao diện người dùng của Android có một chút hạn chế hoặc nhìn chung là khá yếu. Hãy xem xét những gì vượt qua cho "thanh lịch" trong vũ trụ google. Tất cả đều thực sự cầu kỳ và thực dụng. Tôi không phải là fan của Apple vì tôi thích chức năng hơn kiểu dáng, nhưng nếu có khi nào một công ty lớn với lượng tiền mặt cần thiết để xem xét lại giao diện của nó (lên và xuống chuỗi), tôi không thể nghĩ ra một ứng cử viên nào tốt hơn Google.
Yevgeny Simkin

1
Cho đến nay, đây là một trong những giải pháp đáng tin cậy và đơn giản nhất ... mặc dù có từ thời tiền sử, thật tiếc là Google đã không triển khai một thứ gì đó hiệu quả hơn ...
TV

3
Vâng .. Tôi đã mong đợi điều gì đó như gán thủ công ID nút radio cho RadioGroup hoặc điều gì đó sẽ tồn tại nếu việc duyệt tự động trên các nhóm chế độ xem bổ sung không chứa nút radio trong nhóm radio đó rất tốn kém .. Tôi rất chắc chắn một điều gì đó như cái này tồn tại nên tôi bắt đầu tìm kiếm. Bây giờ tôi rời khỏi bài viết này trong tuyệt vọng.
Dreamingwhale

27

Sử dụng lớp này mà tôi đã tạo. Nó sẽ tìm thấy tất cả trẻ em có thể kiểm tra trong hệ thống phân cấp của bạn.

import java.util.ArrayList;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Checkable;
import android.widget.LinearLayout;

public class MyRadioGroup extends LinearLayout {

private ArrayList<View> mCheckables = new ArrayList<View>();

public MyRadioGroup(Context context) {
    super(context);
}

public MyRadioGroup(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}

public MyRadioGroup(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}

@Override
public void addView(View child, int index,
        android.view.ViewGroup.LayoutParams params) {
    super.addView(child, index, params);
    parseChild(child);
}

public void parseChild(final View child)
{
    if(child instanceof Checkable)
    {
        mCheckables.add(child);
        child.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {
                for(int i = 0; i < mCheckables.size();i++)
                {
                    Checkable view = (Checkable) mCheckables.get(i);
                    if(view == v)
                    {
                        ((Checkable)view).setChecked(true);
                    }
                    else
                    {
                        ((Checkable)view).setChecked(false);
                    }
                }
            }
        });
    }
    else if(child instanceof ViewGroup)
    {
        parseChildren((ViewGroup)child);
    }
}

public void parseChildren(final ViewGroup child)
{
    for (int i = 0; i < child.getChildCount();i++)
    {
        parseChild(child.getChildAt(i));
    }
}
}

được cung cấp mã này, làm cách nào tôi có được nút đã chọn hiện tại?
j2emanue

tôi chỉ đặt một biến mCheckedview khi bạn đặt chế độ xem ((Có thể kiểm tra)) .setChecked (true); và tôi trả về biến đó khi tôi cần biết biến nào đã được kiểm tra. Bây giờ có vẻ ổn nhưng phải "performanceClick ()" trên mặc định mà tôi muốn. cảm ơn
j2emanue

17

Vâng, tôi đã viết lớp học đơn giản này.

Chỉ cần sử dụng nó như thế này:

// add any number of RadioButton resource IDs here
GRadioGroup gr = new GRadioGroup(this, 
    R.id.radioButton1, R.id.radioButton2, R.id.radioButton3);

hoặc là

GRadioGroup gr = new GRadioGroup(rb1, rb2, rb3);
// where RadioButton rb1 = (RadioButton) findViewById(R.id.radioButton1);
// etc.

Bạn có thể gọi nó trong onCreate () của Activity chẳng hạn. Bất kể RadioButtonbạn nhấp vào cái nào, những cái khác sẽ không được chọn. Ngoài ra, không có vấn đề gì, nếu một số RadioButtonsbên trong một số RadioGroup, hoặc không.

Đây là lớp học:

package pl.infografnet.GClasses;

import java.util.ArrayList;
import java.util.List;

import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewParent;
import android.widget.RadioButton;
import android.widget.RadioGroup;

public class GRadioGroup {

    List<RadioButton> radios = new ArrayList<RadioButton>();

    /**
     * Constructor, which allows you to pass number of RadioButton instances,
     * making a group.
     * 
     * @param radios
     *            One RadioButton or more.
     */
    public GRadioGroup(RadioButton... radios) {
        super();

        for (RadioButton rb : radios) {
            this.radios.add(rb);
            rb.setOnClickListener(onClick);
        }
    }

    /**
     * Constructor, which allows you to pass number of RadioButtons 
     * represented by resource IDs, making a group.
     * 
     * @param activity
     *            Current View (or Activity) to which those RadioButtons 
     *            belong.
     * @param radiosIDs
     *            One RadioButton or more.
     */
    public GRadioGroup(View activity, int... radiosIDs) {
        super();

        for (int radioButtonID : radiosIDs) {
            RadioButton rb = (RadioButton)activity.findViewById(radioButtonID);
            if (rb != null) {
                this.radios.add(rb);
                rb.setOnClickListener(onClick);
            }
        }
    }

    /**
     * This occurs everytime when one of RadioButtons is clicked, 
     * and deselects all others in the group.
     */
    OnClickListener onClick = new OnClickListener() {

        @Override
        public void onClick(View v) {

            // let's deselect all radios in group
            for (RadioButton rb : radios) {

                ViewParent p = rb.getParent();
                if (p.getClass().equals(RadioGroup.class)) {
                    // if RadioButton belongs to RadioGroup, 
                    // then deselect all radios in it 
                    RadioGroup rg = (RadioGroup) p;
                    rg.clearCheck();
                } else {
                    // if RadioButton DOES NOT belong to RadioGroup, 
                    // just deselect it
                    rb.setChecked(false);
                }
            }

            // now let's select currently clicked RadioButton
            if (v.getClass().equals(RadioButton.class)) {
                RadioButton rb = (RadioButton) v;
                rb.setChecked(true);
            }

        }
    };

}

1
Đẹp. Nếu bạn thay thế RadioButton bằng CompoundButton siêu lớp thì còn tốt hơn nữa, vì sau đó bạn có thể thêm bất kỳ nút nào có thể chuyển đổi (chẳng hạn như ToggleButton) vào nhóm!
Neromancer

1
Cần lưu ý rằng việc thực hiện getCheckedRadioButtonId () từ nhóm radio thông thường của bạn sẽ không hoạt động nữa (luôn trả về -1) nếu các nút radio không được lồng trực tiếp vào nhóm radio. Tôi đã thêm một phương thức khác vào lớp ở trên như sau: `/ ** * Trả về Id của nút radio được chọn hoặc -1 nếu không có nút nào được chọn * @return * / public int getCheckedRadioButtonId () {int checkId = -1; // Vòng lặp từng nút radio for (RadioButton rb: radios) {if (rb.isChecked ()) {return rb.getId (); }} trả về checkId; } `
sham

14

Đây là giải pháp của tôi dựa trên giải pháp @lostdev và việc triển khai RadioGroup. Đó là một RadioGroup được sửa đổi để hoạt động với RadioButtons (hoặc các CompoundButtons khác) được lồng vào bên trong các bố cục con.

import android.content.Context;
import android.os.Build;
import android.support.annotation.IdRes;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.LinearLayout;
import android.widget.RadioButton;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * This class is a replacement for android RadioGroup - it supports
 * child layouts which standard RadioGroup doesn't.
 */
public class RecursiveRadioGroup extends LinearLayout {

    public interface OnCheckedChangeListener {
        void onCheckedChanged(RecursiveRadioGroup group, @IdRes int checkedId);
    }

    /**
     * For generating unique view IDs on API < 17 with {@link #generateViewId()}.
     */
    private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);

    private CompoundButton checkedView;

    private CompoundButton.OnCheckedChangeListener childOnCheckedChangeListener;

    /**
     * When this flag is true, onCheckedChangeListener discards events.
     */
    private boolean mProtectFromCheckedChange = false;

    private OnCheckedChangeListener onCheckedChangeListener;

    private PassThroughHierarchyChangeListener mPassThroughListener;

    public RecursiveRadioGroup(Context context) {
        super(context);
        setOrientation(HORIZONTAL);
        init();
    }

    public RecursiveRadioGroup(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public RecursiveRadioGroup(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        childOnCheckedChangeListener = new CheckedStateTracker();
        mPassThroughListener = new PassThroughHierarchyChangeListener();

        super.setOnHierarchyChangeListener(mPassThroughListener);
    }

    @Override
    public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
        mPassThroughListener.mOnHierarchyChangeListener = listener;
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        // checks the appropriate radio button as requested in the XML file
        if (checkedView != null) {
            mProtectFromCheckedChange = true;
            setCheckedStateForView(checkedView, true);
            mProtectFromCheckedChange = false;
            setCheckedView(checkedView);
        }
    }

    @Override
    public void addView(View child, int index, ViewGroup.LayoutParams params) {
        parseChild(child);

        super.addView(child, index, params);
    }

    private void parseChild(final View child) {
        if (child instanceof CompoundButton) {
            final CompoundButton checkable = (CompoundButton) child;

            if (checkable.isChecked()) {
                mProtectFromCheckedChange = true;
                if (checkedView != null) {
                    setCheckedStateForView(checkedView, false);
                }
                mProtectFromCheckedChange = false;
                setCheckedView(checkable);
            }
        } else if (child instanceof ViewGroup) {
            parseChildren((ViewGroup) child);
        }
    }

    private void parseChildren(final ViewGroup child) {
        for (int i = 0; i < child.getChildCount(); i++) {
            parseChild(child.getChildAt(i));
        }
    }

    /**
     * <p>Sets the selection to the radio button whose identifier is passed in
     * parameter. Using -1 as the selection identifier clears the selection;
     * such an operation is equivalent to invoking {@link #clearCheck()}.</p>
     *
     * @param view the radio button to select in this group
     * @see #getCheckedItemId()
     * @see #clearCheck()
     */
    public void check(CompoundButton view) {
        if(checkedView != null) {
            setCheckedStateForView(checkedView, false);
        }

        if(view != null) {
            setCheckedStateForView(view, true);
        }

        setCheckedView(view);
    }

    private void setCheckedView(CompoundButton view) {
        checkedView = view;

        if(onCheckedChangeListener != null) {
            onCheckedChangeListener.onCheckedChanged(this, checkedView.getId());
        }
    }

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

    /**
     * <p>Returns the identifier of the selected radio button in this group.
     * Upon empty selection, the returned value is -1.</p>
     *
     * @return the unique id of the selected radio button in this group
     * @attr ref android.R.styleable#RadioGroup_checkedButton
     * @see #check(CompoundButton)
     * @see #clearCheck()
     */
    @IdRes
    public int getCheckedItemId() {
        return checkedView.getId();
    }

    public CompoundButton getCheckedItem() {
        return checkedView;
    }

    /**
     * <p>Clears the selection. When the selection is cleared, no radio button
     * in this group is selected and {@link #getCheckedItemId()} returns
     * null.</p>
     *
     * @see #check(CompoundButton)
     * @see #getCheckedItemId()
     */
    public void clearCheck() {
        check(null);
    }

    /**
     * <p>Register a callback to be invoked when the checked radio button
     * changes in this group.</p>
     *
     * @param listener the callback to call on checked state change
     */
    public void setOnCheckedChangeListener(RecursiveRadioGroup.OnCheckedChangeListener listener) {
        onCheckedChangeListener = listener;
    }

    /**
     * Generate a value suitable for use in {@link #setId(int)}.
     * This value will not collide with ID values generated at build time by aapt for R.id.
     *
     * @return a generated ID value
     */
    public static int generateViewId() {
        for (; ; ) {
            final int result = sNextGeneratedId.get();
            // aapt-generated IDs have the high byte nonzero; clamp to the range under that.
            int newValue = result + 1;
            if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0.
            if (sNextGeneratedId.compareAndSet(result, newValue)) {
                return result;
            }
        }
    }

    private class CheckedStateTracker implements CompoundButton.OnCheckedChangeListener {

        @Override
        public void onCheckedChanged(CompoundButton view, boolean b) {
            if (mProtectFromCheckedChange) {
                return;
            }

            mProtectFromCheckedChange = true;
            if (checkedView != null) {
                setCheckedStateForView(checkedView, false);
            }
            mProtectFromCheckedChange = false;

            int id = view.getId();
            setCheckedView(view);
        }
    }

    private class PassThroughHierarchyChangeListener implements OnHierarchyChangeListener {

        private OnHierarchyChangeListener mOnHierarchyChangeListener;

        @Override
        public void onChildViewAdded(View parent, View child) {
            if (child instanceof CompoundButton) {
                int id = child.getId();

                if (id == View.NO_ID) {
                    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
                        child.setId(generateViewId());
                    } else {
                        child.setId(View.generateViewId());
                    }
                }

                ((CompoundButton) child).setOnCheckedChangeListener(childOnCheckedChangeListener);

                if (mOnHierarchyChangeListener != null) {
                    mOnHierarchyChangeListener.onChildViewAdded(parent, child);
                }
            } else if(child instanceof ViewGroup) {
                // View hierarchy seems to be constructed from the bottom up,
                // so all child views are already added. That's why we
                // manually call the listener for all children of ViewGroup.
                for(int i = 0; i < ((ViewGroup) child).getChildCount(); i++) {
                    onChildViewAdded(child, ((ViewGroup) child).getChildAt(i));
                }
            }
        }

        @Override
        public void onChildViewRemoved(View parent, View child) {
            if (child instanceof RadioButton) {
                ((CompoundButton) child).setOnCheckedChangeListener(null);
            }

            if (mOnHierarchyChangeListener != null) {
                mOnHierarchyChangeListener.onChildViewRemoved(parent, child);
            }
        }
    }

}

Bạn có thể sử dụng nó trong bố cục của mình giống như cách bạn làm RadioGroupvới thông thường ngoại trừ nó cũng hoạt động với các dạng RadioButtonxem lồng nhau :

<RecursiveRadioGroup
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="16dp"
    android:layout_marginBottom="16dp"
    android:layout_marginLeft="16dp"
    android:layout_marginRight="16dp"
    android:orientation="horizontal">

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:orientation="vertical">

        <RadioButton
            android:id="@+id/rbNotEnoughProfileInfo"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Not enough profile information"/>

        <RadioButton
            android:id="@+id/rbNotAGoodFit"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Not a good fit"/>

        <RadioButton
            android:id="@+id/rbDatesNoLongerAvailable"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Dates no longer available"/>

    </LinearLayout>

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:orientation="vertical">

        <RadioButton
            android:id="@+id/rbOther"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Other"/>

        <android.support.v7.widget.AppCompatEditText
            android:id="@+id/etReason"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_below="@+id/tvMessageError"
            android:textSize="15sp"
            android:gravity="top|left"
            android:hint="Tell us more"
            android:padding="16dp"
            android:background="@drawable/edit_text_multiline_background"/>
    </LinearLayout>

</RecursiveRadioGroup>

6

Giải pháp này chưa được đăng nên đăng:

Bước 0: Tạo một CompoundButton previousCheckedCompoundButton;biến toàn cục.

Bước 1: Tạo OnCheckedChangedListenercho các nút radio

CompoundButton.OnCheckedChangeListener onRadioButtonCheckedListener = new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            if (!isChecked) return;
            if (previousCheckedCompoundButton != null) {
                previousCheckedCompoundButton.setChecked(false);
                previousCheckedCompoundButton = buttonView;
            } else {
                previousCheckedCompoundButton = buttonView;
            }
        }
    };

Bước 3: thêm người nghe vào tất cả các nút radio:

radioButton1.setOnCheckedChangeListener(onRadioButtonCheckedListener);
radioButton2.setOnCheckedChangeListener(onRadioButtonCheckedListener);
radioButton3.setOnCheckedChangeListener(onRadioButtonCheckedListener);
radioButton4.setOnCheckedChangeListener(onRadioButtonCheckedListener);

Đó là nó!! bạn đã hoàn tất.


5

Haizz .. Thực sự đổ lỗi rằng Android thiếu một chức năng cơ bản như vậy.

Phỏng theo câu trả lời của @ScottBiggs, đây là cách ngắn nhất có thể để làm điều đó với Kotlin:

var currentSelected = button1
listOf<RadioButton>(
    button1, button2, button3, ...
).forEach {
    it.setOnClickListener { _ ->
        currentSelected.isChecked = false
        currentSelected = it
        currentSelected.isChecked = true
    }
}

không có logic bên trong câu trả lời của bạn kiểm tra xem nó một cách cẩn thận hơn
Edgar Khimich

@EdgarKhimich bạn nói "không logic" nghĩa là gì ..? mã của tôi trả lời một cách đơn giản và trang nhã câu hỏi ban đầu về cách nhóm một số nút radio. chúng tôi không đặt bất kỳ onclicklistener nào khác ngoài việc chuyển đổi séc đơn giản.
viz

Điều này là hoàn hảo ... hoạt động như một sự quyến rũ và không thêm nhiều mã. Cảm ơn!
kwishnu

3

Tôi đã tạo ra hai phương pháp này để giải quyết vấn đề này. Tất cả những gì bạn phải làm là chuyển ViewGroup nơi có các RadioButton (có thể là một RadioGroup, LinearLayout, RelativeLayout, v.v.) và nó thiết lập các sự kiện OnClick độc quyền, tức là, bất cứ khi nào một trong các RadioButton là con của ViewGroup ( ở bất kỳ cấp độ lồng nhau nào) được chọn, các cấp độ khác không được chọn. Nó hoạt động với nhiều bố cục lồng nhau như bạn muốn.

public class Utils {
    public static void setRadioExclusiveClick(ViewGroup parent) {
        final List<RadioButton> radios = getRadioButtons(parent);

        for (RadioButton radio: radios) {
            radio.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    RadioButton r = (RadioButton) v;
                    r.setChecked(true);
                    for (RadioButton r2:radios) {
                        if (r2.getId() != r.getId()) {
                            r2.setChecked(false);
                        }
                    }

                }
            });
        }
    }

    private static List<RadioButton> getRadioButtons(ViewGroup parent) {
        List<RadioButton> radios = new ArrayList<RadioButton>();
        for (int i=0;i < parent.getChildCount(); i++) {
            View v = parent.getChildAt(i);
            if (v instanceof RadioButton) {
                radios.add((RadioButton) v);
            } else if (v instanceof ViewGroup) {
                List<RadioButton> nestedRadios = getRadioButtons((ViewGroup) v);
                radios.addAll(nestedRadios);
            }
        }
        return radios;
    }
}

Cách sử dụng bên trong một hoạt động sẽ như thế này:

ViewGroup parent = findViewById(R.id.radios_parent);
Utils.setRadioExclusiveClick(parent);

2

Tôi đã viết lớp nhóm radio của riêng mình cho phép chứa các nút radio lồng nhau. Kiểm tra nó ra. Nếu bạn tìm thấy lỗi, vui lòng cho tôi biết.

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.LinearLayout;

/**
 * This class is used to create a multiple-exclusion scope for a set of compound
 * buttons. Checking one compound button that belongs to a group unchecks any
 * previously checked compound button within the same group. Intially, all of
 * the compound buttons are unchecked. While it is not possible to uncheck a
 * particular compound button, the group can be cleared to remove the checked
 * state. Basically, this class extends functionality of
 * {@link android.widget.RadioGroup} because it doesn't require that compound
 * buttons are direct childs of the group. This means you can wrap compound
 * buttons with other views. <br>
 * <br>
 * 
 * <b>IMPORTATNT! Follow these instruction when using this class:</b><br>
 * 1. Each direct child of this group must contain one compound button or be
 * compound button itself.<br>
 * 2. Do not set any "on click" or "on checked changed" listeners for the childs
 * of this group.
 */
public class CompoundButtonsGroup extends LinearLayout {

 private View checkedView;
 private OnCheckedChangeListener listener;
 private OnHierarchyChangeListener onHierarchyChangeListener;

 private OnHierarchyChangeListener onHierarchyChangeListenerInternal = new OnHierarchyChangeListener() {

  @Override
  public final void onChildViewAdded(View parent, View child) {
   notifyHierarchyChanged(null);
   if (CompoundButtonsGroup.this.onHierarchyChangeListener != null) {
    CompoundButtonsGroup.this.onHierarchyChangeListener.onChildViewAdded(
      parent, child);
   }
  }

  @Override
  public final void onChildViewRemoved(View parent, View child) {
   notifyHierarchyChanged(child);
   if (CompoundButtonsGroup.this.onHierarchyChangeListener != null) {
    CompoundButtonsGroup.this.onHierarchyChangeListener.onChildViewRemoved(
      parent, child);
   }
  }
 };

 public CompoundButtonsGroup(Context context) {
  super(context);
  init();
 }

 public CompoundButtonsGroup(Context context, AttributeSet attrs) {
  super(context, attrs);
  init();
 }

 public CompoundButtonsGroup(Context context, AttributeSet attrs, int defStyle) {
  super(context, attrs, defStyle);
  init();
 }

 private void init() {
  super.setOnHierarchyChangeListener(this.onHierarchyChangeListenerInternal);
 }

 @Override
 public final void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
  this.onHierarchyChangeListener = listener;
 }

 /**
  * Register a callback to be invoked when the checked view changes in this
  * group.
  * 
  * @param listener
  *            the callback to call on checked state change.
  */
 public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
  this.listener = listener;
 }

 /**
  * Returns currently selected view in this group. Upon empty selection, the
  * returned value is null.
  */
 public View getCheckedView() {
  return this.checkedView;
 }

 /**
  * Returns index of currently selected view in this group. Upon empty
  * selection, the returned value is -1.
  */
 public int getCheckedViewIndex() {
  return (this.checkedView != null) ? indexOfChild(this.checkedView) : -1;
 }

 /**
  * Sets the selection to the view whose index in group is passed in
  * parameter.
  * 
  * @param index
  *            the index of the view to select in this group.
  */
 public void check(int index) {
  check(getChildAt(index));
 }

 /**
  * Clears the selection. When the selection is cleared, no view in this
  * group is selected and {@link #getCheckedView()} returns null.
  */
 public void clearCheck() {
  if (this.checkedView != null) {
   findCompoundButton(this.checkedView).setChecked(false);
   this.checkedView = null;
   onCheckedChanged();
  }
 }

 private void onCheckedChanged() {
  if (this.listener != null) {
   this.listener.onCheckedChanged(this.checkedView);
  }
 }

 private void check(View child) {
  if (this.checkedView == null || !this.checkedView.equals(child)) {
   if (this.checkedView != null) {
    findCompoundButton(this.checkedView).setChecked(false);
   }

   CompoundButton comBtn = findCompoundButton(child);
   comBtn.setChecked(true);

   this.checkedView = child;
   onCheckedChanged();
  }
 }

 private void notifyHierarchyChanged(View removedView) {
  for (int i = 0; i < getChildCount(); i++) {
   View child = getChildAt(i);
   child.setOnClickListener(new OnClickListener() {

    @Override
    public void onClick(View v) {
     check(v);
    }
   });
   CompoundButton comBtn = findCompoundButton(child);
   comBtn.setClickable(comBtn.equals(child));
  }

  if (this.checkedView != null && removedView != null
    && this.checkedView.equals(removedView)) {
   clearCheck();
  }
 }

 private CompoundButton findCompoundButton(View view) {
  if (view instanceof CompoundButton) {
   return (CompoundButton) view;
  }

  if (view instanceof ViewGroup) {
   for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
    CompoundButton compoundBtn = findCompoundButton(((ViewGroup) view)
      .getChildAt(i));
    if (compoundBtn != null) {
     return compoundBtn;
    }
   }
  }

  return null;
 }

 /**
  * Interface definition for a callback to be invoked when the checked view
  * changed in this group.
  */
 public interface OnCheckedChangeListener {

  /**
   * Called when the checked view has changed.
   * 
   * @param checkedView
   *            newly checked view or null if selection was cleared in the
   *            group.
   */
  public void onCheckedChanged(View checkedView);
 }

}

2

Bạn cần làm hai điều:

  1. Sử dụng mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
  2. Thực hiện triển khai chế độ xem hàng tùy chỉnh của bạn Checkable.

Vì vậy, tôi nghĩ rằng giải pháp tốt hơn là triển khai Checkable bên trong LinearLayout bên trong của bạn: (cảm ơn daichan4649, từ liên kết của anh ấy, https://gist.github.com/daichan4649/5245378 , tôi đã dán tất cả mã bên dưới)

CheckableLayout.java

package daichan4649.test;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Checkable;
import android.widget.LinearLayout;

public class CheckableLayout extends LinearLayout implements Checkable {

    private static final int[] CHECKED_STATE_SET = { android.R.attr.state_checked };

    public CheckableLayout(Context context) {
        super(context, null);
    }

    public CheckableLayout(Context context, AttributeSet attrs) {
        super(context, attrs, 0);
    }

    public CheckableLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    private boolean checked;

    @Override
    public boolean isChecked() {
        return checked;
    }

    @Override
    public void setChecked(boolean checked) {
        if (this.checked != checked) {
            this.checked = checked;
            refreshDrawableState();

            for (int i = 0; i < getChildCount(); i++) {
                View child = getChildAt(i);
                if (child instanceof Checkable) {
                    ((Checkable) child).setChecked(checked);
                }
            }
        }
    }

    @Override
    public void toggle() {
        setChecked(!checked);
    }

    @Override
    protected int[] onCreateDrawableState(int extraSpace) {
        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
        if (isChecked()) {
            mergeDrawableStates(drawableState, CHECKED_STATE_SET);
        }
        return drawableState;
    }
}

Inflater_list_column.xml

<?xml version="1.0" encoding="utf-8"?>
<daichan4649.test.CheckableLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/check_area"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center_vertical">

    <TextView
        android:id="@+id/text"
        android:layout_width="0dip"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_weight="1"
        android:gravity="center_vertical" />

    <RadioButton
        android:id="@+id/radio"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:clickable="false"
        android:focusable="false"
        android:focusableInTouchMode="false" />

</daichan4649.test.CheckableLayout>

TestFragment.java

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.fragment_test, container, false);

    // 表示データ
    List<String> dataList = new ArrayList<String>();

    // 初期選択位置
    int initSelectedPosition = 3;

    // リスト設定
    TestAdapter adapter = new TestAdapter(getActivity(), dataList);
    ListView listView = (ListView) view.findViewById(R.id.list);
    listView.setAdapter(adapter);
    listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
    listView.setItemChecked(initSelectedPosition, true);

    listView.setOnItemClickListener(new OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            // 選択状態を要素(checkable)へ反映
            Checkable child = (Checkable) parent.getChildAt(position);
            child.toggle();
        }
    });
    return view;
}

private static class TestAdapter extends ArrayAdapter<String> {

    private LayoutInflater inflater;

    public TestAdapter(Context context, List<String> dataList) {
        super(context, 0, dataList);
        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final ViewHolder holder;
        if (convertView == null) {
            convertView = inflater.inflate(R.layout.inflater_list_column, null);
            holder = new ViewHolder();
            holder.text = (TextView) convertView.findViewById(R.id.text);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        // bindData
        holder.text.setText(getItem(position));
        return convertView;
    }
}

private static class ViewHolder {
    TextView text;
}

2

Tôi phải đối mặt với vấn đề tương tự là tôi muốn đặt 4 nút radio khác nhau trong hai tuyến tính khác nhau và bố cục này sẽ là con của nhóm radio. Để đạt được hành vi mong muốn trong RadioGroup, tôi đã nạp chồng hàm addView

Đây là giải pháp

public class AgentRadioGroup extends RadioGroup
{

    public AgentRadioGroup(Context context) {
        super(context);
    }

    public AgentRadioGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public void onViewAdded(View child) {
        if( child instanceof ViewGroup)
        {
            ViewGroup viewGroup = (ViewGroup) child;
            for(int i=0; i<viewGroup.getChildCount(); i++)
            {
                View subChild = viewGroup.getChildAt(i);
                if( subChild instanceof ViewGroup )
                {
                    onViewAdded(subChild);
                }
                else
                {
                    if (subChild instanceof RadioButton) {
                        super.onViewAdded(subChild);
                    }
                }
            }
        }
        if (child instanceof RadioButton)
        {
            super.onViewAdded(child);
        }
    }
}

1

Không có gì ngăn cản bạn triển khai cấu trúc bố cục đó ( RadioGrouptrên thực tế là một lớp con của LinearLayout) nhưng bạn không nên. Trước hết, bạn tạo cấu trúc sâu 4 cấp độ (sử dụng cấu trúc bố cục khác mà bạn có thể tối ưu hóa điều này) và thứ hai, nếu bạn RadioButtonskhông phải là con trực tiếp của a RadioGroup, thì một mục duy nhất được chọn trong nhóm sẽ không hoạt động. Điều này có nghĩa là nếu bạn chọn một Radiobuttontừ bố cục đó và sau đó chọn một bố cục khác, RadioButtonbạn sẽ kết thúc với hai bố cục RadioButtonsđược chọn thay vì bố cục được chọn cuối cùng.

Nếu bạn giải thích những gì bạn muốn làm trong bố cục đó, có lẽ tôi có thể giới thiệu cho bạn một giải pháp thay thế.


Luksprog, Cảm ơn vì lời giải thích của bạn. Nếu tôi hiểu đúng nếu RadioButtons không phải là con trực tiếp của một nhóm radio thì nó sẽ không hoạt động.
marcoqf73,

1
@ marcoqf73 Vâng, nói một cách đơn giản hơn, nếu bạn có bất kỳ thứ gì trong bố cục giữa dấu RadioButtonsvà gốc RadioGroupthì điều này sẽ không hoạt động như bình thường và về cơ bản bạn sẽ kết thúc bằng một LinearLayoutđiền RadioButtons.
Luksprog

2
Có rất nhiều lý do để làm điều gì đó như thế này. Ví dụ: bạn có thể muốn có nhiều quyền kiểm soát bố cục của mình hơn là một LinearLayout đơn giản; trong trường hợp của tôi, tôi muốn tạo nhiều hàng RadioButtons. Lồng bố cục là cách hoạt động của MỌI bố cục Android. Bah, tôi phát ngán khi phải nghe, "Bạn không thể làm điều đó", trong khi tìm kiếm giải pháp cho những câu hỏi hóc búa về giao diện người dùng này mà tôi nhận được hàng ngày. :(
SMBiggs

@ScottBiggs Tôi không nói rằng bạn không thể làm điều đó, tôi đã nói rằng thử những gì người dùng đặt câu hỏi sẽ không hiệu quả. Bạn có thể tự do triển khai bố cục của riêng mình (nhưng không dễ dàng để làm cho nó đúng) hoặc sử dụng một thủ thuật như trong câu trả lời này của tôi stackoverflow.com/questions/10425569/… .
Luksprog

Tôi đã tạo một lớp radiogroup mở rộng bố cục bảng và thêm các tính năng từ lớp radiogroup. Nó hoạt động khá tốt với số lượng cột không giới hạn, thêm các nút radio một cách linh hoạt. stackoverflow.com/questions/10425569/…
Kristy Welsh

1

0,02 đô la của tôi dựa trên @infografnet và @lostdev (cũng cảm ơn @Neromancer về đề xuất Nút ghép!)

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

Cách sử dụng (với trình nghe bao gồm):

AdvRadioGroup group = new AdvRadioGroup(findViewById(R.id.YOUR_VIEW));
group.setOnButtonCheckedListener(new AdvRadioGroup.OnButtonCheckedListener() {
    @Override
    public void onButtonChecked(CompoundButton button) {
        // do fun stuff here!
    }
});

Phần thưởng: Bạn có thể nhận được nút được kiểm tra cuối cùng, danh sách toàn bộ các nút và bạn có thể kiểm tra bất kỳ nút nào theo chỉ mục với cái này!


giải pháp tuyệt vời! nó làm việc cho tôi. chỉ khi bạn cần chỉ định bố cục tuyến tính bên trong trình nghe onClick mới bởi vì chỉ khi bạn chạm vào vòng tròn của nút radio, seleccion mới thay đổi.
benoffi7

1
    int currentCheckedRadioButton = 0;
    int[] myRadioButtons= new int[6];
    myRadioButtons[0] = R.id.first;
    myRadioButtons[1] = R.id.second;
    //..
    for (int radioButtonID : myRadioButtons) {
        findViewById(radioButtonID).setOnClickListener(
                    new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (currentCheckedRadioButton != 0)
                    ((RadioButton) findViewById(currentCheckedRadioButton)).setChecked(false);
                currentCheckedRadioButton = v.getId();

            }
        });
    }

0

Mặc dù đây có thể là một chủ đề cũ hơn, nhưng tôi muốn nhanh chóng chia sẻ mã hacky đơn giản mà tôi đã viết .. Nó không dành cho tất cả mọi người và cũng có thể thực hiện với một số cải tiến ..

Tình hình sử dụng mã này ??
Mã này dành cho những người có bố cục của câu hỏi ban đầu hoặc tương tự, trong trường hợp của tôi, nó như dưới đây. Điều này cá nhân là cho một Hộp thoại mà tôi đang sử dụng.

  • LinLayout_Main
    • LinLayout_Row1
      • ImageView
      • Nút radio
    • LinLayout_Row2
      • ImageView
      • Nút radio
    • LinLayout_Row3
      • ImageView
      • Nút radio

Bản thân mã làm gì ??
Mã này sẽ liệt kê từng Con của "LinLayout_Main" và đối với mỗi con là "LinearLayout", nó sẽ liệt kê Chế độ xem đó cho bất kỳ RadioButtons nào.

Đơn giản là nó sẽ tìm kiếm "LinLayout_Main" mẹ và tìm thấy bất kỳ RadioButton nào trong bất kỳ Child LinearLayouts nào.

MyMethod_ShowDialog
Sẽ hiển thị hộp thoại có tệp bố cục XML trong khi cũng xem xét nó để đặt "setOnClickListener" cho mỗi RadioButton mà nó tìm thấy

MyMethod_ClickRadio
Sẽ lặp lại từng RadioButton giống như cách "MyMethod_ShowDialog" thực hiện nhưng thay vì đặt "setOnClickListener", thay vào đó nó sẽ "setChecked (false)" để xóa từng RadioButton và sau đó ở bước cuối cùng sẽ "setChecked (false)" cho RadioButton đó được gọi là sự kiện nhấp chuột.

public void MyMethod_ShowDialog(final double tmpLat, final double tmpLng) {
        final Dialog dialog = new Dialog(actMain);
        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        dialog.setContentView(R.layout.layout_dialogXML);

        final LinearLayout tmpLayMain = (LinearLayout)dialog.findViewById(R.id.LinLayout_Main);
        if (tmpLayMain!=null) {
            // Perform look for each child of main LinearLayout
            int iChildCount1 = tmpLayMain.getChildCount();
            for (int iLoop1=0; iLoop1 < iChildCount1; iLoop1++){
                View tmpChild1 = tmpLayMain.getChildAt(iLoop1);
                if (tmpChild1 instanceof LinearLayout) {
                    // Perform look for each LinearLayout child of main LinearLayout
                    int iChildCount2 = ((LinearLayout) tmpChild1).getChildCount();
                    for (int iLoop2=0; iLoop2 < iChildCount2; iLoop2++){
                        View tmpChild2 = ((LinearLayout) tmpChild1).getChildAt(iLoop2);
                        if (tmpChild2 instanceof RadioButton) {
                            ((RadioButton) tmpChild2).setOnClickListener(new RadioButton.OnClickListener() {
                                public void onClick(View v) {
                                    MyMethod_ClickRadio(v, dialog);
                                }
                            });
                        }
                    }
                }
            }

            Button dialogButton = (Button)dialog.findViewById(R.id.LinLayout_Save);
            dialogButton.setOnClickListener(new Button.OnClickListener() {
                public void onClick(View v) {
                    dialog.dismiss();
                }
            });
        }
       dialog.show();
}


public void MyMethod_ClickRadio(View vRadio, final Dialog dDialog) {

        final LinearLayout tmpLayMain = (LinearLayout)dDialog.findViewById(R.id.LinLayout_Main);
        if (tmpLayMain!=null) {
            int iChildCount1 = tmpLayMain.getChildCount();
            for (int iLoop1=0; iLoop1 < iChildCount1; iLoop1++){
                View tmpChild1 = tmpLayMain.getChildAt(iLoop1);
                if (tmpChild1 instanceof LinearLayout) {
                    int iChildCount2 = ((LinearLayout) tmpChild1).getChildCount();
                    for (int iLoop2=0; iLoop2 < iChildCount2; iLoop2++){
                        View tmpChild2 = ((LinearLayout) tmpChild1).getChildAt(iLoop2);
                        if (tmpChild2 instanceof RadioButton) {
                            ((RadioButton) tmpChild2).setChecked(false);
                        }
                    }
                }
            }
        }

        ((RadioButton) vRadio).setChecked(true);
}

Có thể có lỗi, được sao chép từ dự án và đổi tên thành Voids / XML / ID

Bạn cũng có thể chạy cùng một loại vòng lặp để tìm ra mục nào được kiểm tra


Bạn có thể làm cho điều này hoạt động. Tôi đang cố gắng tạo một nhóm radio với các phát tuyến tính phụ có nút radio bên cạnh nút thông thường. Tôi không thể làm cho nó hoạt động và được đăng , nhưng được thông báo rằng radiogroup sẽ gặp sự cố trên bất kỳ trẻ em nào không phải là nút radio.
abalter,

0

Đây là phiên bản sửa đổi của giải pháp @ Infografnet. Nó đơn giản và dễ sử dụng.

RadioGroupHelper group = new RadioGroupHelper(this,R.id.radioButton1,R.id.radioButton2); group.radioButtons.get(0).performClick(); //programmatically

Chỉ cần sao chép và dán

package com.qamar4p.farmer.ui.custom;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.view.View;
import android.widget.CompoundButton;
import android.widget.RadioButton;

public class RadioGroupHelper {

    public List<CompoundButton> radioButtons = new ArrayList<>();

    public RadioGroupHelper(RadioButton... radios) {
        super();
        for (RadioButton rb : radios) {
            add(rb);
        }
    }

    public RadioGroupHelper(Activity activity, int... radiosIDs) {
        this(activity.findViewById(android.R.id.content),radiosIDs);
    }

    public RadioGroupHelper(View rootView, int... radiosIDs) {
        super();
        for (int radioButtonID : radiosIDs) {
            add((RadioButton)rootView.findViewById(radioButtonID));
        }
    }

    private void add(CompoundButton button){
        this.radioButtons.add(button);
        button.setOnClickListener(onClickListener);
    }

    View.OnClickListener onClickListener = v -> {
        for (CompoundButton rb : radioButtons) {
            if(rb != v) rb.setChecked(false);
        }
    };
}

0

Như được hiển thị trong câu trả lời, giải pháp là một hack tùy chỉnh đơn giản. Đây là phiên bản tối giản của tôi trong Kotlin.

import android.widget.RadioButton

class SimpleRadioGroup(private val radioButtons: List<RadioButton>) {

    init {
        radioButtons.forEach {
            it.setOnClickListener { clickedButton ->
                radioButtons.forEach { it.isChecked = false }
                (clickedButton as RadioButton).isChecked = true
            }
        }
    }

    val checkedButton: RadioButton?
        get() = radioButtons.firstOrNull { it.isChecked }
}

thì bạn chỉ cần làm điều gì đó như vậy trong onCreate của hoạt động hoặc onViewCreate của hoạt động của bạn:

SimpleRadioGroup(listOf(radio_button_1, radio_button_2, radio_button_3))

0

Đây là giải pháp của tôi trên Kotlin cho bố cục tùy chỉnh với RadioButton bên trong.

tipInfoContainerFirst.radioButton.isChecked = true

var prevSelected = tipInfoContainerFirst.radioButton
prevSelected.isSelected = true

listOf<RadioButton>(
    tipInfoContainerFirst.radioButton,
    tipInfoContainerSecond.radioButton,
    tipInfoContainerThird.radioButton,
    tipInfoContainerForth.radioButton,
    tipInfoContainerCustom.radioButton
).forEach {
    it.setOnClickListener { _it ->
    if(!it.isSelected) {
        prevSelected.isChecked = false
        prevSelected.isSelected = false
        it.radioButton.isSelected = true
        prevSelected = it.radioButton
    }
  }
}

0

Tôi gặp phải vấn đề tương tự, tôi phải sử dụng nút Radio cho giới tính và tất cả đều có hình ảnh và văn bản nên tôi đã cố gắng giải quyết bằng cách sau.

tệp xml:

<RadioGroup
       android:layout_marginTop="40dp"
       android:layout_marginEnd="23dp"
       android:id="@+id/rgGender"
       android:layout_width="match_parent"
       android:layout_below="@id/tvCustomer"
       android:orientation="horizontal"
       android:layout_height="wrap_content">

       <LinearLayout
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:orientation="vertical"
           android:gravity="center_horizontal"
           android:layout_weight="1">
       <RadioButton
           android:id="@+id/rbMale"
           android:layout_width="80dp"
           android:layout_height="60dp"
           android:background="@drawable/male_radio_btn_selector"
           android:button="@null"
           style="@style/RadioButton.Roboto.20sp"/>

           <TextView
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:text="Male"
               style="@style/TextView.RobotoLight.TxtGrey.18sp"
               android:layout_margin="0dp"
               android:textSize="@dimen/txtsize_20sp"/>
       </LinearLayout>
       <LinearLayout
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:orientation="vertical"
           android:gravity="center_horizontal"
           android:layout_weight="1">
       <RadioButton
           android:layout_weight="1"
           android:gravity="center"
           android:id="@+id/rbFemale"
           android:layout_width="80dp"
           android:layout_height="60dp"
           android:button="@null"
           android:background="@drawable/female_radio_btn_selector"
           style="@style/RadioButton.Roboto.20sp"
           android:textColor="@color/light_grey"/>
           <TextView
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:text="Female"
               android:layout_margin="0dp"
               style="@style/TextView.RobotoLight.TxtGrey.18sp"
               android:textSize="@dimen/txtsize_20sp"/>
       </LinearLayout>
       <LinearLayout
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:orientation="vertical"
           android:gravity="center_horizontal"
           android:layout_weight="1">
       <RadioButton
           android:layout_weight="1"
           android:gravity="center"
           android:id="@+id/rbOthers"
           android:layout_width="80dp"
           android:layout_height="60dp"
           android:button="@null"
           android:background="@drawable/other_gender_radio_btn_selector"
           style="@style/RadioButton.Roboto.20sp"/>
          <TextView
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="Other"
              android:layout_margin="0dp"
              style="@style/TextView.RobotoLight.TxtGrey.18sp"
              android:textSize="@dimen/txtsize_20sp"/>
      </LinearLayout>
   </RadioGroup>

Trong tệp java: Tôi đặt setOnCheckedChangeListener trên cả 3 nút radio và phương pháp ghi đè như được đề cập bên dưới và nó hoạt động tốt đối với tôi.

@Override
    public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
   switch (compoundButton.getId()){
       case R.id.rbMale:
           if(rbMale.isChecked()){
               rbMale.setChecked(true);
               rbFemale.setChecked(false);
               rbOther.setChecked(false);
           }
           break;
       case R.id.rbFemale:
           if(rbFemale.isChecked()){
               rbMale.setChecked(false);
               rbFemale.setChecked(true);
               rbOther.setChecked(false);
           }
           break;
       case R.id.rbOthers:
           if(rbOther.isChecked()){
               rbMale.setChecked(false);
               rbFemale.setChecked(false);
               rbOther.setChecked(true);
           }
           break;

   }
    }

0

MixedCompoundButtonGroup làm điều đó cho bạn!

Ý chính của MixedCompoundButtonGroup

fun setAll() {
    for (i in 0 until childCount) {
        val child = getChildAt(i)
        setCompoundButtonListener(child)
    }
}  


private fun setCompoundButtonListener(view: View?) {
    if (view == null) return
    if (view is CompoundButton) {
        view.setOnCheckedChangeListener(compoundButtonCheckedChangedListener)
    } else if (view is ViewGroup && view !is RadioGroup) { // NOT RadioGroup!
        for (i in 0 until view.childCount) {
            setCompoundButtonListener(view.getChildAt(i))
        }
    }
}

private fun initCompoundButtonListener() {
    compoundButtonCheckedChangedListener = CompoundButton.OnCheckedChangeListener { compoundButton, isChecked ->
        setChecked(compoundButton, isChecked)
    }
}

private fun setChecked(compoundButton: CompoundButton, isChecked: Boolean) {
    if (isChecked.not()) return
    if (currentCompoundButton != null) {
        currentCompoundButton!!.isChecked = false
        currentCompoundButton = compoundButton
    } else {
        currentCompoundButton = compoundButton
    }
    checkedChangedListener?.onCheckedChanged(currentCompoundButton!!)
}

0

Bạn có thể sử dụng mã mở rộng RadioGroup đơn giản này. Thả bất kỳ bố cục / chế độ xem / hình ảnh nào vào đó cùng với RadioButtons và nó sẽ hoạt động.

Nó chứa lệnh gọi lại lựa chọn trả về RadioButton đã chọn với chỉ mục của nó và bạn có thể đặt lựa chọn theo chương trình bằng chỉ mục hoặc id:

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RadioButton;
import android.widget.RadioGroup;

import java.util.ArrayList;

public class EnhancedRadioGroup extends RadioGroup implements View.OnClickListener {

    public interface OnSelectionChangedListener {
        void onSelectionChanged(RadioButton radioButton, int index);
    }

    private OnSelectionChangedListener selectionChangedListener;
    ArrayList<RadioButton> radioButtons = new ArrayList<>();

    public EnhancedRadioGroup(Context context) {
        super(context);
    }

    public EnhancedRadioGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        if (changed) {
            getRadioButtons();
        }
    }

    private void getRadioButtons() {
        radioButtons.clear();
        checkForRadioButtons(this);
    }

    private void checkForRadioButtons(ViewGroup viewGroup) {
        if (viewGroup == null) {
            return;
        }
        for (int i = 0; i < viewGroup.getChildCount(); i++) {
            View v = viewGroup.getChildAt(i);
            if (v instanceof RadioButton) {
                v.setOnClickListener(this);
                // store index of item
                v.setTag(radioButtons.size());
                radioButtons.add((RadioButton) v);
            }
            else if (v instanceof ViewGroup) {
                checkForRadioButtons((ViewGroup)v);
            }
        }
    }

    public RadioButton getSelectedItem() {
        if (radioButtons.isEmpty()) {
            getRadioButtons();
        }
        for (RadioButton radioButton : radioButtons) {
            if (radioButton.isChecked()) {
                return radioButton;
            }
        }
        return null;
    }

    public void setOnSelectionChanged(OnSelectionChangedListener selectionChangedListener) {
        this.selectionChangedListener = selectionChangedListener;
    }

    public void setSelectedById(int id) {
        if (radioButtons.isEmpty()) {
            getRadioButtons();
        }
        for (RadioButton radioButton : radioButtons) {
            boolean isSelectedRadioButton = radioButton.getId() == id;
            radioButton.setChecked(isSelectedRadioButton);
            if (isSelectedRadioButton && selectionChangedListener != null) {
                selectionChangedListener.onSelectionChanged(radioButton, (int)radioButton.getTag());
            }
        }
    }

    public void setSelectedByIndex(int index) {
        if (radioButtons.isEmpty()) {
            getRadioButtons();
        }
        if (radioButtons.size() > index) {
            setSelectedRadioButton(radioButtons.get(index));
        }
    }

    @Override
    public void onClick(View v) {
        setSelectedRadioButton((RadioButton) v);
    }

    private void setSelectedRadioButton(RadioButton rb) {
        if (radioButtons.isEmpty()) {
            getRadioButtons();
        }
        for (RadioButton radioButton : radioButtons) {
            radioButton.setChecked(rb == radioButton);
        }
        if (selectionChangedListener != null) {
            selectionChangedListener.onSelectionChanged(rb, (int)rb.getTag());
        }
    }
}

Sử dụng nó trong xml bố cục của bạn:

    <path.to.your.package.EnhancedRadioGroup>
       Layouts containing RadioButtons/Images/Views and other RadioButtons
    </path.to.your.package.EnhancedRadioGroup>

Để đăng ký cuộc gọi lại:

        enhancedRadioGroupInstance.setOnSelectionChanged(new EnhancedRadioGroup.OnSelectionChangedListener() {
            @Override
            public void onSelectionChanged(RadioButton radioButton, int index) {

            }
        });
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.