Как сгруппировать RadioButton из разных LinearLayouts?
Мне было интересно, можно ли группировать каждый одиночный RadioButton
в уникальном RadioGroup
поддерживая ту же структуру. Моя структура выглядит так:
- LinearLayout_main
- LinearLayout_1
- LinearLayout_2
- LinearLayout_3
Как вы можете видеть, теперь каждый RadioButton
является дочерним по-разному LinearLayout
. Я попытался использовать нижеприведенную структуру, но она не работает:
- RadioGroup
- LinearLayout_main
- LinearLayout_1
- LinearLayout_2
- LinearLayout_3
Ответы
Ответ 1
Похоже, что хорошие люди в Google/Android предполагают, что при использовании RadioButtons вам не нужна гибкость, которая приходит с каждым другим аспектом системы Android UI/layout. Проще говоря: они не хотят, чтобы вы вставляли макеты и переключатели. Вздох.
Итак, вам нужно решить эту проблему. Это означает, что вы должны самостоятельно использовать переключатели.
Это действительно не слишком сложно. В своем onCreate() установите свои RadioButtons со своим onClick(), чтобы при активации они установили CheckCheck (true) и сделали противоположное для других кнопок. Например:
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()
}
Да, я знаю - путь старой школы. Но это работает. Удачи!
Ответ 2
Используйте этот класс, который я создал. Он найдет всех проверяемых детей в вашей иерархии.
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));
}
}
}
Ответ 3
Ну, я написал этот простой класс.
Просто используйте его так:
// add any number of RadioButton resource IDs here
GRadioGroup gr = new GRadioGroup(this,
R.id.radioButton1, R.id.radioButton2, R.id.radioButton3);
или
GRadioGroup gr = new GRadioGroup(rb1, rb2, rb3);
// where RadioButton rb1 = (RadioButton) findViewById(R.id.radioButton1);
// etc.
Вы можете вызвать его в onCreate() Activity, например. Независимо от того, какой RadioButton
вы нажмете, остальные будут отключены. Кроме того, не имеет значения, если некоторые из RadioButtons
находятся внутри некоторого RadioGroup
или нет.
Здесь класс:
package pl.infografnet.GClasses;
import java.util.ArrayList;
import java.util.List;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewParent;
import android.widget.RadioButton;
import android.widget.RadioGroup;
public class GRadioGroup {
List<RadioButton> radios = new ArrayList<RadioButton>();
/**
* Constructor, which allows you to pass number of RadioButton instances,
* making a group.
*
* @param radios
* One RadioButton or more.
*/
public GRadioGroup(RadioButton... radios) {
super();
for (RadioButton rb : radios) {
this.radios.add(rb);
rb.setOnClickListener(onClick);
}
}
/**
* Constructor, which allows you to pass number of RadioButtons
* represented by resource IDs, making a group.
*
* @param activity
* Current View (or Activity) to which those RadioButtons
* belong.
* @param radiosIDs
* One RadioButton or more.
*/
public GRadioGroup(View activity, int... radiosIDs) {
super();
for (int radioButtonID : radiosIDs) {
RadioButton rb = (RadioButton)activity.findViewById(radioButtonID);
if (rb != null) {
this.radios.add(rb);
rb.setOnClickListener(onClick);
}
}
}
/**
* This occurs everytime when one of RadioButtons is clicked,
* and deselects all others in the group.
*/
OnClickListener onClick = new OnClickListener() {
@Override
public void onClick(View v) {
// let 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 select currently clicked RadioButton
if (v.getClass().equals(RadioButton.class)) {
RadioButton rb = (RadioButton) v;
rb.setChecked(true);
}
}
};
}
Ответ 4
Вот мое решение, основанное на решении @lostdev и реализации RadioGroup
. Это RadioGroup, модифицированная для работы с RadioButton (или другими CompoundButtons), которые вложены в дочерние макеты.
import android.content.Context;
import android.os.Build;
import android.support.annotation.IdRes;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import java.util.concurrent.atomic.AtomicInteger;
/**
* This class is a replacement for android RadioGroup - it supports
* child layouts which standard RadioGroup doesn't.
*/
public class RecursiveRadioGroup extends LinearLayout {
public interface OnCheckedChangeListener {
void onCheckedChanged(RecursiveRadioGroup group, @IdRes int checkedId);
}
/**
* For generating unique view IDs on API < 17 with {@link #generateViewId()}.
*/
private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
private CompoundButton checkedView;
private CompoundButton.OnCheckedChangeListener childOnCheckedChangeListener;
/**
* When this flag is true, onCheckedChangeListener discards events.
*/
private boolean mProtectFromCheckedChange = false;
private OnCheckedChangeListener onCheckedChangeListener;
private PassThroughHierarchyChangeListener mPassThroughListener;
public RecursiveRadioGroup(Context context) {
super(context);
setOrientation(HORIZONTAL);
init();
}
public RecursiveRadioGroup(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public RecursiveRadioGroup(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
childOnCheckedChangeListener = new CheckedStateTracker();
mPassThroughListener = new PassThroughHierarchyChangeListener();
super.setOnHierarchyChangeListener(mPassThroughListener);
}
@Override
public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
mPassThroughListener.mOnHierarchyChangeListener = listener;
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
// checks the appropriate radio button as requested in the XML file
if (checkedView != null) {
mProtectFromCheckedChange = true;
setCheckedStateForView(checkedView, true);
mProtectFromCheckedChange = false;
setCheckedView(checkedView);
}
}
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
parseChild(child);
super.addView(child, index, params);
}
private void parseChild(final View child) {
if (child instanceof CompoundButton) {
final CompoundButton checkable = (CompoundButton) child;
if (checkable.isChecked()) {
mProtectFromCheckedChange = true;
if (checkedView != null) {
setCheckedStateForView(checkedView, false);
}
mProtectFromCheckedChange = false;
setCheckedView(checkable);
}
} else if (child instanceof ViewGroup) {
parseChildren((ViewGroup) child);
}
}
private void parseChildren(final ViewGroup child) {
for (int i = 0; i < child.getChildCount(); i++) {
parseChild(child.getChildAt(i));
}
}
/**
* <p>Sets the selection to the radio button whose identifier is passed in
* parameter. Using -1 as the selection identifier clears the selection;
* such an operation is equivalent to invoking {@link #clearCheck()}.</p>
*
* @param view the radio button to select in this group
* @see #getCheckedItemId()
* @see #clearCheck()
*/
public void check(CompoundButton view) {
if(checkedView != null) {
setCheckedStateForView(checkedView, false);
}
if(view != null) {
setCheckedStateForView(view, true);
}
setCheckedView(view);
}
private void setCheckedView(CompoundButton view) {
checkedView = view;
if(onCheckedChangeListener != null) {
onCheckedChangeListener.onCheckedChanged(this, checkedView.getId());
}
}
private void setCheckedStateForView(View checkedView, boolean checked) {
if (checkedView != null && checkedView instanceof CompoundButton) {
((CompoundButton) checkedView).setChecked(checked);
}
}
/**
* <p>Returns the identifier of the selected radio button in this group.
* Upon empty selection, the returned value is -1.</p>
*
* @return the unique id of the selected radio button in this group
* @attr ref android.R.styleable#RadioGroup_checkedButton
* @see #check(CompoundButton)
* @see #clearCheck()
*/
@IdRes
public int getCheckedItemId() {
return checkedView.getId();
}
public CompoundButton getCheckedItem() {
return checkedView;
}
/**
* <p>Clears the selection. When the selection is cleared, no radio button
* in this group is selected and {@link #getCheckedItemId()} returns
* null.</p>
*
* @see #check(CompoundButton)
* @see #getCheckedItemId()
*/
public void clearCheck() {
check(null);
}
/**
* <p>Register a callback to be invoked when the checked radio button
* changes in this group.</p>
*
* @param listener the callback to call on checked state change
*/
public void setOnCheckedChangeListener(RecursiveRadioGroup.OnCheckedChangeListener listener) {
onCheckedChangeListener = listener;
}
/**
* Generate a value suitable for use in {@link #setId(int)}.
* This value will not collide with ID values generated at build time by aapt for R.id.
*
* @return a generated ID value
*/
public static int generateViewId() {
for (; ; ) {
final int result = sNextGeneratedId.get();
// aapt-generated IDs have the high byte nonzero; clamp to the range under that.
int newValue = result + 1;
if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0.
if (sNextGeneratedId.compareAndSet(result, newValue)) {
return result;
}
}
}
private class CheckedStateTracker implements CompoundButton.OnCheckedChangeListener {
@Override
public void onCheckedChanged(CompoundButton view, boolean b) {
if (mProtectFromCheckedChange) {
return;
}
mProtectFromCheckedChange = true;
if (checkedView != null) {
setCheckedStateForView(checkedView, false);
}
mProtectFromCheckedChange = false;
int id = view.getId();
setCheckedView(view);
}
}
private class PassThroughHierarchyChangeListener implements OnHierarchyChangeListener {
private OnHierarchyChangeListener mOnHierarchyChangeListener;
@Override
public void onChildViewAdded(View parent, View child) {
if (child instanceof CompoundButton) {
int id = child.getId();
if (id == View.NO_ID) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
child.setId(generateViewId());
} else {
child.setId(View.generateViewId());
}
}
((CompoundButton) child).setOnCheckedChangeListener(childOnCheckedChangeListener);
if (mOnHierarchyChangeListener != null) {
mOnHierarchyChangeListener.onChildViewAdded(parent, child);
}
} else if(child instanceof ViewGroup) {
// View hierarchy seems to be constructed from the bottom up,
// so all child views are already added. That why we
// manually call the listener for all children of ViewGroup.
for(int i = 0; i < ((ViewGroup) child).getChildCount(); i++) {
onChildViewAdded(child, ((ViewGroup) child).getChildAt(i));
}
}
}
@Override
public void onChildViewRemoved(View parent, View child) {
if (child instanceof RadioButton) {
((CompoundButton) child).setOnCheckedChangeListener(null);
}
if (mOnHierarchyChangeListener != null) {
mOnHierarchyChangeListener.onChildViewRemoved(parent, child);
}
}
}
}
Вы можете использовать его в макете так же, как и обычную RadioGroup
за исключением того, что она работает и с вложенными представлениями RadioButton
:
<RecursiveRadioGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<RadioButton
android:id="@+id/rbNotEnoughProfileInfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Not enough profile information"/>
<RadioButton
android:id="@+id/rbNotAGoodFit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Not a good fit"/>
<RadioButton
android:id="@+id/rbDatesNoLongerAvailable"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Dates no longer available"/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical">
<RadioButton
android:id="@+id/rbOther"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Other"/>
<android.support.v7.widget.AppCompatEditText
android:id="@+id/etReason"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/tvMessageError"
android:textSize="15sp"
android:gravity="top|left"
android:hint="Tell us more"
android:padding="16dp"
android:background="@drawable/edit_text_multiline_background"/>
</LinearLayout>
</RecursiveRadioGroup>
Ответ 5
Вздох.. Действительно виноват, что Android не имеет такой основной функциональности.
Адаптировано из ответа @ScottBiggs, вот, возможно, самый короткий способ сделать это с Kotlin:
var currentSelected = button1
listOf<RadioButton>(
button1, button2, button3, ...
).forEach {
it.setOnClickListener { _ ->
currentSelected.isChecked = false
currentSelected = it
currentSelected.isChecked = true
}
}
Ответ 6
Я создал эти два метода для решения этой проблемы. Все, что вам нужно сделать, это передать ViewGroup, где RadioButtons (может быть RadioGroup, LinearLayout, RelativeLayout и т.д.), И она устанавливает события OnClick исключительно, то есть, когда один из RadioButtons, являющийся дочерним элементом ViewGroup ( на любом вложенном уровне), остальные не выбраны. Он работает с большим количеством вложенных макетов, как вам хотелось бы.
public class Utils {
public static void setRadioExclusiveClick(ViewGroup parent) {
final List<RadioButton> radios = getRadioButtons(parent);
for (RadioButton radio: radios) {
radio.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
RadioButton r = (RadioButton) v;
r.setChecked(true);
for (RadioButton r2:radios) {
if (r2.getId() != r.getId()) {
r2.setChecked(false);
}
}
}
});
}
}
private static List<RadioButton> getRadioButtons(ViewGroup parent) {
List<RadioButton> radios = new ArrayList<RadioButton>();
for (int i=0;i < parent.getChildCount(); i++) {
View v = parent.getChildAt(i);
if (v instanceof RadioButton) {
radios.add((RadioButton) v);
} else if (v instanceof ViewGroup) {
List<RadioButton> nestedRadios = getRadioButtons((ViewGroup) v);
radios.addAll(nestedRadios);
}
}
return radios;
}
}
Использование внутри действия будет следующим:
ViewGroup parent = findViewById(R.id.radios_parent);
Utils.setRadioExclusiveClick(parent);
Ответ 7
Я написал свой собственный класс радиогрупп, который позволяет содержать вложенные радиокнопки. Проверьте это. Если вы найдете ошибки, сообщите мне.
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);
}
}
Ответ 8
Вам нужно сделать две вещи:
- Используйте
mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
- Сделайте свой пользовательский вид представления строки
Checkable
.
Поэтому я считаю, что лучшим решением является реализация Checkable внутри вашего LinearLayout: (благодаря daichan4649, по его ссылке, https://gist.github.com/daichan4649/5245378, Я взял весь код, вставленный ниже)
CheckableLayout.java
package daichan4649.test;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Checkable;
import android.widget.LinearLayout;
public class CheckableLayout extends LinearLayout implements Checkable {
private static final int[] CHECKED_STATE_SET = { android.R.attr.state_checked };
public CheckableLayout(Context context) {
super(context, null);
}
public CheckableLayout(Context context, AttributeSet attrs) {
super(context, attrs, 0);
}
public CheckableLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
private boolean checked;
@Override
public boolean isChecked() {
return checked;
}
@Override
public void setChecked(boolean checked) {
if (this.checked != checked) {
this.checked = checked;
refreshDrawableState();
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (child instanceof Checkable) {
((Checkable) child).setChecked(checked);
}
}
}
}
@Override
public void toggle() {
setChecked(!checked);
}
@Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
if (isChecked()) {
mergeDrawableStates(drawableState, CHECKED_STATE_SET);
}
return drawableState;
}
}
inflater_list_column.xml
<?xml version="1.0" encoding="utf-8"?>
<daichan4649.test.CheckableLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/check_area"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical">
<TextView
android:id="@+id/text"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:gravity="center_vertical" />
<RadioButton
android:id="@+id/radio"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false" />
</daichan4649.test.CheckableLayout>
TestFragment.java
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_test, container, false);
// 表示データ
List<String> dataList = new ArrayList<String>();
// 初期選択位置
int initSelectedPosition = 3;
// リスト設定
TestAdapter adapter = new TestAdapter(getActivity(), dataList);
ListView listView = (ListView) view.findViewById(R.id.list);
listView.setAdapter(adapter);
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
listView.setItemChecked(initSelectedPosition, true);
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// 選択状態を要素(checkable)へ反映
Checkable child = (Checkable) parent.getChildAt(position);
child.toggle();
}
});
return view;
}
private static class TestAdapter extends ArrayAdapter<String> {
private LayoutInflater inflater;
public TestAdapter(Context context, List<String> dataList) {
super(context, 0, dataList);
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.inflater_list_column, null);
holder = new ViewHolder();
holder.text = (TextView) convertView.findViewById(R.id.text);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
// bindData
holder.text.setText(getItem(position));
return convertView;
}
}
private static class ViewHolder {
TextView text;
}
Ответ 9
Ничто не мешает вам реализовать эту структуру компоновки (RadioGroup
на самом деле является подклассом LinearLayout
), но вы не должны. Прежде всего, вы создаете структуру 4 уровня в глубину (используя другую структуру макета, которую вы можете оптимизировать), а во-вторых, если ваши RadioButtons
не являются прямыми дочерними элементами RadioGroup
, единственный элемент, выбранный в группе, не будет работать. Это означает, что если вы выберете Radiobutton
из этого макета, а затем выберите другой Radiobutton
, вы получите вместо него два RadioButtons
вместо последнего выбранного.
Если вы объясните, что вы хотите сделать в этом макете, я могу порекомендовать вам альтернативу.
Ответ 10
У меня проблема с той же проблемой, что и я хочу разместить 4 разных переключателя в двух разных linearlayout, и этот макет будет дочерним элементом группы радио. Чтобы добиться поведения желания в RadioGroup, я перегрузил функцию addView
Вот решение
public class AgentRadioGroup extends RadioGroup
{
public AgentRadioGroup(Context context) {
super(context);
}
public AgentRadioGroup(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void onViewAdded(View child) {
if( child instanceof ViewGroup)
{
ViewGroup viewGroup = (ViewGroup) child;
for(int i=0; i<viewGroup.getChildCount(); i++)
{
View subChild = viewGroup.getChildAt(i);
if( subChild instanceof ViewGroup )
{
onViewAdded(subChild);
}
else
{
if (subChild instanceof RadioButton) {
super.onViewAdded(subChild);
}
}
}
}
if (child instanceof RadioButton)
{
super.onViewAdded(child);
}
}
}
Ответ 11
Это решение не было опубликовано так:
Шаг 0: Создайте глобальную переменную CompountButton previousCheckedCompoundButton;
.
Шаг 1: Создайте OnCheckedChangedListener
для радиокнопки
CompoundButton.OnCheckedChangeListener onRadioButtonCheckedListener = new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (!isChecked) return;
if (previousCheckedCompoundButton != null) {
previousCheckedCompoundButton.setChecked(false);
previousCheckedCompoundButton = buttonView;
} else {
previousCheckedCompoundButton = buttonView;
}
}
};
Шаг 3: добавьте прослушиватель ко всем переключателям:
radioButton1.setOnCheckedChangeListener(onRadioButtonCheckedListener);
radioButton2.setOnCheckedChangeListener(onRadioButtonCheckedListener);
radioButton3.setOnCheckedChangeListener(onRadioButtonCheckedListener);
radioButton4.setOnCheckedChangeListener(onRadioButtonCheckedListener);
Вот оно! твоя сделана.
Ответ 12
Мои $0,02 на основе @infografnet и @lostdev (также спасибо @Neromancer для предложения кнопки Compound!)
public class AdvRadioGroup {
public interface OnButtonCheckedListener {
void onButtonChecked(CompoundButton button);
}
private final List<CompoundButton> buttons;
private final View.OnClickListener onClick = new View.OnClickListener() {
@Override
public void onClick(View v) {
setChecked((CompoundButton) v);
}
};
private OnButtonCheckedListener listener;
private CompoundButton lastChecked;
public AdvRadioGroup(View view) {
buttons = new ArrayList<>();
parseView(view);
}
private void parseView(final View view) {
if(view instanceof CompoundButton) {
buttons.add((CompoundButton) view);
view.setOnClickListener(onClick);
} else if(view instanceof ViewGroup) {
final ViewGroup group = (ViewGroup) view;
for (int i = 0; i < group.getChildCount();i++) {
parseView(group.getChildAt(i));
}
}
}
public List<CompoundButton> getButtons() { return buttons; }
public CompoundButton getLastChecked() { return lastChecked; }
public void setChecked(int index) { setChecked(buttons.get(index)); }
public void setChecked(CompoundButton button) {
if(button == lastChecked) return;
for (CompoundButton btn : buttons) {
btn.setChecked(false);
}
button.setChecked(true);
lastChecked = button;
if(listener != null) {
listener.onButtonChecked(button);
}
}
public void setOnButtonCheckedListener(OnButtonCheckedListener listener) { this.listener = listener; }
}
Использование (с включенным слушателем):
AdvRadioGroup group = new AdvRadioGroup(findViewById(R.id.YOUR_VIEW));
group.setOnButtonCheckedListener(new AdvRadioGroup.OnButtonCheckedListener() {
@Override
public void onButtonChecked(CompoundButton button) {
// do fun stuff here!
}
});
Бонус: вы можете получить последнюю отмеченную кнопку, список целых кнопок, и вы можете проверить любую кнопку по индексу с помощью этого!
Ответ 13
В то время как это, возможно, более старая тема, я хотел бы быстро поделиться простым взломанным кодом, который я написал.. Его не для всех и могли бы сделать с некоторой доработкой, а также.
Ситуация для использования этого кода
Этот код предназначен для людей, у которых есть макет оригинального вопроса или подобного, в моем случае это было так, как показано ниже. Это было лично для диалога, который я использовал.
- LinLayout_Main
- LinLayout_Row1
- LinLayout_Row2
- LinLayout_Row3
Что делает сам код?
Этот код будет перечислять когда-либо Child из "LinLayout_Main", а для каждого дочернего элемента, который является "LinearLayout", он будет перечислять этот вид для любых RadioButtons.
Просто он будет выглядеть родительским "LinLayout_Main" и найти любые RadioButtons, которые находятся в любом дочернем LinearLayouts.
MyMethod_ShowDialog
Покажет диалог с файлом макета XML, а также посмотрит, как установить "setOnClickListener" для каждого найденного вами RadioButton.
MyMethod_ClickRadio
Будет ли цикл RadioButton таким же образом "MyMethod_ShowDialog", но вместо установки "setOnClickListener" вместо "setChecked (false)" будет очищен каждый RadioButton, а затем, когда последний шаг будет "setChecked (false)" на RadioButton, который вызвал событие click.
public void MyMethod_ShowDialog(final double tmpLat, final double tmpLng) {
final Dialog dialog = new Dialog(actMain);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(R.layout.layout_dialogXML);
final LinearLayout tmpLayMain = (LinearLayout)dialog.findViewById(R.id.LinLayout_Main);
if (tmpLayMain!=null) {
// Perform look for each child of main LinearLayout
int iChildCount1 = tmpLayMain.getChildCount();
for (int iLoop1=0; iLoop1 < iChildCount1; iLoop1++){
View tmpChild1 = tmpLayMain.getChildAt(iLoop1);
if (tmpChild1 instanceof LinearLayout) {
// Perform look for each LinearLayout child of main LinearLayout
int iChildCount2 = ((LinearLayout) tmpChild1).getChildCount();
for (int iLoop2=0; iLoop2 < iChildCount2; iLoop2++){
View tmpChild2 = ((LinearLayout) tmpChild1).getChildAt(iLoop2);
if (tmpChild2 instanceof RadioButton) {
((RadioButton) tmpChild2).setOnClickListener(new RadioButton.OnClickListener() {
public void onClick(View v) {
MyMethod_ClickRadio(v, dialog);
}
});
}
}
}
}
Button dialogButton = (Button)dialog.findViewById(R.id.LinLayout_Save);
dialogButton.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
dialog.dismiss();
}
});
}
dialog.show();
}
public void MyMethod_ClickRadio(View vRadio, final Dialog dDialog) {
final LinearLayout tmpLayMain = (LinearLayout)dDialog.findViewById(R.id.LinLayout_Main);
if (tmpLayMain!=null) {
int iChildCount1 = tmpLayMain.getChildCount();
for (int iLoop1=0; iLoop1 < iChildCount1; iLoop1++){
View tmpChild1 = tmpLayMain.getChildAt(iLoop1);
if (tmpChild1 instanceof LinearLayout) {
int iChildCount2 = ((LinearLayout) tmpChild1).getChildCount();
for (int iLoop2=0; iLoop2 < iChildCount2; iLoop2++){
View tmpChild2 = ((LinearLayout) tmpChild1).getChildAt(iLoop2);
if (tmpChild2 instanceof RadioButton) {
((RadioButton) tmpChild2).setChecked(false);
}
}
}
}
}
((RadioButton) vRadio).setChecked(true);
}
Там могут быть ошибки, скопированные из проекта и переименованные Voids/XML/ID
Вы также можете запустить цикл того же типа, чтобы узнать, какие элементы отмечены.
Ответ 14
Это модифицированная версия решения @Infografnet. Это простой и удобный в использовании.
RadioGroupHelper group = new RadioGroupHelper(this,R.id.radioButton1,R.id.radioButton2); group.radioButtons.get(0).performClick();//programmatically
Просто скопируйте и вставьте
package com.qamar4p.farmer.ui.custom;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.view.View;
import android.widget.CompoundButton;
import android.widget.RadioButton;
public class RadioGroupHelper {
public List<CompoundButton> radioButtons = new ArrayList<>();
public RadioGroupHelper(RadioButton... radios) {
super();
for (RadioButton rb : radios) {
add(rb);
}
}
public RadioGroupHelper(Activity activity, int... radiosIDs) {
this(activity.findViewById(android.R.id.content),radiosIDs);
}
public RadioGroupHelper(View rootView, int... radiosIDs) {
super();
for (int radioButtonID : radiosIDs) {
add((RadioButton)rootView.findViewById(radioButtonID));
}
}
private void add(CompoundButton button){
this.radioButtons.add(button);
button.setOnClickListener(onClickListener);
}
View.OnClickListener onClickListener = v -> {
for (CompoundButton rb : radioButtons) {
if(rb != v) rb.setChecked(false);
}
};
}
Ответ 15
Как показано в ответах, решение представляет собой простой пользовательский взлом. Вот моя минималистичная версия в Котлине.
import android.widget.RadioButton
class SimpleRadioGroup(private val radioButtons: List<RadioButton>) {
init {
radioButtons.forEach {
it.setOnClickListener { clickedButton ->
radioButtons.forEach { it.isChecked = false }
(clickedButton as RadioButton).isChecked = true
}
}
}
val checkedButton: RadioButton?
get() = radioButtons.firstOrNull { it.isChecked }
}
тогда вам просто нужно сделать что-то подобное в своей деятельности onCreate или фрагмент onViewCreated:
SimpleRadioGroup(listOf(radio_button_1, radio_button_2, radio_button_3))
Ответ 16
Это мое решение на Kotlin для пользовательского макета с RadioButton внутри.
tipInfoContainerFirst.radioButton.isChecked = true
var prevSelected = tipInfoContainerFirst.radioButton
prevSelected.isSelected = true
listOf<RadioButton>(
tipInfoContainerFirst.radioButton,
tipInfoContainerSecond.radioButton,
tipInfoContainerThird.radioButton,
tipInfoContainerForth.radioButton,
tipInfoContainerCustom.radioButton
).forEach {
it.setOnClickListener { _it ->
if(!it.isSelected) {
prevSelected.isChecked = false
prevSelected.isSelected = false
it.radioButton.isSelected = true
prevSelected = it.radioButton
}
}
}
Ответ 17
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();
}
});
}
Ответ 18
Я попал в ту же проблему, я должен использовать кнопку радио для пола, и все были с изображением и текстом, поэтому я попытался решить ее следующим образом.
XML файл:
<RadioGroup
android:layout_marginTop="40dp"
android:layout_marginEnd="23dp"
android:id="@+id/rgGender"
android:layout_width="match_parent"
android:layout_below="@id/tvCustomer"
android:orientation="horizontal"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center_horizontal"
android:layout_weight="1">
<RadioButton
android:id="@+id/rbMale"
android:layout_width="80dp"
android:layout_height="60dp"
android:background="@drawable/male_radio_btn_selector"
android:button="@null"
style="@style/RadioButton.Roboto.20sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Male"
style="@style/TextView.RobotoLight.TxtGrey.18sp"
android:layout_margin="0dp"
android:textSize="@dimen/txtsize_20sp"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center_horizontal"
android:layout_weight="1">
<RadioButton
android:layout_weight="1"
android:gravity="center"
android:id="@+id/rbFemale"
android:layout_width="80dp"
android:layout_height="60dp"
android:button="@null"
android:background="@drawable/female_radio_btn_selector"
style="@style/RadioButton.Roboto.20sp"
android:textColor="@color/light_grey"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Female"
android:layout_margin="0dp"
style="@style/TextView.RobotoLight.TxtGrey.18sp"
android:textSize="@dimen/txtsize_20sp"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center_horizontal"
android:layout_weight="1">
<RadioButton
android:layout_weight="1"
android:gravity="center"
android:id="@+id/rbOthers"
android:layout_width="80dp"
android:layout_height="60dp"
android:button="@null"
android:background="@drawable/other_gender_radio_btn_selector"
style="@style/RadioButton.Roboto.20sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Other"
android:layout_margin="0dp"
style="@style/TextView.RobotoLight.TxtGrey.18sp"
android:textSize="@dimen/txtsize_20sp"/>
</LinearLayout>
</RadioGroup>
В файле Java: я установил setOnCheckedChangeListener на все 3 переключателя и метод переопределения, как упомянуто ниже, и он работает нормально для меня.
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
switch (compoundButton.getId()){
case R.id.rbMale:
if(rbMale.isChecked()){
rbMale.setChecked(true);
rbFemale.setChecked(false);
rbOther.setChecked(false);
}
break;
case R.id.rbFemale:
if(rbFemale.isChecked()){
rbMale.setChecked(false);
rbFemale.setChecked(true);
rbOther.setChecked(false);
}
break;
case R.id.rbOthers:
if(rbOther.isChecked()){
rbMale.setChecked(false);
rbFemale.setChecked(false);
rbOther.setChecked(true);
}
break;
}
}
Ответ 19
Попробуйте этот способ добавить RadioGroup
в LinearLayout
.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<RadioGroup
android:id="@+id/radioGroup1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="1" >
<RadioButton
android:id="@+id/radio0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="RadioButton" />
<RadioButton
android:id="@+id/radio1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RadioButton" />
<RadioButton
android:id="@+id/radio2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RadioButton" />
</RadioGroup>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<RadioGroup
android:id="@+id/radioGroup2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="1" >
<RadioButton
android:id="@+id/radio3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="RadioButton" />
<RadioButton
android:id="@+id/radio4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RadioButton" />
<RadioButton
android:id="@+id/radio5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RadioButton" />
</RadioGroup>
</LinearLayout>
</LinearLayout>