it-swarm.com.de

Wie gruppiere ich Radio Button aus verschiedenen linearen Layouts?

Ich habe mich gefragt, ob es möglich ist, jedes einzelne RadioButton in einem eindeutigen RadioGroup_ Zu gruppieren, wobei die gleiche Struktur beibehalten wird. Meine Struktur sieht so aus:

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

Wie Sie sehen, ist jetzt jedes RadioButton ein Kind von verschiedenen LinearLayout. Ich habe versucht, die folgende Struktur zu verwenden, aber es funktioniert nicht:

  • Radiogruppe
    • LinearLayout_main
      • LinearLayout_1
        • RadioButton1
      • LinearLayout_2
        • RadioButton2
      • LinearLayout_3
        • RadioButton3 
75
marcoqf73

Es scheint, dass die guten Leute bei Google/Android davon ausgehen, dass Sie bei der Verwendung von RadioButtons nicht die Flexibilität benötigen, die mit allen anderen Aspekten des Android-UI/Layout-Systems verbunden ist. Einfach ausgedrückt: Sie möchten nicht, dass Sie Layouts und Optionsfelder verschachteln. Seufzer.

Du musst also das Problem umgehen. Das bedeutet, dass Sie Optionsfelder selbst implementieren müssen.

Das ist wirklich nicht zu schwer. Stellen Sie in Ihrem onCreate () Ihre RadioButtons mit ihrem eigenen onClick () ein, damit sie, wenn sie aktiviert sind, Checked (true) setzen und für die anderen Buttons das Gegenteil tun. Zum Beispiel:

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

}

Ja, ich weiß, wie althergesehen. Aber es funktioniert. Viel Glück!

37
Scott Biggs

Verwenden Sie diese Klasse, die ich erstellt habe. Es werden alle überprüfbaren Kinder in Ihrer Hierarchie gefunden.

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

Nun, ich habe diese einfache Klasse geschrieben.

Verwenden Sie es einfach so:

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

oder

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

Sie können es beispielsweise in onCreate () von Activity aufrufen. Unabhängig davon, auf welches RadioButton Sie klicken, werden die anderen deaktiviert. Auch spielt es keine Rolle, ob einige von RadioButtons in einem von RadioGroup sind oder nicht.

Hier ist die Klasse:

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

        }
    };

}
17
infografnet

Hier ist meine Lösung basierend auf @lostdev Lösung und Implementierung von RadioGroup. Es ist eine Radiogruppe, die so geändert wurde, dass sie mit RadioButtons (oder anderen CompoundButtons) funktioniert, die in untergeordneten Layouts verschachtelt sind.

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

}

Sie können es in Ihrem Layout auf die gleiche Weise verwenden wie eine reguläre RadioGroup, mit der Ausnahme, dass es auch mit verschachtelten RadioButton-Ansichten funktioniert:

<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>
7
Ivan Kušt

Seufz ... Wirklich schuld, dass Android eine solche Grundfunktionalität fehlt.

Angepasst an die Antwort von @ScottBiggs, hier der möglicherweise kürzeste Weg, um dies mit Kotlin zu tun:

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

Ich habe diese beiden Methoden entwickelt, um dieses Problem zu lösen. Sie müssen lediglich die ViewGroup übergeben, in der sich die RadioButtons befinden (es könnte sich um eine RadioGroup, ein LinearLayout, ein RelativeLayout usw. handeln), und es werden ausschließlich die OnClick-Ereignisse festgelegt. auf einer verschachtelten Ebene) ausgewählt ist, sind die anderen nicht ausgewählt. Es funktioniert mit so vielen verschachtelten Layouts, wie Sie möchten.

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

Die Verwendung innerhalb einer Aktivität würde folgendermaßen aussehen:

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

Ich habe meine eigene Funkgruppenklasse geschrieben, in der sich verschachtelte Optionsfelder befinden können. Hör zu. Wenn Sie Fehler finden, lass es mich wissen.

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
Egis

Sie müssen zwei Dinge tun:

  1. Verwenden Sie mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
  2. Setzen Sie Ihre benutzerdefinierte Zeilenansicht in Checkable.

Ich denke, dass die bessere Lösung darin besteht, Checkable in Ihrem inneren LinearLayout zu implementieren: (Dank an daichan4649 von seinem Link https://Gist.github.com/daichan4649/5245378 , habe ich den unten eingefügten Code genommen )

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
madx

Ich habe das gleiche Problem, da ich 4 verschiedene Radioknöpfe in zwei unterschiedlichen linearen Layouts platzieren möchte. Um das Wunschverhalten in RadioGroup zu erreichen, habe ich die AddView-Funktion überladen 

Hier ist die Lösung

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
umerk44

Mein $ 0,02 basiert auf @infografnet und @lostdev (auch dank @Neromancer für den Compound Button-Vorschlag!)

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

Verwendung (mit enthaltenem 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!
    }
});

