我有一个RadioGroup
,我想在两列和五行中将按钮彼此相邻对齐,但我无法实现。我尝试过的事情:
RelativeLayout
-> 外部RadioGroup
-> 内部RadioGroup
。全部RadioButtons
被选中,但我只想选择一个。RadioGroup
: 方向- 跨度,拉伸柱
TableRow
TableLayout
请让我知道如何创建一RadioGroup
列和两列以及其中RadioButtons
的许多列。
我有一个RadioGroup
,我想在两列和五行中将按钮彼此相邻对齐,但我无法实现。我尝试过的事情:
RelativeLayout
-> 外部RadioGroup
-> 内部RadioGroup
。全部RadioButtons
被选中,但我只想选择一个。RadioGroup
: 方向TableRow
TableLayout
请让我知道如何创建一RadioGroup
列和两列以及其中RadioButtons
的许多列。
你可以模拟它RadioGroup
,让它看起来像你只有一个。例如,您有rg1
and rg2
(RadioGroups
方向设置为vertical
(两列))。要设置这些RadioGroups
:
rg1 = (RadioGroup) findViewById(R.id.radioGroup1);
rg2 = (RadioGroup) findViewById(R.id.radioGroup2);
rg1.clearCheck(); // this is so we can start fresh, with no selection on both RadioGroups
rg2.clearCheck();
rg1.setOnCheckedChangeListener(listener1);
rg2.setOnCheckedChangeListener(listener2);
要RadioButton
在RadioGroups
上面的听众中只选择一个,将是:
private OnCheckedChangeListener listener1 = new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
if (checkedId != -1) {
rg2.setOnCheckedChangeListener(null); // remove the listener before clearing so we don't throw that stackoverflow exception(like Vladimir Volodin pointed out)
rg2.clearCheck(); // clear the second RadioGroup!
rg2.setOnCheckedChangeListener(listener2); //reset the listener
Log.e("XXX2", "do the work");
}
}
};
private OnCheckedChangeListener listener2 = new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
if (checkedId != -1) {
rg1.setOnCheckedChangeListener(null);
rg1.clearCheck();
rg1.setOnCheckedChangeListener(listener1);
Log.e("XXX2", "do the work");
}
}
};
要从你那里得到检查RadioButton
,RadioGroups
你可以这样做:
int chkId1 = rg1.getCheckedRadioButtonId();
int chkId2 = rg2.getCheckedRadioButtonId();
int realCheck = chkId1 == -1 ? chkId2 : chkId1;
如果你使用的check()
方法RadioGroup
你必须记得调用clearCheck()
其他的Radiogroup
。
RadioGroup 是从 LinearLayout 扩展而来的。
linearlayout 做不到,所以 RadioGroup 做不到。
为什么不自己实现呢。
使用 RelativeLayout 来布局子视图。并记录子视图的状态。使用 setLevel 来控制状态。
祝你好运!。
如果布局不复杂,最好的方法是使用 Single RelativeLayout 而不是多个 Linear Layouts。
下面是 2 行的代码。第一行有 3 列。第二行一列。
<RadioGroup
android:id="@+id/radio_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="4dp"
android:layout_marginTop="4dp"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.AppCompatRadioButton
android:id="@+id/r1c1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginRight="8dp"
android:gravity="center"
android:text="Row 1 Column1" />
<android.support.v7.widget.AppCompatRadioButton
android:id="@+id/r2c1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/r1c1"
android:layout_gravity="left|center_vertical"
android:layout_marginRight="8dp"
android:layout_weight="1"
android:gravity="left|center_vertical"
android:text="Row 2 Column 1" />
<android.support.v7.widget.AppCompatRadioButton
android:id="@+id/r1c2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="8dp"
android:layout_toRightOf="@id/r1c1"
android:gravity="center"
android:text="Row 1 Column 2"/>
<android.support.v7.widget.AppCompatRadioButton
android:id="@+id/r1c3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="8dp"
android:layout_toRightOf="@id/r1c2"
android:gravity="center"
android:text="Row 1 Column 3" />
</RelativeLayout>
</RadioGroup>
使用 LinearLayout 在 xml 文件中创建 2 个 RadioGroup,每个具有 5 个 RadioButton 并使用 layout_weight 属性将它们并排放置在屏幕上。然后为这些广播组创建监听器,如下所示:
rg1 = (RadioGroup) findViewById(R.id.radiogroup1);
rg2 = (RadioGroup) findViewById(R.id.radiogroup2);
rg1.clearCheck();//this is so we can start fresh, with no selection on both RadioGroups
rg2.clearCheck();
rg1.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
// TODO Auto-generated method stub
if (checkedId != -1) {
fun2();
}
}
});
rg2.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
// TODO Auto-generated method stub
if (checkedId != -1) {
fun1();
}
}
});
fun1() & fun2() 的定义如下:
public void fun1() {
rg1.setOnCheckedChangeListener(null);
rg1.clearCheck();
rg1.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
fun2();
Log.v("Inside fun1","fun2");
}
});
}
public void fun2() {
rg2.setOnCheckedChangeListener(null);
rg2.clearCheck();
rg2.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
// TODO Auto-generated method stub
fun1();
Log.v("Inside fun2","fun1");
}
});
}
我不得不做同样的事情并最终将 TableLayout 和 RadioButtonGroup 组合在一起。我将单选按钮动态添加到 TableRows。这是课程:
public class RadioGroupColumns extends TableLayout implements OnClickListener {
private static final String TAG = "RadioGroupColumns";
private RadioButton activeRadioButton;
private int mCheckedId = -1;
// tracks children radio buttons checked state
private CompoundButton.OnCheckedChangeListener mChildOnCheckedChangeListener;
// when true, mOnCheckedChangeListener discards events
private boolean mProtectFromCheckedChange = false;
private OnCheckedChangeListener mOnCheckedChangeListener;
private PassThroughHierarchyChangeListener mPassThroughListener;
public RadioGroupColumns(Context context) {
super(context);
setOrientation(VERTICAL);
init();
}
public RadioGroupColumns(Context context, AttributeSet attrs) {
super(context, attrs);
Resources res = Resources.getSystem();
int value = 0;
// retrieve selected radio button as requested by the user in the
// XML layout file
TypedArray attributes = null;
try {
attributes = context.obtainStyledAttributes(attrs, getAttributes(context), R.attr.radioButtonStyle, 0);
value = attributes.getResourceId(getAttribute(context), View.NO_ID);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
Log.d("Exception RadioGroupColumns Construct",e.toString());
e.printStackTrace();
}
catch (ClassNotFoundException e) {
Log.d("Exception RadioGroupColumns Construct",e.toString());
e.printStackTrace();
}
if (value != View.NO_ID) {
mCheckedId = value;
}
//hardcode it to vertical
//final int index = attributes.getInt(com.android.internal.R.styleable.RadioGroup_orientation, VERTICAL);
//setOrientation(index);
attributes.recycle();
setOrientation(VERTICAL);
init();
}
@Override
public void onClick(View v) {
if (v instanceof TableRow) {
TableRow row = (TableRow)v;
for (int j=0;j<row.getChildCount();j++) {
if (RadioButton.class.isAssignableFrom(row.getChildAt(j).getClass())) {
((RadioButton) row.getChildAt(j)).setChecked(true);
activeRadioButton = (RadioButton) row.getChildAt(j);
}
}
}
else {
final RadioButton rb = (RadioButton) v;
if (activeRadioButton != null) {
activeRadioButton.setChecked(false);
}
rb.setChecked(true);
activeRadioButton = rb;
}
}
private void init() {
mChildOnCheckedChangeListener = new CheckedStateTracker();
mPassThroughListener = new PassThroughHierarchyChangeListener();
super.setOnHierarchyChangeListener(mPassThroughListener);
}
private int getAttribute(Context con) throws ClassNotFoundException, IllegalArgumentException, IllegalAccessException {
//use reflect to get styleable class.
Field[] alFields = null;
ArrayList<Integer> alInts = new ArrayList<Integer>();
int R_ID = 0;
for (Class c : android.R.class.getClasses()) {
if (c.getName().indexOf("styleable") >= 0) {
alFields = Class.forName( con.getPackageName() + ".R$styleable" ).getFields();
}
}
for (Field f : alFields) {
Log.d("field name",f.getName());
if (f.getName().equals("RadioGroup_checkedButton")) {
int[] ret = (int[])f.get(null);
R_ID = ret[0];
}
}
return R_ID;
}
//gets all RadioGroup R,android.internal.styleable.RadioGroup values
private int[] getAttributes(Context con) throws IllegalAccessException, ClassNotFoundException {
//use reflect to get styleable class.
Field[] alFields = null;
ArrayList<Integer> alInts = new ArrayList<Integer>();
int[] ints = null;
int count = 0;
try {
for (Class c : android.R.class.getClasses()) {
if (c.getName().indexOf("styleable") >= 0) {
Log.d("get Class Name Outer", c.getName());
//use reflection to access the resource class
alFields = Class.forName( con.getPackageName() + ".R$styleable" ).getFields();
}
}
if (alFields != null)
{
Log.d("field numbers size", String.valueOf(alFields.length));
for (Field field : alFields) {
Class<?> targetType = field.getType();
Log.d("field type", field.getType().toString());
if (targetType.equals(Integer.TYPE) && targetType.isPrimitive()) {
//alInts.add((Integer)field);
Object objectValue = (Integer)field.getInt(null);
//Object objectValue = (Integer)targetType.newInstance();
alInts.add((Integer)objectValue);
count++;
}
ints = new int[count];
for (int i=0;i<alInts.size();i++) {
ints[i] = alInts.get(i);
}
}
}
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
return ints;
}
public void check(int id) {
// don't even bother
if (id != -1 && (id == mCheckedId)) {
return;
}
if (mCheckedId != -1) {
setCheckedStateForView(mCheckedId, false);
}
if (id != -1) {
setCheckedStateForView(id, true);
}
activeRadioButton = (RadioButton) findViewById(id);
activeRadioButton.setChecked(true);
setCheckedId(id);
}
public void setOnCheckedChangeListener(RadioGroupColumns.OnCheckedChangeListener onCheckedChangeListener) {
mOnCheckedChangeListener = (OnCheckedChangeListener) onCheckedChangeListener;
}
private void setCheckedId(int id) {
mCheckedId = id;
if (mOnCheckedChangeListener != null) {
mOnCheckedChangeListener.onCheckedChanged(this, mCheckedId);
}
}
private void setCheckedStateForView(int viewId, boolean checked) {
View checkedView = findViewById(viewId);
if (!RadioButton.class.isAssignableFrom(checkedView.getClass()) && checkedView != null) {
TableRow row = (TableRow) checkedView;
for (int j=0;j<row.getChildCount();j++) {
RadioButton button = (RadioButton) row.getChildAt(j);
if (button.isChecked() && button != null) {
button.setChecked(checked);
}
}
}
if (checkedView != null && checkedView instanceof RadioButton) {
((RadioButton) checkedView).setChecked(checked);
}
}
/*
* (non-Javadoc)
*
* @see android.widget.TableLayout#addView(android.view.View, int,
* android.view.ViewGroup.LayoutParams)
*/
@Override
public void addView(View child, int index,
android.view.ViewGroup.LayoutParams params) {
super.addView(child, index, params);
setChildrenOnClickListener((TableRow) child);
}
/*
* (non-Javadoc)
*
* @see android.widget.TableLayout#addView(android.view.View,
* android.view.ViewGroup.LayoutParams)
*/
@Override
public void addView(View child, android.view.ViewGroup.LayoutParams params) {
super.addView(child, params);
setChildrenOnClickListener((TableRow) child);
}
private void setChildrenOnClickListener(TableRow tr) {
final int c = tr.getChildCount();
for (int i = 0; i < c; i++) {
final View v = tr.getChildAt(i);
if (v instanceof RadioButton) {
v.setOnClickListener(this);
}
}
}
public int getCheckedRadioButtonId() {
if (activeRadioButton != null) {
return activeRadioButton.getId();
}
return -1;
}
public interface OnCheckedChangeListener {
public void onCheckedChanged(RadioGroupColumns group, int checkedId);
}
private class CheckedStateTracker implements CompoundButton.OnCheckedChangeListener {
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
// prevents from infinite recursion
if (mProtectFromCheckedChange) {
return;
}
mProtectFromCheckedChange = true;
if (mCheckedId != -1) {
setCheckedStateForView(mCheckedId, false);
}
mProtectFromCheckedChange = false;
int id = buttonView.getId();
setCheckedId(id);
}
}
private class PassThroughHierarchyChangeListener implements android.view.ViewGroup.OnHierarchyChangeListener {
private android.view.ViewGroup.OnHierarchyChangeListener mOnHierarchyChangeListener;
/**
* {@inheritDoc}
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public void onChildViewAdded(View parent, View child) {
if (parent == RadioGroupColumns.this
&& child instanceof RadioButton) {
int id = child.getId();
// generates an id if it's missing
if (id == View.NO_ID) {
id = View.generateViewId();
child.setId(id);
}
((RadioButton) child).setOnCheckedChangeListener((com.assistek.ediary.RadioButton.OnCheckedChangeListener) mChildOnCheckedChangeListener);
}
if (mOnHierarchyChangeListener != null) {
mOnHierarchyChangeListener.onChildViewAdded(parent, child);
}
}
/**
* {@inheritDoc}
*/
public void onChildViewRemoved(View parent, View child) {
if (parent == RadioGroupColumns.this
&& child instanceof RadioButton) {
((RadioButton) child).setOnCheckedChangeListener(null);
}
if (mOnHierarchyChangeListener != null) {
mOnHierarchyChangeListener.onChildViewRemoved(parent, child);
}
}
}
}
这是将单选按钮添加到扩展单选组的代码:
private void setupRadioButtonAnswers() {
ArrayList<HolderAnswer> listAnswers = GlobalVars.questionHolders[GlobalVars.arrayRowNumber]
.getListAnswers();
ArrayList<ArrayList<HolderAnswer>> listAnswersSorted = new ArrayList<ArrayList<HolderAnswer>>();
ArrayList<TableRow> alTableRows = new ArrayList<TableRow>();
int NumberInColumns = (int) Math.floor(listAnswers.size() / NUMBER_OF_COLUMNS);
// make higher number of answers on the right
if (listAnswers.size() % NUMBER_OF_COLUMNS > 0)
NumberInColumns++;
for (int i = 0; i < NumberInColumns; i++) {
TableRow row = new TableRow(this);
TableRow.LayoutParams lp = new TableRow.LayoutParams(
TableRow.LayoutParams.WRAP_CONTENT);
row.setLayoutParams(lp);
alTableRows.add(row);
}
int count = 0;
// sort by row
/*
* a[0] = "Question 1"
a[1] = "Question 2"
a[2] = "Question 3"
a[3] = "Question 4"
a[4] = "Question 5"
a[5] = "Question 6"
a[6] = "Question 7"
sorted to:
a[0] = "Question 1" a[1] = "Question 5"
a[2] = "Question 2" a[3] = "Question 6"
a[4] = "Question 3" a[5] = "Question 7"
a[6] = "Question 4"
*/
// initialize the ArrayLists in listAnswersSorted
int numRows = listAnswers.size() / NUMBER_OF_COLUMNS + 1;
for (int i = 0; i < numRows; i += 1) {
listAnswersSorted.add(new ArrayList<HolderAnswer>());
}
// calculate column index where the "step" happens
int step = listAnswers.size() % NUMBER_OF_COLUMNS;
// loop through and add elements to listAnswersSorted
int index = 0;
int row = 0;
int col = 0;
while (index < listAnswers.size()) {
listAnswersSorted.get(row).add(listAnswers.get(index));
int rows = col < step ? numRows : numRows - 1;
row += 1;
if (row == rows) {
row = 0;
col += 1;
}
index += 1;
}
row = 0;
int columncount = 1;
for (ArrayList<HolderAnswer> sortedArrayList : listAnswersSorted) {
for (HolderAnswer answer : sortedArrayList) {
final RadioButton button = new RadioButton(this);
button.setTag(answer.getRecID());
button.setId(GlobalVars.getLatestId());
button.setTextColor(Color.BLACK);
GlobalVars.setupText(con, button, answer.getTextID());
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
button.setEnabled(false);
handlerReenableView.sendEmptyMessageDelayed(button.getId(), 1000);
button.setChecked(true);
radioGroup.check(button.getId());
}
});
button.setLayoutParams(new TableRow.LayoutParams(columncount));
alTableRows.get(row).addView(button);
if (columncount==NUMBER_OF_COLUMNS) {
columncount = 1;
radioGroup.addView(alTableRows.get(row));
alTableRows.get(row).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
for(int k=0;k<((TableRow) v).getChildCount();k++) {
TableRow row = (TableRow) v;
for (int l=0;l<row.getChildCount();l++) {
RadioButton tableButton = (RadioButton) row.getChildAt(l);
if (tableButton.isChecked) {
radioGroup.check(tableButton.getId());
}
}
}
}
});
}
else {
columncount++;
}
//if (row=NumberInColumns)
count++;
}
if (count == listAnswers.size()) {
radioGroup.addView(alTableRows.get(row));
}
row++;
}
radioGroup.setOnCheckedChangeListener(new RadioGroupColumns.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroupColumns group, int checkedId) {
Log.d("We're here",String.valueOf(checkedId));
if (checkedId == -1) {
for (int i = 0; i < radioGroup.getChildCount(); i++) {
TableRow row = (TableRow)radioGroup.getChildAt(i);
for (int j=0;j<row.getChildCount();j++) {
if (RadioButton.class.isAssignableFrom(row.getChildAt(j).getClass())) {
((RadioButton) row.getChildAt(j)).setChecked(false);
}
}
}
} else {
for (int i = 0; i < radioGroup.getChildCount(); i++) {
TableRow row = (TableRow)radioGroup.getChildAt(i);
for (int j=0;j<row.getChildCount();j++) {
if (RadioButton.class.isAssignableFrom(row.getChildAt(j).getClass())
&& row.getChildAt(j).getId() != -1) {
((RadioButton) row.getChildAt(j)).setChecked(false);
}
}
}
RadioButton checkedRadioButton = (RadioButton) radioGroup.findViewById(checkedId);
checkedRadioButton.setChecked(true);
Log.d("checkedID onchecked Change()", String.valueOf(radioGroup.getCheckedRadioButtonId()));
}
}
});
}
更新:自从我在这里发布代码以来,我更新了代码。更新的链接在此链接中: https ://github.com/Gavras/MultiLineRadioGroup/blob/master/app/src/main/java/com/whygraphics/multilineradiogroup/MultiLineRadioGroup.java
当我需要多线无线电组时,我做了一些非常小的事情
这是一个扩展 RadioGroup 的自定义视图。
您可以连续选择所需的最大按钮数。它基于 TableLayout,因此它也对齐按钮。一切都记录在案。
/**
* Layout that arranges radio buttons in multiple lines.
* Only one radio button can be checked at the same time.
* <p>
* XML Attributes:
* <p>
* max_in_row:
* A non-negative number that represents the maximum radio buttons in a row,
* 0 for all in one line.
* <p>
* radio_buttons:
* String-array resource reference that represents the texts of the desired radio buttons.
* <p>
* default_button:
* String that represents the text or the index of the radio button to be checked by default.
* The string should be in the following format:
* for text: "text:[text-of-button]" where text-of-button is the text of the button to check.
* for index: "index:[index-of-button]" where index-of-button is the index of the button to check.
* when the prefix omitted, "text:" inserted implicitly.
*/
public class MultiLineRadioGroup extends RadioGroup {
private static final String XML_DEFAULT_BUTTON_PREFIX_INDEX = "index:";
private static final String XML_DEFAULT_BUTTON_PREFIX_TEXT = "text:";
private static final int DEF_VAL_MAX_IN_ROW = 0;
private OnCheckedChangeListener mOnCheckedChangeListener;
private int mMaxInRow;
// all buttons are stored in table layout
private TableLayout mTableLayout;
// list to store all the buttons
private List<RadioButton> mRadioButtons;
// the checked button
private RadioButton checkedButton;
/**
* Creates a new MultiLineRadioGroup for the given context.
*
* @param context the application environment
*/
public MultiLineRadioGroup(Context context) {
super(context);
init(null);
}
/**
* Creates a new MultiLineRadioGroup for the given context
* and with the specified set attributes.
*
* @param context the application environment
* @param attrs a collection of attributes
*/
public MultiLineRadioGroup(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
// initializes the layout
private void init(AttributeSet attrs) {
mRadioButtons = new ArrayList<>();
mTableLayout = getTableLayout();
addView(mTableLayout);
if (attrs != null)
initAttrs(attrs);
}
// initializes the layout with the specified attributes
private void initAttrs(AttributeSet attrs) {
TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(
attrs, R.styleable.multi_line_radio_group,
0, 0);
try {
// gets and sets the max in row.
setMaxInRow(typedArray.getInt(R.styleable.multi_line_radio_group_max_in_row,
DEF_VAL_MAX_IN_ROW));
// gets and adds the starting buttons
CharSequence[] radioButtonStrings = typedArray.getTextArray(
R.styleable.multi_line_radio_group_radio_buttons);
addButtons(radioButtonStrings);
// gets the default button and checks it if presents.
String string = typedArray.getString(R.styleable.multi_line_radio_group_default_button);
if (string != null)
setDefaultButton(string);
} finally {
typedArray.recycle();
}
}
// checks the default button based on the passed string
private void setDefaultButton(String string) {
final int START_OF_INDEX = 6;
final int START_OF_TEXT = 5;
// the text of the button to check
String buttonToCheck;
if (string.startsWith(XML_DEFAULT_BUTTON_PREFIX_INDEX)) {
String indexString = string.substring(START_OF_INDEX, string.length());
int index = Integer.parseInt(indexString);
if (index < 0 || index >= mRadioButtons.size())
throw new IllegalArgumentException("index must be between 0 to getRadioButtonCount() - 1 [" +
(getRadioButtonCount() - 1) + "]");
buttonToCheck = mRadioButtons.get(index).getText().toString();
} else if (string.startsWith(XML_DEFAULT_BUTTON_PREFIX_TEXT)) {
buttonToCheck = string.substring(START_OF_TEXT, string.length());
} else { // when there is no prefix assumes the string is the text of the button
buttonToCheck = string;
}
check(buttonToCheck);
}
/**
* Returns the table layout to set to this layout.
*
* @return the table layout
*/
protected TableLayout getTableLayout() {
return (TableLayout) LayoutInflater.from(getContext())
.inflate(R.layout.table_layout, this, false);
}
/**
* Returns the table row to set in this layout.
*
* @return the table row
*/
protected TableRow getTableRow() {
return (TableRow) LayoutInflater.from(getContext())
.inflate(R.layout.table_row, mTableLayout, false);
}
/**
* Returns the radio button to set in this layout.
*
* @return the radio button
*/
protected RadioButton getRadioButton() {
return (RadioButton) LayoutInflater.from(getContext())
.inflate(R.layout.radio_button, null);
}
/**
* Register a callback to be invoked when a radio button is checked.
*
* @param onCheckedChangeListener the listener to attach
*/
public void setOnCheckedChangeListener(OnCheckedChangeListener onCheckedChangeListener) {
this.mOnCheckedChangeListener = onCheckedChangeListener;
}
/**
* Sets the maximum radio buttons in a row, 0 for all in one line
* and arranges the layout accordingly.
*
* @param maxInRow the maximum radio buttons in a row
* @throws IllegalArgumentException if maxInRow is negative
*/
public void setMaxInRow(int maxInRow) {
if (maxInRow < 0)
throw new IllegalArgumentException("maxInRow must not be negative");
this.mMaxInRow = maxInRow;
arrangeButtons();
}
/**
* Adds a view to the layout
* <p>
* Consider using addButtons() instead
*
* @param child the view to add
*/
@Override
public void addView(View child) {
addView(child, -1, child.getLayoutParams());
}
/**
* Adds a view to the layout in the specified index
* <p>
* Consider using addButtons() instead
*
* @param child the view to add
* @param index the index in which to insert the view
*/
@Override
public void addView(View child, int index) {
addView(child, index, child.getLayoutParams());
}
/**
* Adds a view to the layout with the specified width and height.
* Note that for radio buttons the width and the height are ignored.
* <p>
* Consider using addButtons() instead
*
* @param child the view to add
* @param width the width of the view
* @param height the height of the view
*/
@Override
public void addView(View child, int width, int height) {
addView(child, -1, new LinearLayout.LayoutParams(width, height));
}
/**
* Adds a view to the layout with the specified layout params.
* Note that for radio buttons the params are ignored.
* <p>
* Consider using addButtons() instead
*
* @param child the view to add
* @param params the layout params of the view
*/
@Override
public void addView(View child, ViewGroup.LayoutParams params) {
addView(child, -1, params);
}
/**
* Adds a view to the layout in the specified index
* with the specified layout params.
* Note that for radio buttons the params are ignored.
* <p>
* * Consider using addButtons() instead
*
* @param child the view to add
* @param index the index in which to insert the view
* @param params the layout params of the view
*/
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
if (params == null) {
params = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
}
if (child instanceof RadioButton)
addButtons(index, ((RadioButton) child).getText());
else
super.addView(child, index, params);
}
/**
* Adds radio buttons to the layout based on the texts in the radioButtons array.
* Adds them in the last index.
* If radioButtons is null does nothing.
*
* @param radioButtons the texts of the buttons to add
*/
public void addButtons(CharSequence... radioButtons) {
addButtons(-1, radioButtons);
}
/**
* Adds radio buttons to the layout based on the texts in the radioButtons array.
* Adds them in the specified index, -1 for the last index.
* If radioButtons is null does nothing.
*
* @param index the index in which to insert the radio buttons
* @param radioButtons the texts of the buttons to add
* @throws IllegalArgumentException if index is less than -1 or greater than the number of radio buttons
*/
public void addButtons(int index, CharSequence... radioButtons) {
if (index < -1 || index > mRadioButtons.size())
throw new IllegalArgumentException("index must be between -1 to getRadioButtonCount() [" +
getRadioButtonCount() + "]");
if (radioButtons == null)
return;
int realIndex = (index != -1) ? index : mRadioButtons.size();
// adds the buttons to the list
for (CharSequence text : radioButtons)
mRadioButtons.add(realIndex++, createRadioButton(text));
arrangeButtons();
}
// creates a radio button with the specified text
private RadioButton createRadioButton(CharSequence text) {
RadioButton radioButton = getRadioButton();
radioButton.setText(text);
radioButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
checkButton((RadioButton) v);
if (mOnCheckedChangeListener != null)
mOnCheckedChangeListener.onCheckedChanged(MultiLineRadioGroup.this, checkedButton);
}
});
return radioButton;
}
/**
* Removes a view from the layout.
* <p>
* Consider using removeButton().
*
* @param view the view to remove
*/
@Override
public void removeView(View view) {
super.removeView(view);
}
/**
* Removes a view from the layout in the specified index.
* <p>
* Consider using removeButton().
*
* @param index the index from which to remove the view
*/
@Override
public void removeViewAt(int index) {
super.removeViewAt(index);
}
/**
* Removes the specified range of views from the layout.
* <p>
* Consider using removeButtons().
*
* @param start the start index to remove
* @param count the number of views to remove
*/
@Override
public void removeViews(int start, int count) {
super.removeViews(start, count);
}
/**
* Removes all the views from the layout.
* <p>
* Consider using removeAllButtons().
*/
@Override
public void removeAllViews() {
super.removeAllViews();
}
/**
* Removes a radio button from the layout.
* If the radio button is null does nothing.
*
* @param radioButton the radio button to remove
*/
public void removeButton(RadioButton radioButton) {
if (radioButton == null)
return;
removeButton(radioButton.getText());
}
/**
* Removes a radio button from the layout based on its text.
* Removes the first occurrence.
* If the text is null does nothing.
*
* @param text the text of the radio button to remove
*/
public void removeButton(CharSequence text) {
if (text == null)
return;
int index = -1;
for (int i = 0, len = mRadioButtons.size(); i < len; i++) {
// checks if the texts are equal
if (mRadioButtons.get(i).getText().equals(text)) {
index = i;
break;
}
}
// removes just if the index was found
if (index != -1)
removeButton(index);
}
/**
* Removes the radio button in the specified index from the layout.
*
* @param index the index from which to remove the radio button
* @throws IllegalArgumentException if index is less than 0
* or greater than the number of radio buttons - 1
*/
public void removeButton(int index) {
removeButtons(index, 1);
}
/**
* Removes all the radio buttons in the specified range from the layout.
* Count can be any non-negative number.
*
* @param start the start index to remove
* @param count the number of radio buttons to remove
* @throws IllegalArgumentException if index is less than 0
* or greater than the number of radio buttons - 1
* or count is negative
*/
public void removeButtons(int start, int count) {
if (start < 0 || start >= mRadioButtons.size())
throw new IllegalArgumentException("remove index must be between 0 to getRadioButtonCount() - 1 [" +
(getRadioButtonCount() - 1) + "]");
if (count < 0)
throw new IllegalArgumentException("count must not be negative");
if (count == 0)
return;
int endIndex = start + count - 1;
// if endIndex is not in the range of the radio buttons sets it to the last index
if (endIndex >= mRadioButtons.size())
endIndex = mRadioButtons.size() - 1;
// iterates over the buttons to remove
for (int i = endIndex; i >= start; i--) {
RadioButton radiobutton = mRadioButtons.get(i);
// if the button to remove is the checked button set checkedButton to null
if (radiobutton == checkedButton)
checkedButton = null;
// removes the button from the list
mRadioButtons.remove(i);
}
arrangeButtons();
}
/**
* Removes all the radio buttons from the layout.
*/
public void removeAllButtons() {
removeButtons(0, mRadioButtons.size());
}
// arrange the button in the layout
private void arrangeButtons() {
// iterates over each button and puts it in the right place
for (int i = 0, len = mRadioButtons.size(); i < len; i++) {
RadioButton radioButtonToPlace = mRadioButtons.get(i);
int rowToInsert = (mMaxInRow != 0) ? i / mMaxInRow : 0;
int columnToInsert = (mMaxInRow != 0) ? i % mMaxInRow : i;
// gets the row to insert. if there is no row create one
TableRow tableRowToInsert = (mTableLayout.getChildCount() <= rowToInsert)
? addTableRow() : (TableRow) mTableLayout.getChildAt(rowToInsert);
int tableRowChildCount = tableRowToInsert.getChildCount();
// if there is already a button in the position
if (tableRowChildCount > columnToInsert) {
RadioButton currentButton = (RadioButton) tableRowToInsert.getChildAt(columnToInsert);
// insert the button just if the current button is different
if (currentButton != radioButtonToPlace) {
// removes the current button
removeButtonFromParent(currentButton, tableRowToInsert);
// removes the button to place from its current position
removeButtonFromParent(radioButtonToPlace, (ViewGroup) radioButtonToPlace.getParent());
// adds the button to the right place
tableRowToInsert.addView(radioButtonToPlace, columnToInsert);
}
// if there isn't already a button in the position
} else {
// removes the button to place from its current position
removeButtonFromParent(radioButtonToPlace, (ViewGroup) radioButtonToPlace.getParent());
// adds the button to the right place
tableRowToInsert.addView(radioButtonToPlace, columnToInsert);
}
}
removeRedundancies();
}
// removes the redundant rows and radio buttons
private void removeRedundancies() {
// the number of rows to fit the buttons
int rows;
if (mRadioButtons.size() == 0)
rows = 0;
else if (mMaxInRow == 0)
rows = 1;
else
rows = (mRadioButtons.size() - 1) / mMaxInRow + 1;
int tableChildCount = mTableLayout.getChildCount();
// if there are redundant rows remove them
if (tableChildCount > rows)
mTableLayout.removeViews(rows, tableChildCount - rows);
tableChildCount = mTableLayout.getChildCount();
int maxInRow = (mMaxInRow != 0) ? mMaxInRow : mRadioButtons.size();
// iterates over the rows
for (int i = 0; i < tableChildCount; i++) {
TableRow tableRow = (TableRow) mTableLayout.getChildAt(i);
int tableRowChildCount = tableRow.getChildCount();
int startIndexToRemove;
int count;
// if it is the last row removes all redundancies after the last button in the list
if (i == tableChildCount - 1) {
startIndexToRemove = (mRadioButtons.size() - 1) % maxInRow + 1;
count = tableRowChildCount - startIndexToRemove;
// if it is not the last row removes all the buttons after maxInRow position
} else {
startIndexToRemove = maxInRow;
count = tableRowChildCount - maxInRow;
}
if (count > 0)
tableRow.removeViews(startIndexToRemove, count);
}
}
// adds and returns a table row
private TableRow addTableRow() {
TableRow tableRow = getTableRow();
mTableLayout.addView(tableRow);
return tableRow;
}
// removes a radio button from a parent
private void removeButtonFromParent(RadioButton radioButton, ViewGroup parent) {
if (radioButton == null || parent == null)
return;
parent.removeView(radioButton);
}
/**
* Returns the number of radio buttons.
*
* @return the number of radio buttons
*/
public int getRadioButtonCount() {
return mRadioButtons.size();
}
/**
* Returns the radio button in the specified index.
* If the index is out of range returns null.
*
* @param index the index of the radio button
* @return the radio button
*/
public RadioButton getRadioButtonAt(int index) {
if (index < 0 || index >= mRadioButtons.size())
return null;
return mRadioButtons.get(index);
}
/**
* Checks the radio button with the specified id.
* If the specified id is not found does nothing.
*
* @param id the radio button's id
*/
@Override
public void check(int id) {
if (id <= 0)
return;
for (RadioButton radioButton : mRadioButtons) {
if (radioButton.getId() == id) {
checkButton(radioButton);
return;
}
}
}
/**
* Checks the radio button with the specified text.
* If there is more than one radio button associated with this text
* checks the first radio button.
* If the specified text is not found does nothing.
*
* @param text the radio button's text
*/
public void check(CharSequence text) {
if (text == null)
return;
for (RadioButton radioButton : mRadioButtons) {
if (radioButton.getText().equals(text)) {
checkButton(radioButton);
return;
}
}
}
/**
* Checks the radio button at the specified index.
* If the specified index is invalid does nothing.
*
* @param index the radio button's index
*/
public void checkAt(int index) {
if (index < 0 || index >= mRadioButtons.size())
return;
checkButton(mRadioButtons.get(index));
}
// checks and switches the button with the checkedButton
private void checkButton(RadioButton button) {
if (button == null)
return;
// if the button to check is different from the current checked button
if (button != checkedButton) {
// if exists sets checkedButton to null
if (checkedButton != null)
checkedButton.setChecked(false);
button.setChecked(true);
checkedButton = button;
}
}
/**
* Clears the checked radio button
*/
@Override
public void clearCheck() {
checkedButton.setChecked(false);
checkedButton = null;
}
/**
* Returns the checked radio button's id.
* If no radio buttons are checked returns -1.
*
* @return the checked radio button's id
*/
@Override
public int getCheckedRadioButtonId() {
if (checkedButton == null)
return -1;
return checkedButton.getId();
}
/**
* Returns the checked radio button's index.
* If no radio buttons are checked returns -1.
*
* @return the checked radio button's index
*/
public int getCheckedRadioButtonIndex() {
if (checkedButton == null)
return -1;
return mRadioButtons.indexOf(checkedButton);
}
/**
* Returns the checked radio button's text.
* If no radio buttons are checked returns null.
*
* @return the checked radio buttons's text
*/
public CharSequence getCheckedRadioButtonText() {
if (checkedButton == null)
return null;
return checkedButton.getText();
}
/**
* Interface definition for a callback to be invoked when a radio button is checked.
*/
public interface OnCheckedChangeListener {
/**
* Called when a radio button is checked.
*
* @param group the MultiLineRadioGroup that stores the radio button
* @param button the radio button that was checked
*/
void onCheckedChanged(MultiLineRadioGroup group, RadioButton button);
}
}
值/attrs.xml 文件:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="multi_line_radio_group">
<attr name="max_in_row" format="integer" />
<attr name="radio_buttons" format="reference" />
<attr name="default_button" format="string" />
</declare-styleable>
</resources>
R.layout.table_layout:
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/table_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:stretchColumns="*" />
R.layout.table_row:
<?xml version="1.0" encoding="utf-8"?>
<TableRow xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/table_row"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
R.layout.radio_button:(您可以在此处更改文本大小)
<?xml version="1.0" encoding="utf-8"?>
<RadioButton xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/radio_button"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="@dimen/radio_button_text_size" />
使用 xml 中的此布局的示例:
<?xml version="1.0" encoding="utf-8"?>
<[package].MultiLineRadioGroup xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:multi_line_radio_group="http://schemas.android.com/apk/res-auto"
android:id="@+id/multi_line_radio_group"
android:layout_width="match_parent"
android:layout_height="match_parent"
multi_line_radio_group:default_button="@string/defaultText"
multi_line_radio_group:max_in_row="@integer/radio_button_max_in_row"
multi_line_radio_group:radio_buttons="@array/radio_buttons" />
我创建了自己的 RadioGridLayout,其中包括 RadioGroup 代码并扩展了 GridLayout。您可以复制此代码。对我来说工作得很好。在您可以在 xml 中使用此布局之后。并自定义网格布局。
对于 R.styleable.RadioGridLayout_checked 我使用了这样的代码:
<resources>
<declare-styleable name="RadioGridLayout">
<attr name="checked" format="integer" />
</declare-styleable>
</resources>
public class RadioGridLayout extends GridLayout {
private int mCheckedId = -1;
private CompoundButton.OnCheckedChangeListener mChildOnCheckedChangeListener;
private boolean mProtectFromCheckedChange = false;
private OnCheckedChangeListener mOnCheckedChangeListener;
private PassThroughHierarchyChangeListener mPassThroughListener;
private void setCheckedId(@IdRes int id) {
mCheckedId = id;
if (mOnCheckedChangeListener != null) {
mOnCheckedChangeListener.onCheckedChanged(this, mCheckedId);
}
AutofillManager afm = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
afm = getContext().getSystemService(AutofillManager.class);
}
if (afm != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
afm.notifyValueChanged(this);
}
}
}
public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
mOnCheckedChangeListener = listener;
}
public interface OnCheckedChangeListener {
void onCheckedChanged(RadioGridLayout group, @IdRes int checkedId);
}
private int mInitialCheckedId = View.NO_ID;
public RadioGridLayout(Context context) {
super(context);
setOrientation(VERTICAL);
init();
}
public RadioGridLayout(Context context, AttributeSet attrs) {
super(context, attrs);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (getImportantForAutofill() == IMPORTANT_FOR_AUTOFILL_AUTO) {
setImportantForAutofill(IMPORTANT_FOR_AUTOFILL_YES);
}
}
TypedArray attributes = context.obtainStyledAttributes(
attrs,
R.styleable.RadioGridLayout,
R.attr.radioButtonStyle, 0);
int value = attributes.getResourceId(R.styleable.RadioGridLayout_checked, View.NO_ID);
if (value != View.NO_ID) {
mCheckedId = value;
mInitialCheckedId = value;
}
attributes.recycle();
init();
}
private void init() {
mChildOnCheckedChangeListener = new CheckedStateTracker();
mPassThroughListener = new PassThroughHierarchyChangeListener();
super.setOnHierarchyChangeListener(mPassThroughListener);
}
@Override
public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
mPassThroughListener.mOnHierarchyChangeListener = listener;
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
if (mCheckedId != -1) {
mProtectFromCheckedChange = true;
setCheckedStateForView(mCheckedId, true);
mProtectFromCheckedChange = false;
setCheckedId(mCheckedId);
}
}
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
if (child instanceof RadioButton) {
final RadioButton button = (RadioButton) child;
if (button.isChecked()) {
mProtectFromCheckedChange = true;
if (mCheckedId != -1) {
setCheckedStateForView(mCheckedId, false);
}
mProtectFromCheckedChange = false;
setCheckedId(button.getId());
}
}
super.addView(child, index, params);
}
public void check(@IdRes int id) {
if (id != -1 && (id == mCheckedId)) {
return;
}
if (mCheckedId != -1) {
setCheckedStateForView(mCheckedId, false);
}
if (id != -1) {
setCheckedStateForView(id, true);
}
setCheckedId(id);
}
private void setCheckedStateForView(int viewId, boolean checked) {
View checkedView = findViewById(viewId);
if (checkedView != null && checkedView instanceof RadioButton) {
((RadioButton) checkedView).setChecked(checked);
}
}
@IdRes
public int getCheckedRadioButtonId() {
return mCheckedId;
}
public void clearCheck() {
check(-1);
}
@Override
public GridLayout.LayoutParams generateLayoutParams(AttributeSet attrs) {
return new GridLayout.LayoutParams(getContext(), attrs);
}
@Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p instanceof RadioGroup.LayoutParams;
}
@Override
protected GridLayout.LayoutParams generateDefaultLayoutParams() {
return new LayoutParams();
}
@Override
public CharSequence getAccessibilityClassName() {
return RadioGroup.class.getName();
}
public static class LayoutParams extends GridLayout.LayoutParams {
public LayoutParams(Spec rowSpec, Spec columnSpec) {
super(rowSpec, columnSpec);
}
public LayoutParams() {
super();
}
public LayoutParams(ViewGroup.LayoutParams params) {
super(params);
}
public LayoutParams(MarginLayoutParams params) {
super(params);
}
public LayoutParams(GridLayout.LayoutParams source) {
super(source);
}
public LayoutParams(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void setBaseAttributes(TypedArray a,
int widthAttr, int heightAttr) {
if (a.hasValue(widthAttr)) {
width = a.getLayoutDimension(widthAttr, "layout_width");
} else {
width = WRAP_CONTENT;
}
if (a.hasValue(heightAttr)) {
height = a.getLayoutDimension(heightAttr, "layout_height");
} else {
height = WRAP_CONTENT;
}
}
}
private class CheckedStateTracker implements CompoundButton.OnCheckedChangeListener {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (mProtectFromCheckedChange) {
return;
}
mProtectFromCheckedChange = true;
if (mCheckedId != -1) {
setCheckedStateForView(mCheckedId, false);
}
mProtectFromCheckedChange = false;
int id = buttonView.getId();
setCheckedId(id);
}
}
private class PassThroughHierarchyChangeListener implements
ViewGroup.OnHierarchyChangeListener {
private ViewGroup.OnHierarchyChangeListener mOnHierarchyChangeListener;
@Override
public void onChildViewAdded(View parent, View child) {
if (parent == RadioGridLayout.this && child instanceof RadioButton) {
int id = child.getId();
if (id == View.NO_ID) {
id = View.generateViewId();
child.setId(id);
}
((RadioButton) child).setOnCheckedChangeListener(
mChildOnCheckedChangeListener);
}
if (mOnHierarchyChangeListener != null) {
mOnHierarchyChangeListener.onChildViewAdded(parent, child);
}
}
@Override
public void onChildViewRemoved(View parent, View child) {
if (parent == RadioGridLayout.this && child instanceof RadioButton) {
((RadioButton) child).setOnCheckedChangeListener(null);
}
if (mOnHierarchyChangeListener != null) {
mOnHierarchyChangeListener.onChildViewRemoved(parent, child);
}
}
}
@Override
public void onProvideAutofillStructure(ViewStructure structure, int flags) {
super.onProvideAutofillStructure(structure, flags);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
structure.setDataIsSensitive(mCheckedId != mInitialCheckedId);
}
}
@Override
public void autofill(AutofillValue value) {
if (!isEnabled()) return;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (!value.isList()) {
Timber.w(value + " could not be autofilled into " + this);
return;
}
}
int index = 0;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
index = value.getListValue();
}
final View child = getChildAt(index);
if (child == null) {
Timber.w("RadioGroup.autoFill(): no child with index %s", index);
return;
}
check(child.getId());
}
@Override
public int getAutofillType() {
return isEnabled() ? AUTOFILL_TYPE_LIST : AUTOFILL_TYPE_NONE;
}
@Override
public AutofillValue getAutofillValue() {
if (!isEnabled()) return null;
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getId() == mCheckedId) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
return AutofillValue.forList(i);
}
}
}
return null;
}
}
其他几个答案可以正常工作,但比简单情况所需的要复杂得多。如果您只是希望多个 RadioGroup 充当一个并且可以在单击时处理所有决策,那么您可以这样做:
在您的布局 XML 中,将相同的单击处理程序添加到您想要组合的所有RadioButtons:
android:onClick="handleCombinedClick"
然后,让您的点击处理程序看起来像这样:
public void handleCombinedClick(View view) {
// Clear any checks from both groups:
rg1.clearCheck();
rg2.clearCheck();
// Manually set the check in the newly clicked radio button:
((RadioButton) view).setChecked(true);
// Perform any action desired for the new selection:
switch (view.getId()) {
case R.id.radio_button_1:
// do something
break;
case R.id.radio_button_2:
// do something
break;
...
}
}
这还有一个额外的好处,就是可以在同一个地方处理您的所有选择。如果您想将此扩展到 3 个或更多 RadioGroups,那么您只需rgX.clearCheck();
为每个添加的组添加额外的一行。
我确定您的问题现在已经得到解答,但这里有另一种看法。使用此代码,您可以将单选按钮包装到您想要的任何布局中(实际上您根本不需要单选组)。另外我建议使用线性布局来制作您需要的列/行。
我的代码基于@infografnet 和@lostdev(也感谢@Neromancer 的复合按钮建议!)
public class AdvRadioGroup {
public interface OnButtonCheckedListener {
void onButtonChecked(CompoundButton button);
}
private final List<CompoundButton> buttons;
private final View.OnClickListener onClick = new View.OnClickListener() {
@Override
public void onClick(View v) {
setChecked((CompoundButton) v);
}
};
private OnButtonCheckedListener listener;
private CompoundButton lastChecked;
public AdvRadioGroup(View view) {
buttons = new ArrayList<>();
parseView(view);
}
private void parseView(final View view) {
if(view instanceof CompoundButton) {
buttons.add((CompoundButton) view);
view.setOnClickListener(onClick);
} else if(view instanceof ViewGroup) {
final ViewGroup group = (ViewGroup) view;
for (int i = 0; i < group.getChildCount();i++) {
parseView(group.getChildAt(i));
}
}
}
public List<CompoundButton> getButtons() { return buttons; }
public CompoundButton getLastChecked() { return lastChecked; }
public void setChecked(int index) { setChecked(buttons.get(index)); }
public void setChecked(CompoundButton button) {
if(button == lastChecked) return;
for (CompoundButton btn : buttons) {
btn.setChecked(false);
}
button.setChecked(true);
lastChecked = button;
if(listener != null) {
listener.onButtonChecked(button);
}
}
public void setOnButtonCheckedListener(OnButtonCheckedListener listener) { this.listener = listener; }
}
用法(包含监听器):
AdvRadioGroup group = new AdvRadioGroup(findViewById(R.id.YOUR_VIEW));
group.setOnButtonCheckedListener(new AdvRadioGroup.OnButtonCheckedListener() {
@Override
public void onButtonChecked(CompoundButton button) {
// do fun stuff here!
}
});
奖励:您可以获得最后检查的按钮,整个按钮的列表,并且您可以通过索引检查任何按钮!
这就是我在我的 XML 布局上所做的,它工作正常。
<RadioGroup
android:id="@+id/radioGroup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RadioButton
android:id="@+id/radioOwner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:buttonTint="@color/login_button_color"
android:fontFamily="@font/rnhousesans_regular"
android:text="Owner"
android:textColor="@color/colorPrimary" />
<RadioButton
android:id="@+id/radioLivingParents"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:buttonTint="@color/login_button_color"
android:fontFamily="@font/rnhousesans_regular"
android:text="Living with parents"
android:textColor="@color/colorPrimary" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RadioButton
android:id="@+id/radioTenant"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:buttonTint="@color/login_button_color"
android:fontFamily="@font/rnhousesans_regular"
android:text="Tenant"
android:textColor="@color/colorPrimary" />
<RadioButton
android:id="@+id/radioOther"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:buttonTint="@color/login_button_color"
android:fontFamily="@font/rnhousesans_regular"
android:text="Other"
android:textColor="@color/colorPrimary" />
</LinearLayout>
</RadioGroup>
您可以在 RadioGroup 中使用嵌套的 GridLayout,尽管您将失去 RadioGroup 的主要属性来管理 RadioButtons:例如单项选择。RadioButtons 应该是直接的孩子。
<RadioGroup
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<GridLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:columnCount="2"
>
<androidx.appcompat.widget.AppCompatRadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Text 1"
/>
<androidx.appcompat.widget.AppCompatRadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Text 2"
/>
<androidx.appcompat.widget.AppCompatRadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Text 3"
/>
<androidx.appcompat.widget.AppCompatRadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Text 4"
/>
<androidx.appcompat.widget.AppCompatRadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Text 5"
/>
</GridLayout>
</RadioGroup>
此解决方案用于在单击主体内处理单击
xml:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="2">
<RadioGroup
android:id="@+id/radioGroup_action_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:layout_weight="1"
android:orientation="vertical">
<RadioButton
android:id="@+id/radio_a"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/a"
android:textColor="@color/textColor"
/>
<RadioButton
android:id="@+id/radio_b"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/b"
android:textColor="@color/textColor" />
<RadioButton
android:id="@+id/radio_c"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/c"
android:textColor="@color/textColor" />
</RadioGroup>
<RadioGroup
android:id="@+id/radioGroup_action_2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:layout_weight="1"
android:orientation="vertical">
<RadioButton
android:id="@+id/radio_d"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="@string/d"
android:textColor="@color/textColor" />
<RadioButton
android:id="@+id/radio_e"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/e"
android:textColor="@color/textColor" />
<RadioButton
android:id="@+id/f"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/f"
android:textColor="@color/textColor" />
</RadioGroup>
</LinearLayout>
代码 :
private var isChecking = true
mBinding.radioGroupAction1.setOnCheckedChangeListener { radioGroup, i ->
if (i != -1 && isChecking) {
isChecking = false
mBinding.radioGroupAction2.clearCheck()
}
isChecking = true
when (i) {
R.id.a -> {
Log.e("radioGroupAction:", "a")
}
R.id.b -> {
Log.e("radioGroupAction:", "b")
}
R.id.c -> {
Log.e("radioGroupAction:", "c")
}
}
}
mBinding.radioGroupAction2.setOnCheckedChangeListener { radioGroup, i ->
if (i != -1 && isChecking) {
isChecking = false
mBinding.radioGroupAction1.clearCheck()
}
isChecking = true
when (i) {
R.id.d -> {
Log.e("radioGroupAction:", "d")
}
R.id.e -> {
Log.e("radioGroupAction:", "e")
}
R.id.f -> {
Log.e("radioGroupAction:", "f")
}
}
}
祝你好运