วิธีการจัดกลุ่ม RadioButton จาก LinearLayouts ที่แตกต่างกัน?


93

ฉันสงสัยว่าเป็นไปได้หรือไม่ที่จะจัดกลุ่มแต่ละซิงเกิลRadioButtonในเอกลักษณ์ที่RadioGroup คงโครงสร้างเดียวกัน โครงสร้างของฉันมีลักษณะดังนี้:

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

ที่คุณสามารถดูตอนนี้แต่ละคนเป็นเด็กที่แตกต่างกันRadioButton LinearLayoutฉันลองใช้โครงสร้างด้านล่าง แต่ไม่ได้ผล:

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

14
@coding อีกาหากคุณถูกบังคับให้ถามแสดงว่าคุณไม่เคยทำงานกับนักออกแบบสำหรับการไหลของ UI (และฉันเดาว่าปุ่มตัวเลือกของคุณอาจไม่ซับซ้อนมาก) ลองนึกภาพ (ถ้าคุณทำได้) ปุ่มตัวเลือกที่อยู่ถัดจากข้อความสองส่วนอันที่เป็นบรรทัดแรกและอีกปุ่มหนึ่งที่เป็นข้อความย่อย ทีนี้ลองนึกภาพ 5 ข้อต่อกัน คุณจะทำสิ่งนั้นได้อย่างไร? อ๊ะ ... คุณทำไม่ได้ เป็นสิ่งที่ดีที่ไม่จำเป็นต้องมีอะไรแปลกใหม่หรือ Google จะดูโง่เขลาจริงๆเมื่อมองข้ามฟังก์ชันการจัดวางพื้นฐานดังกล่าวในชุดเครื่องมือเลย์เอาต์ที่ครอบคลุมเป็นอย่างอื่น
Yevgeny Simkin

3
@ ดร. เดรเดลว้าวแม้ว่าฉันจะเห็นด้วยกับสิ่งที่คุณพูด (การใช้ radioButtons) แต่ปฏิกิริยาของคุณอาจมีอารมณ์มากเกินไป? :)
infografnet

14
มันไม่ได้อารมณ์มากจนน่ารำคาญอย่างเห็นได้ชัด ความคิดเห็นนั้นเสนออะไรให้กับ OP? โดยทั่วไปเสนออะไรให้กับเธรด? มันหมายความว่าคำถามนั้นไม่มีบุญและเป็นคนใจร้อนและขี้ขลาด หากเขาเริ่มต้นด้วย "คุณช่วยอธิบายได้ไหมว่าทำไมคุณถึงต้องการทำสิ่งนี้" ซึ่งจะทั้งเหมาะสมและสุภาพ "ฉันถูกบังคับให้ถาม" เป็นทางเลือกที่คลุมเครือบาง ๆ สำหรับ "คนงี่เง่าแบบไหนที่ต้องการ kluge ที่แปลกประหลาดนี้?" อย่างน้อยนั่นคือวิธีที่ฉันอ่าน
Yevgeny Simkin

1
ทำไมนักพัฒนา Android ยังไม่อนุญาตให้ใช้ LinearLayout ใน RadioGroup Marshmallow ออกแล้ว
Shan Xeeshi

1
ยังไม่มีคำตอบที่เหมาะสม? ฉันกำลังค้นหาวิธีแก้ปัญหา
นีน่า

คำตอบ:


49

ดูเหมือนว่าคนเก่ง ๆ ใน Google / Android จะคิดว่าเมื่อคุณใช้ RadioButtons คุณไม่ต้องการความยืดหยุ่นที่มาพร้อมกับระบบ UI / เค้าโครง Android ทุกด้าน พูดง่ายๆก็คือพวกเขาไม่ต้องการให้คุณซ้อนเค้าโครงและปุ่มตัวเลือก เฮ้อ.

ดังนั้นคุณต้องแก้ไขปัญหา นั่นหมายความว่าคุณต้องติดตั้งปุ่มตัวเลือกด้วยตัวคุณเอง

