Saya bertanya-tanya apakah mungkin untuk mengelompokkan masing-masing RadioButton
dalam satu RadioGroup
pemeliharaan unik dengan struktur yang sama. Struktur saya terlihat seperti ini:
- LinearLayout_main
- LinearLayout_1
- RadioButton1
- LinearLayout_2
- RadioButton2
- LinearLayout_3
- RadioButton3
- LinearLayout_1
Seperti yang Anda lihat, sekarang masing RadioButton
- masing adalah anak yang berbeda LinearLayout
. Saya mencoba menggunakan struktur di bawah ini, tetapi tidak berhasil:
- Radiogroup
- LinearLayout_main
- LinearLayout_1
- RadioButton1
- LinearLayout_2
- RadioButton2
- LinearLayout_3
- RadioButton3
- LinearLayout_1
- LinearLayout_main
android
radio-button
android-linearlayout
radio-group
marcoqf73.dll
sumber
sumber
Jawaban:
Tampaknya orang-orang baik di Google / Android berasumsi bahwa saat Anda menggunakan RadioButtons, Anda tidak memerlukan fleksibilitas yang menyertai setiap aspek lain dari sistem UI / tata letak Android. Sederhananya: mereka tidak ingin Anda membuat tata letak bersarang dan tombol radio. Mendesah.
Jadi, Anda harus mengatasi masalah tersebut. Itu berarti Anda harus menerapkan tombol radio sendiri.
Ini tidak terlalu sulit. Di onCreate () Anda, setel RadioButtons Anda dengan onClick () mereka sendiri sehingga ketika diaktifkan, mereka mengaturChecked (true) dan melakukan yang sebaliknya untuk tombol lainnya. Sebagai contoh:
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() }
Ya, saya tahu - cara lama-sekolah. Tapi itu berhasil. Semoga berhasil!
sumber
Gunakan kelas yang saya buat ini. Ini akan menemukan semua anak yang dapat dicentang dalam hierarki Anda.
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)); } } }
sumber
Nah, saya menulis kelas sederhana ini.
Gunakan saja seperti ini:
// add any number of RadioButton resource IDs here GRadioGroup gr = new GRadioGroup(this, R.id.radioButton1, R.id.radioButton2, R.id.radioButton3);
atau
GRadioGroup gr = new GRadioGroup(rb1, rb2, rb3); // where RadioButton rb1 = (RadioButton) findViewById(R.id.radioButton1); // etc.
Anda dapat memanggilnya di onCreate () Aktivitas misalnya. Apa pun yang
RadioButton
Anda klik, yang lain tidak akan dicentang. Juga, tidak masalah, jika beberapaRadioButtons
berada di dalam beberapaRadioGroup
, atau tidak.Inilah kelasnya:
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); } } }; }
sumber
Inilah solusi saya berdasarkan solusi @lostdev dan implementasi
RadioGroup
. Ini adalah RadioGroup yang dimodifikasi untuk bekerja dengan RadioButtons (atau CompoundButtons lainnya) yang bersarang di dalam tata letak anak.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); } } } }
Anda dapat menggunakannya dalam tata letak Anda dengan cara yang sama seperti yang biasa Anda lakukan
RadioGroup
dengan pengecualian bahwa ini juga berfungsi denganRadioButton
tampilan bersarang :<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>
sumber
Solusi ini belum diposting jadi posting:
Langkah 0: Buat
CompoundButton previousCheckedCompoundButton;
sebagai variabel global.Langkah 1: Buat
OnCheckedChangedListener
untuk tombol radioCompoundButton.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; } } };
Langkah 3: tambahkan pendengar ke semua tombol radio:
radioButton1.setOnCheckedChangeListener(onRadioButtonCheckedListener); radioButton2.setOnCheckedChangeListener(onRadioButtonCheckedListener); radioButton3.setOnCheckedChangeListener(onRadioButtonCheckedListener); radioButton4.setOnCheckedChangeListener(onRadioButtonCheckedListener);
Itu dia!! kamu sudah selesai.
sumber
Sigh .. Sungguh disalahkan bahwa Android tidak memiliki fungsi dasar seperti itu.
Diadaptasi dari jawaban @ScottBiggs, berikut kemungkinan cara terpendek untuk melakukannya dengan Kotlin:
var currentSelected = button1 listOf<RadioButton>( button1, button2, button3, ... ).forEach { it.setOnClickListener { _ -> currentSelected.isChecked = false currentSelected = it currentSelected.isChecked = true } }
sumber
Saya membuat dua metode ini untuk mengatasi masalah ini. Yang harus Anda lakukan adalah meneruskan ViewGroup di mana RadioButtons berada (bisa menjadi RadioGroup, LinearLayout, RelativeLayout, dll.) Dan menyetel kejadian OnClick secara eksklusif, yaitu, setiap kali salah satu RadioButtons yang merupakan anak dari ViewGroup ( di setiap tingkat bersarang) dipilih, yang lainnya tidak dipilih. Ini berfungsi dengan sebanyak mungkin tata letak bersarang yang Anda inginkan.
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; } }
Penggunaan di dalam suatu aktivitas akan seperti ini:
ViewGroup parent = findViewById(R.id.radios_parent); Utils.setRadioExclusiveClick(parent);
sumber
Saya telah menulis kelas grup radio saya sendiri yang memungkinkan untuk memuat tombol radio bersarang. Saksikan berikut ini. Jika Anda menemukan bug, beri tahu saya.
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); } }
sumber
Anda perlu melakukan dua hal:
mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
Checkable
.Jadi saya pikir solusi yang lebih baik adalah menerapkan Checkable di dalam LinearLayout batin Anda: (terima kasih kepada daichan4649, dari tautannya, https://gist.github.com/daichan4649/5245378 , saya mengambil semua kode yang ditempel di bawah)
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; }
sumber
Saya menghadapi masalah yang sama karena saya ingin menempatkan 4 tombol radio yang berbeda dalam dua linearlayout yang berbeda dan tata letak ini akan menjadi anak dari grup radio. Untuk mencapai perilaku keinginan di RadioGroup saya telah membebani fungsi addView
Inilah solusinya
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); } } }
sumber
Tidak ada yang menghentikan Anda untuk mengimplementasikan struktur tata letak itu (
RadioGroup
sebenarnya adalah subkelas dariLinearLayout
) tetapi Anda tidak boleh melakukannya. Pertama-tama Anda membuat struktur dengan kedalaman 4 tingkat (menggunakan struktur tata letak lain Anda dapat mengoptimalkan ini) dan kedua, jika AndaRadioButtons
bukan anak langsung dari aRadioGroup
, satu-satunya item yang dipilih dalam grup tidak akan berfungsi. Ini berarti bahwa jika Anda memilihRadiobutton
dari tata letak itu dan kemudian memilih yang lain,RadioButton
Anda akan berakhir dengan dua yangRadioButtons
dipilih, bukan yang terakhir dipilih.Jika Anda menjelaskan apa yang ingin Anda lakukan dalam tata letak itu mungkin saya dapat merekomendasikan Anda alternatif.
sumber
RadioButtons
dan orang tuaRadioGroup
maka ini tidak akan bekerja seperti biasa dan pada dasarnya Anda akan berakhir denganLinearLayout
penuhRadioButtons
.$ 0,02 saya berdasarkan @infografnet dan @lostdev (juga terima kasih @Neromancer atas saran Tombol Gabungan!)
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; } }
Penggunaan (dengan pendengar yang disertakan):
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: Anda bisa mendapatkan tombol centang terakhir, daftar seluruh tombol, dan Anda dapat memeriksa tombol apa pun dengan indeks dengan ini!
sumber
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(); } }); }
sumber
Anda dapat menggunakan kode ekstensi RadioGroup sederhana ini. Jatuhkan tata letak / tampilan / gambar apa pun di dalamnya bersama dengan RadioButtons dan itu akan berfungsi.
Ini berisi callback pilihan yang mengembalikan RadioButton yang dipilih dengan indeksnya dan Anda dapat mengatur pilihan secara terprogram berdasarkan indeks atau 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()); } } }
Gunakan dalam tata letak Anda xml:
<path.to.your.package.EnhancedRadioGroup> Layouts containing RadioButtons/Images/Views and other RadioButtons </path.to.your.package.EnhancedRadioGroup>
Untuk mendaftar ke panggilan balik:
enhancedRadioGroupInstance.setOnSelectionChanged(new EnhancedRadioGroup.OnSelectionChangedListener() { @Override public void onSelectionChanged(RadioButton radioButton, int index) { } });
sumber
Meskipun ini mungkin topik yang lebih lama, saya ingin segera membagikan kode hacky sederhana yang saya tulis .. Ini bukan untuk semua orang dan dapat dilakukan dengan beberapa perbaikan juga ..
Situasi untuk menggunakan kode ini ??
Kode ini untuk orang-orang yang memiliki layout pertanyaan asli atau serupa, dalam kasus saya seperti di bawah ini. Ini secara pribadi untuk Dialog yang saya gunakan.
Apa kode itu sendiri ??
Kode ini akan menghitung setiap Anak dari "LinLayout_Main" dan untuk setiap anak yang merupakan "LinearLayout" kemudian akan menghitung Tampilan tersebut untuk RadioButtons.
Cukup itu akan melihat induk "LinLayout_Main" dan menemukan RadioButtons yang ada di setiap LinearLayouts Anak.
MyMethod_ShowDialog
Akan menampilkan dialog dengan file layout XML sambil juga mencarinya untuk menyetel "setOnClickListener" untuk setiap RadioButton yang ditemukannya
MyMethod_ClickRadio
Akan mengulang setiap RadioButton dengan cara yang sama seperti "MyMethod_ShowDialog" tetapi alih-alih menyetel "setOnClickListener", ia malah akan "setChecked (false)" untuk menghapus setiap RadioButton dan kemudian sebagai langkah terakhir akan "setChecked (false)" ke RadioButton yang yang disebut acara klik.
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); }
Mungkin ada bug, disalin dari proyek dan berganti nama menjadi Voids / XML / ID
Anda juga dapat menjalankan tipe loop yang sama untuk mengetahui item mana yang diperiksa
sumber
Ini adalah versi modifikasi dari solusi @ Infografnet. Sederhana dan mudah digunakan.
RadioGroupHelper group = new RadioGroupHelper(this,R.id.radioButton1,R.id.radioButton2); group.radioButtons.get(0).performClick(); //programmatically
Cukup salin dan tempel
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); } }; }
sumber
Seperti yang ditunjukkan dalam jawaban, solusinya adalah peretasan khusus sederhana. Ini versi minimalis saya di 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 } }
maka Anda hanya perlu melakukan sesuatu seperti itu di onCreate aktivitas Anda atau onViewCreated fragmen:
SimpleRadioGroup(listOf(radio_button_1, radio_button_2, radio_button_3))
sumber
Ini adalah solusi saya di Kotlin untuk tata letak khusus dengan RadioButton di dalamnya.
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 } } }
sumber
Saya mengalami masalah yang sama, saya harus menggunakan tombol Radio untuk gender dan semuanya dengan gambar dan teks jadi saya mencoba menyelesaikannya dengan cara berikut.
file 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>
Dalam file java: Saya mengatur setOnCheckedChangeListener pada semua 3 tombol radio dan metode override seperti yang disebutkan di bawah ini dan berfungsi dengan baik untuk saya.
@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; } }
sumber
MixedCompoundButtonGroup melakukannya untuk Anda!
MixedCompoundButtonGroup intinya
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!!) }
sumber