Bonus: Sie können den zuletzt angekreuzten Button, die Liste der gesamten Buttons erhalten, und Sie können jeden Button anhand des Indexes damit überprüfen!

1
Nick

Diese Lösung wurde noch nicht so gebucht:

Schritt 0: Erstellen Sie einen CompountButton previousCheckedCompoundButton; als globale Variable.

Schritt 1: Erstellen Sie OnCheckedChangedListener für Optionsfelder

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

Schritt 3: Hinzufügen eines Listeners zu allen Optionsfeldern:

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

Das ist es!! Sie sind fertig.

1
Pankaj

Es gibt nichts, was Sie daran hindert, diese Layoutstruktur zu implementieren (RadioGroup ist tatsächlich eine Unterklasse von LinearLayout), aber Sie sollten es nicht tun. Erstens erstellen Sie eine Struktur mit einer Tiefe von 4 Ebenen (mit einer anderen Layoutstruktur können Sie diese optimieren) und zweitens, wenn Ihre RadioButtons keine direkten Kinder einer RadioGroup ist, funktioniert das einzige in Gruppe ausgewählte Element nicht. Das heißt, wenn Sie eine Radiobutton aus diesem Layout auswählen und dann eine andere RadioButton auswählen, erhalten Sie am Ende zwei RadioButtons statt der zuletzt ausgewählten.

Wenn Sie erklären, was Sie in diesem Layout tun möchten, kann ich Ihnen eine Alternative empfehlen.

1
Luksprog
    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
med.Hamdan

Dies ist eine modifizierte Version der @ Infografnet-Lösung. Es ist einfach und leicht zu bedienen.

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

Einfach kopieren und einfügen

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
Qamar4P

Während dies vielleicht ein älteres Thema ist, möchte ich schnell einfachen hacky Code teilen, den ich geschrieben habe. Es ist nicht für jedermann geeignet und könnte auch etwas verfeinert werden.

Die Situation, um diesen Code zu verwenden?
Dieser Code wendet sich an Personen, die ein Layout der ursprünglichen Frage oder ähnliches haben. In meinem Fall war dies wie folgt. Das war persönlich für einen Dialog, den ich benutzte.

  • LinLayout_Main
    • LinLayout_Row1
      • Bildansicht
      • Radio knopf
    • LinLayout_Row2
      • Bildansicht
      • Radio knopf
    • LinLayout_Row3
      • Bildansicht
      • Radio knopf

Was macht der Code selbst?
Dieser Code wird alle untergeordneten Elemente von "LinLayout_Main" auflisten, und für jedes untergeordnete Element, das ein "LinearLayout" ist, wird diese Ansicht dann für alle RadioButtons aufgelistet.

Es wird einfach das übergeordnete "LinLayout_Main" aussehen und alle RadioButtons finden, die sich in Child LinearLayouts befinden.

MyMethod_ShowDialog
Zeigt ein Dialogfeld mit einer XML-Layout-Datei an und sucht gleichzeitig nach "setOnClickListener" für jede gefundene RadioButton

MyMethod_ClickRadio
Schleifen jedes RadioButton auf die gleiche Weise wie "MyMethod_ShowDialog", aber anstatt "setOnClickListener" festzulegen, wird statt "setChecked (false)" jeder RadioButton gelöscht, und als letzten Schritt wird "checkCheck (false)" auf den Wert gesetzt RadioButton, der das Klickereignis aufgerufen hat.

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

Möglicherweise Fehler, kopiert aus Projekt und umbenannt in Voids/XML/ID

Sie können auch denselben Loop-Typ ausführen, um herauszufinden, welche Elemente geprüft werden

0
Mayhem

Ich gerate in das gleiche Problem, ich muss das Optionsfeld für das Geschlecht verwenden und alle waren mit einem Bild und einem Text versehen, also habe ich versucht, es auf folgende Weise zu lösen.

xML-Datei:

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

In Java -Datei: Ich habe setOnCheckedChangeListener für alle 3 Optionsfelder und die Überschreibungsmethode wie unten erwähnt festgelegt und funktioniert für mich einwandfrei.

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

Dies ist meine Lösung für Kotlin für benutzerdefiniertes Layout mit 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
Edgar Khimich

Wie in den Antworten gezeigt, ist die Lösung ein einfacher benutzerdefinierter Hack. Hier ist meine minimalistische Version in 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 }
}

dann müssen Sie nur etwas in onCreate Ihrer Aktivität oder onViewCreated von Fragment tun:

SimpleRadioGroup(listOf(radio_button_1, radio_button_2, radio_button_3))
0
Achraf Amil