เรื่องนี้ไม่ยากเกินไป ใน onCreate () ของคุณให้ตั้งค่า RadioButtons ของคุณด้วย onClick () ของตัวเองเพื่อให้เมื่อเปิดใช้งานพวกเขา setChecked (จริง) และทำสิ่งที่ตรงกันข้ามกับปุ่มอื่น ๆ ตัวอย่างเช่น:

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

}

ใช่ฉันรู้ - ทางโรงเรียนเก่า แต่มันได้ผล โชคดี!


34
โกรธ. ไม่น่าเชื่อเลยว่านี่คือระดับของการเล่นตลกที่จำเป็นต่อการทำสิ่งที่เป็นโลกีย์อย่าง "ปุ่มตัวเลือก" เกินกว่าที่จะเชื่อได้ว่า Google มอบทางลัดมากมายสำหรับสิ่งที่เกือบจะไร้ประโยชน์ (เช่น 80% ของวิดเจ็ตแอนิเมชั่น) จากนั้นปล่อยให้เราหมุนปุ่มตัวเลือกของเราเอง (น้ำลาย!).
Yevgeny Simkin

3
@ ดร. เดรเดล: ใช่ฉันยอมรับว่าตัวเลือก UI มากมายของพวกเขานั้นแปลกประหลาด ฉันเดาได้อย่างเดียวเกี่ยวกับข้อ จำกัด นี้คือพวกเขาอาจกำลังคิดว่า "มันไม่ยากเลยที่จะทำด้วยตนเอง" แต่คงจะดีไม่น้อยหากพวกเขาบันทึกคุณลักษณะนี้ไว้อย่างน้อยที่สุด (เช่นหน้าบทช่วยสอน?) ดังที่คุณชี้ให้เห็นพวกเขาได้ไปหาสิ่งอื่น ๆ ที่เกือบจะไร้ประโยชน์ (อาจเป็นโครงการสัตว์เลี้ยง?)
SMBiggs

3
ฉันสามารถเดาได้ แต่ความประทับใจโดยรวมของฉันคือทีม UI ของ Android อาจได้รับการหดสั้น ๆ หรือโดยทั่วไปแล้วค่อนข้างอ่อนแอ พิจารณาสิ่งที่ผ่านสำหรับ "สง่างาม" ในจักรวาลของ Google ทั้งหมดนี้เป็นสปาร์ตันและเป็นประโยชน์อย่างแท้จริง ฉันไม่ใช่แฟนของ Apple เพราะฉันชอบฟังก์ชั่นการใช้งานที่มีสไตล์ แต่ถ้าเคยเป็น บริษัท ขนาดใหญ่ที่มีเงินสดจำนวนมากจำเป็นต้องคิดทบทวนรูปลักษณ์ใหม่ (ขึ้นและลงห่วงโซ่) ฉันไม่สามารถนึกถึงผู้สมัครที่ดีไปกว่า Google
Yevgeny Simkin

1
นี่เป็นหนึ่งในวิธีแก้ปัญหาที่น่าเชื่อถือและเรียบง่ายที่สุดที่มี ... แม้ว่าจะเป็นยุคก่อนประวัติศาสตร์ แต่ก็น่าเสียดายที่ Google ไม่ได้นำสิ่งที่มีประสิทธิภาพมากกว่านี้มาใช้ ...
ทีวี

3
ใช่ .. ฉันคาดหวังว่าจะมีบางอย่างเช่นการกำหนดรหัสปุ่มตัวเลือกให้กับ RadioGroup ด้วยตนเองหรือบางสิ่งบางอย่างจะมีอยู่หากมีค่าใช้จ่ายสูงในการส่งผ่านอัตโนมัติในกลุ่มมุมมองพิเศษที่ไม่มีปุ่มตัวเลือกภายในกลุ่มวิทยุ .. ฉันแน่ใจว่าบางอย่างเช่น มีอยู่ดังนั้นฉันจึงเริ่มค้นหา ตอนนี้ฉันออกจากโพสต์นี้ด้วยความสิ้นหวัง
Dreamingwhale

28

ใช้คลาสที่ฉันสร้างขึ้นนี้ จะพบลูกที่ตรวจสอบได้ทั้งหมดในลำดับชั้นของคุณ

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

หากได้รับรหัสนี้ฉันจะรับปุ่มที่เลือกในปัจจุบันได้อย่างไร
j2emanue

ฉันเพิ่งใส่ตัวแปร mCheckedview เมื่อคุณตั้งค่ามุมมอง ((ตรวจสอบได้)) .setChecked (จริง); และฉันส่งคืนตัวแปรนั้นเมื่อฉันต้องการทราบว่าตัวแปรใดถูกตรวจสอบ ตอนนี้ดูเหมือนจะโอเค แต่ต้อง "performClick ()" ตามค่าเริ่มต้นที่ฉันต้องการ ขอบคุณ
j2emanue

17

ฉันเขียนคลาสง่ายๆนี้

เพียงใช้มันดังนี้:

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

หรือ

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

คุณสามารถเรียกใช้ใน onCreate () ของกิจกรรมได้เช่น ไม่ว่าRadioButtonคุณจะคลิกที่ใดคนอื่น ๆ จะไม่ถูกเลือก นอกจากนี้ไม่สำคัญถ้าบางส่วนRadioButtonsอยู่ในบางส่วนRadioGroupหรือไม่

นี่คือชั้นเรียน:

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
ดี. หากคุณแทนที่ RadioButton ด้วย Super class CompoundButton มันจะดีกว่านั้นเพราะคุณสามารถเพิ่มปุ่มที่สลับได้ (เช่น ToggleButton) ลงในกลุ่ม!
Neromancer

1
เป็นที่น่าสังเกตว่าการดำเนินการ getCheckedRadioButtonId () จากกลุ่มวิทยุปกติของคุณจะไม่ทำงานอีกต่อไป (คืนค่า -1 เสมอ) หากปุ่มตัวเลือกไม่ได้ซ้อนกันโดยตรงในกลุ่มวิทยุ ฉันเพิ่มวิธีการอื่นในคลาสด้านบนดังนี้: `/ ** * ส่งคืน Id ของปุ่มตัวเลือกที่ถูกตรวจสอบหรือ -1 หากไม่มีการตรวจสอบ * @return * / public int getCheckedRadioButtonId () {int checkedId = -1; // วนปุ่มตัวเลือกแต่ละปุ่มสำหรับ (RadioButton rb: radios) {if (rb.isChecked ()) {return rb.getId (); }} ส่งคืน checkedId; } `
แชม

15

นี่คือทางออกของฉันขึ้นอยู่กับวิธีการแก้ปัญหา @lostdevRadioGroupและการดำเนินการ มันเป็น RadioGroup ที่แก้ไขให้ทำงานกับ RadioButtons (หรือ CompoundButtons อื่น ๆ ) ที่ซ้อนอยู่ภายในเค้าโครงลูก

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

}

คุณสามารถใช้มันในเค้าโครงของคุณในลักษณะเดียวกับที่คุณทำตามปกติRadioGroupโดยมีข้อยกเว้นว่ามันทำงานร่วมกับRadioButtonมุมมองที่ซ้อนกันได้เช่นกัน:

<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

ยังไม่มีการโพสต์โซลูชันนี้จึงโพสต์:

ขั้นตอนที่ 0: สร้างCompoundButton previousCheckedCompoundButton;ตัวแปร as global

ขั้นตอนที่ 1: สร้างOnCheckedChangedListenerสำหรับปุ่มตัวเลือก

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

ขั้นตอนที่ 3: เพิ่มผู้ฟังลงในปุ่มตัวเลือกทั้งหมด:

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

แค่นั้นแหละ!! คุณทำเสร็จแล้ว


5

เฮ้อ .. น่าตำหนิจริงๆที่ Android ขาดฟังก์ชันพื้นฐานแบบนี้

ดัดแปลงมาจากคำตอบของ @ScottBiggs นี่เป็นวิธีที่สั้นที่สุดในการทำกับ Kotlin:

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

ไม่มีตรรกะใด ๆ ในคำตอบของคุณโปรดตรวจสอบอย่างรอบคอบมากขึ้น
Edgar Khimich

@EdgarKhimich "no logic" แปลว่าอะไร .. ? รหัสของฉันตอบคำถามเดิมอย่างเรียบง่ายและสวยงามเกี่ยวกับวิธีการจัดกลุ่มปุ่มตัวเลือกต่างๆ เราไม่ได้ตั้งค่า onclicklistener อื่นใดนอกจากการสลับเช็คแบบธรรมดา
ได้แก่

สมบูรณ์แบบ ... ใช้งานได้อย่างมีเสน่ห์และไม่ได้เพิ่มรหัสมากนักขอบคุณ!
วิษณุ

3

ฉันสร้างสองวิธีนี้เพื่อแก้ปัญหานี้ สิ่งที่คุณต้องทำคือส่งผ่าน ViewGroup ที่ RadioButtons อยู่ (อาจเป็น RadioGroup, LinearLayout, RelativeLayout เป็นต้น) และตั้งค่าเหตุการณ์ OnClick โดยเฉพาะนั่นคือเมื่อใดก็ตามที่ RadioButtons ตัวใดตัวหนึ่งที่เป็นลูกของ ViewGroup ( ที่ระดับที่ซ้อนกัน) ถูกเลือกส่วนอื่น ๆ จะไม่ถูกเลือก ทำงานร่วมกับเค้าโครงที่ซ้อนกันได้มากเท่าที่คุณต้องการ

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

การใช้งานภายในกิจกรรมจะเป็นดังนี้:

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

2

ฉันได้เขียนคลาสกลุ่มวิทยุของตัวเองที่อนุญาตให้มีปุ่มตัวเลือกซ้อนกัน ลองดูสิ หากคุณพบข้อบกพร่องโปรดแจ้งให้เราทราบ

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

คุณต้องทำสองสิ่ง:

  1. ใช้ mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
  2. ทำให้มุมมองแถวที่กำหนดเองของคุณใช้งานCheckableได้

ดังนั้นฉันคิดว่าทางออกที่ดีกว่าคือการใช้ Checkable ภายใน LinearLayout ภายในของคุณ: (ขอบคุณ daichan4649 จากลิงค์ของเขาhttps://gist.github.com/daichan4649/5245378ฉันเอารหัสทั้งหมดมาวางด้านล่าง)

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

ฉันประสบปัญหาเดียวกันกับที่ฉันต้องการวางปุ่มตัวเลือก 4 ปุ่มใน linearlayout สองแบบที่แตกต่างกันและรูปแบบเหล่านี้จะเป็นส่วนย่อยของกลุ่มวิทยุ เพื่อให้บรรลุพฤติกรรมที่ต้องการใน RadioGroup ฉันได้ใช้ฟังก์ชัน addView มากเกินไป

นี่คือวิธีแก้ปัญหา

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

ไม่มีอะไรหยุดคุณจากการใช้โครงสร้างเลย์เอาต์นั้น ( RadioGroupอันที่จริงเป็นคลาสย่อยของLinearLayout) แต่คุณไม่ควรทำ แรกของทั้งหมดที่คุณสร้างโครงสร้าง 4 ระดับลึก (โดยใช้โครงสร้างรูปแบบอื่นที่คุณสามารถเพิ่มประสิทธิภาพนี้) และครั้งที่สองถ้าคุณRadioButtonsไม่ได้เป็นเด็กโดยตรงของRadioGroup, เพียงหนึ่งรายการที่เลือกในกลุ่มจะไม่ทำงาน ซึ่งหมายความว่าหากคุณเลือกRadiobuttonจากเค้าโครงนั้นแล้วเลือกรายการอื่นRadioButtonคุณจะได้RadioButtonsรับเลือกสองรายการแทนที่จะเป็นแบบที่เลือกสุดท้าย

หากคุณอธิบายว่าคุณต้องการทำอะไรในเค้าโครงนั้นฉันอาจแนะนำทางเลือกให้คุณได้


Luksprog ขอบคุณสำหรับคำอธิบาย ถ้าฉันเข้าใจถูกต้องถ้า RadioButtons ไม่ใช่ลูกโดยตรงของกลุ่มวิทยุก็จะใช้ไม่ได้
marcoqf73

1
@ marcoqf73 ใช่จะนำมันง่ายขึ้นถ้าคุณมีอะไรในรูปแบบระหว่างRadioButtonsและผู้ปกครองRadioGroupแล้วนี้จะไม่ทำงานเหมือนปกติและพื้นคุณจะจบลงด้วยการที่เต็มไปด้วยLinearLayout RadioButtons
ผู้ใช้

2
มีหลายเหตุผลที่จะทำสิ่งนี้ ตัวอย่างเช่นคุณอาจต้องการควบคุมเลย์เอาต์ของคุณมากกว่า LinearLayout แบบธรรมดา ในกรณีของฉันฉันต้องการสร้าง RadioButtons หลายแถว เลย์เอาต์การทำรังคือการทำงานของเลย์เอาต์ Android ทุกอย่าง ฉันเบื่อที่จะได้ยิน "คุณทำอย่างนั้นไม่ได้" ในขณะที่ค้นหาวิธีแก้ปัญหา UI เหล่านี้ซึ่งฉันได้รับทุกวัน ๆ :(
SMBiggs

@ScottBiggs ฉันไม่ได้บอกว่าคุณทำไม่ได้ฉันบอกว่าลองใช้สิ่งที่ผู้ใช้ถามคำถามจะไม่ได้ผล คุณมีอิสระที่จะใช้รูปแบบของคุณเอง ( แต่ไม่ใช่เรื่องง่ายที่จะได้รับมันขวา) หรือใช้เคล็ดลับเช่นในคำตอบของฉันนี้stackoverflow.com/questions/10425569/...
ผู้ใช้

ฉันสร้างคลาสเรดิโอกรุ๊ปที่ขยายเค้าโครงตารางและเพิ่มคุณสมบัติจากคลาสเรดิโอกรุ๊ป ทำงานได้ดีกับคอลัมน์ไม่ จำกัด จำนวนที่เพิ่มปุ่มตัวเลือกแบบไดนามิก stackoverflow.com/questions/10425569/…
Kristy Welsh

1

0.02 เหรียญของฉันขึ้นอยู่กับ @infografnet และ @lostdev (ขอบคุณ @Neromancer สำหรับคำแนะนำปุ่มผสม!)

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

โบนัส: คุณจะได้รับปุ่มตรวจสอบล่าสุดรายการปุ่มทั้งหมดและคุณสามารถตรวจสอบปุ่มใดก็ได้ตามดัชนีด้วยสิ่งนี้!


ทางออกที่ดี! มันได้ผลสำหรับฉัน เพียงแค่คุณต้องเทียบเคียงกับเลย์เอาต์เชิงเส้นภายในตัวฟัง onClick ใหม่เพราะถ้าคุณแตะวงกลมของปุ่มเรดิโอเท่านั้นการเปลี่ยนแปลง seleccion
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

แม้ว่านี่อาจจะเป็นหัวข้อที่เก่ากว่า แต่ฉันก็อยากแบ่งปันโค้ดแฮ็กกี้ง่ายๆที่ฉันเขียนไว้อย่างรวดเร็ว .. มันไม่ใช่สำหรับทุกคนและสามารถทำได้ด้วยการปรับแต่งบางอย่างเช่นกัน ..

สถานการณ์ที่จะใช้รหัสนี้ ??
รหัสนี้มีไว้สำหรับผู้ที่มีเค้าโครงของคำถามเดิมหรือคล้ายกันในกรณีของฉันเป็นดังนี้ นี่เป็นการส่วนตัวสำหรับ Dialog ที่ฉันใช้อยู่

  • LinLayout_Main
    • LinLayout_Row1
      • ImageView
      • RadioButton
    • LinLayout_Row2
      • ImageView
      • RadioButton
    • LinLayout_Row3
      • ImageView
      • RadioButton

โค้ดทำอะไรเอง ??
รหัสนี้จะแจกแจง Child ของ "LinLayout_Main" และสำหรับเด็กแต่ละคนที่เป็น "LinearLayout" ระบบจะระบุมุมมองนั้นสำหรับ RadioButtons ใด ๆ

เพียงแค่มองไปที่พาเรนต์ "LinLayout_Main" และค้นหา RadioButtons ที่อยู่ใน Child LinearLayouts

MyMethod_ShowDialog
จะแสดงกล่องโต้ตอบพร้อมไฟล์เลย์เอาต์ XML ในขณะเดียวกันก็มองหาเพื่อตั้งค่า "setOnClickListener" สำหรับ RadioButton แต่ละรายการที่พบ

MyMethod_ClickRadio
จะวนซ้ำ RadioButton แต่ละรายการในลักษณะเดียวกับที่ "MyMethod_ShowDialog" ทำ แต่แทนที่จะตั้งค่า "setOnClickListener" จะเป็น "setChecked (false)" แทนเพื่อล้าง RadioButton แต่ละรายการจากนั้นขั้นตอนสุดท้ายจะ "setChecked (false)" ไปยัง RadioButton ที่ เรียกว่าเหตุการณ์คลิก

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

อาจมีข้อบกพร่องคัดลอกจากโปรเจ็กต์และเปลี่ยนชื่อเป็น Voids / XML / ID

คุณยังสามารถเรียกใช้ลูปประเภทเดียวกันเพื่อดูว่ารายการใดบ้างที่ถูกตรวจสอบ


คุณสามารถทำให้สิ่งนี้ทำงานได้หรือไม่ ฉันกำลังพยายามสร้างกลุ่มวิทยุที่มีช่องรายการย่อยที่มีปุ่มตัวเลือกถัดจากปุ่มปกติ ฉันไม่สามารถใช้งานและโพสต์ได้ แต่ได้รับแจ้งว่ากลุ่มวิทยุจะขัดข้องกับเด็ก ๆ ที่ไม่ใช่ปุ่มวิทยุ
โรงอาบน้ำ

0

นี่คือโซลูชันของ @ Infografnet เวอร์ชันแก้ไข มันง่ายและใช้งานง่าย

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

เพียงแค่คัดลอกและวาง

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

ดังที่แสดงไว้ในคำตอบวิธีแก้ปัญหาคือแฮ็คที่กำหนดเองง่ายๆ นี่คือเวอร์ชันที่เรียบง่ายของฉันใน 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 }
}

จากนั้นคุณก็ต้องทำอะไรแบบนั้นใน onCreate ของกิจกรรมหรือ onViewCreated ของส่วน:

SimpleRadioGroup(listOf(radio_button_1, radio_button_2, radio_button_3))

0

นี่คือวิธีแก้ปัญหาของฉันใน Kotlin สำหรับเลย์เอาต์แบบกำหนดเองที่มี RadioButton อยู่ภายใน

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

ฉันประสบปัญหาเดียวกันฉันต้องใช้ปุ่มตัวเลือกสำหรับเพศและทั้งหมดมีรูปภาพและข้อความดังนั้นฉันจึงพยายามแก้ไขโดยใช้วิธีต่อไปนี้

ไฟล์ 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>

ในไฟล์ java: ฉันตั้ง setOnCheckedChangeListener บนปุ่มตัวเลือกทั้ง 3 ปุ่มและวิธีการแทนที่ตามที่ระบุไว้ด้านล่างและมันทำงานได้ดีสำหรับฉัน

@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ทำเพื่อคุณ!

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

คุณสามารถใช้รหัสส่วนขยาย RadioGroup แบบธรรมดานี้ วางเลย์เอาต์ / มุมมอง / ภาพใดก็ได้พร้อมกับ RadioButtons และจะใช้งานได้

มันมีการเรียกกลับการเลือกซึ่งส่งคืน RadioButton ที่เลือกพร้อมดัชนีและคุณสามารถตั้งค่าการเลือกโดยใช้ดัชนีหรือ 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());
        }
    }
}

ใช้ในรูปแบบ xml ของคุณ:

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

ในการลงทะเบียนเพื่อโทรกลับ:

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

            }
        });
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.