1、背景说明
RadioGroup在使用过程中,若RadioButton较多,容易出现排版问题(一行显示不下,并且不自动换行),导致一些问题。
网上的资料一般是自定义一个RadioGroup控件。在Xamarin.Android中的实现如下.
2、具体实现
using Android.Content;
using Android.Util;
using Android.Views;
using Android.Widget;
using System;
namespace DoctorWorkstationApp.Controls
{
public class CGRadioGroup : RadioGroup
{
private static string TAG = "RadioGroupEx";
public CGRadioGroup(Context context) : base(context){}
public CGRadioGroup(Context context, IAttributeSet attrs) : base(context, attrs){}
protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int widthSize = MeasureSpec.GetSize(widthMeasureSpec);
var widthMode = MeasureSpec.GetMode(widthMeasureSpec);
int heightSize = MeasureSpec.GetSize(heightMeasureSpec);
var heightMode = MeasureSpec.GetMode(heightMeasureSpec);
MeasureChildren(widthMeasureSpec, heightMeasureSpec);
//最大的宽
int maxWidth = 0;
//累计的高
int totalHeight = 0;
//当前这一行的累计行宽
int lineWidth = 0;
//当前这行的最大行高
int maxLineHeight = 0;
//用于记录换行前的行宽和行高
int oldHeight;
int oldWidth;
int count = ChildCount;
//假设 widthMode和heightMode都是AT_MOST
for (int i = 0; i < count; i++)
{
View child =GetChildAt(i);
MarginLayoutParams cgparams=(MarginLayoutParams)child.LayoutParameters;
//得到这一行的最高
oldHeight = maxLineHeight;
//当前最大宽度
oldWidth = maxWidth;
int deltaX = child.MeasuredWidth + cgparams.LeftMargin + cgparams.RightMargin;
if (lineWidth + deltaX + PaddingLeft + PaddingRight > widthSize)
{//如果折行,height增加
//和目前最大的宽度比较,得到最宽。不能加上当前的child的宽,所以用的是oldWidth
maxWidth = Math.Max(lineWidth, oldWidth);
//重置宽度
lineWidth = deltaX;
//累加高度
totalHeight += oldHeight;
//重置行高,当前这个View,属于下一行,因此当前最大行高为这个child的高度加上margin
maxLineHeight = child.MeasuredHeight + cgparams.TopMargin + cgparams.BottomMargin;
Log.Verbose(TAG, "maxHeight:" + totalHeight + "---" + "maxWidth:" + maxWidth);
}
else
{
//不换行,累加宽度
lineWidth += deltaX;
//不换行,计算行最高
int deltaY = child.MeasuredHeight + cgparams.TopMargin + cgparams.BottomMargin;
maxLineHeight = Math.Max(maxLineHeight, deltaY);
}
if (i == count - 1)
{
//前面没有加上下一行的搞,如果是最后一行,还要再叠加上最后一行的最高的值
totalHeight += maxLineHeight;
//计算最后一行和前面的最宽的一行比较
maxWidth = Math.Max(lineWidth, oldWidth);
}
}
//加上当前容器的padding值
maxWidth += PaddingLeft + PaddingRight;
totalHeight += PaddingTop + PaddingBottom;
SetMeasuredDimension(widthMode == MeasureSpecMode.Exactly ? widthSize : maxWidth,
heightMode == MeasureSpecMode.Exactly ? heightSize : totalHeight);
}
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
int count = ChildCount;
//pre为前面所有的child的相加后的位置
int preLeft = PaddingLeft;
int preTop = PaddingTop;
//记录每一行的最高值
int maxHeight = 0;
for (int i = 0; i < count; i++)
{
View child = GetChildAt(i);
MarginLayoutParams cgparams = (MarginLayoutParams)child.LayoutParameters;
//r-l为当前容器的宽度。如果子view的累积宽度大于容器宽度,就换行。
if (preLeft + cgparams.LeftMargin + child.MeasuredWidth + cgparams.RightMargin + PaddingRight > (r - l)) {
//重置
preLeft = PaddingLeft;
//要选择child的height最大的作为设置
preTop = preTop + maxHeight;
maxHeight = GetChildAt(i).MeasuredHeight + cgparams.TopMargin + cgparams.BottomMargin;
} else
{ //不换行,计算最大高度
maxHeight = Math.Max(maxHeight, child.MeasuredHeight + cgparams.TopMargin + cgparams.BottomMargin);
}
//left坐标
int left = preLeft + cgparams.LeftMargin;
//top坐标
int top = preTop + cgparams.TopMargin;
int right = left + child.MeasuredWidth;
int bottom = top + child.MeasuredHeight;
//为子view布局
child.Layout(left, top, right, bottom);
//计算布局结束后,preLeft的值
preLeft += cgparams.LeftMargin + child.MeasuredWidth + cgparams.RightMargin;
}
}
}
}
3、具体使用
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<DoctorWorkstationApp.Controls.CGRadioGroup
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RadioButton android:id="@+id/allOrderTypeRBTN"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="@string/all_order_type" />
<RadioButton android:id="@+id/drugOrderRBTN"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/drug_order_type" />
<RadioButton android:id="@+id/labOrderRBTN"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/lab_order_type" />
<RadioButton android:id="@+id/examOrderRBTN"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/exam_order_type" />
<RadioButton android:id="@+id/operateOrderRBTN"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/operate_order_type" />
<RadioButton android:id="@+id/cureOrderRBTN"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cure_order_type" />
<RadioButton android:id="@+id/foodOrderRBTN"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/food_order_type" />
<RadioButton android:id="@+id/nurseOrderRBTN"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/nurse_order_type" />
<RadioButton android:id="@+id/otherOrderRBTN"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/other_order_type" />
</DoctorWorkstationApp.Controls.CGRadioGroup>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Switch
android:id="@+id/orderValidSwitch"
android:layout_marginLeft="10dp"
android:text="@string/order_is_valid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:textOn="@string/valid_order"
android:textOff="@string/all_orders" />
<Switch
android:id="@+id/orderLFTSwitch"
android:layout_marginLeft="10dp"
android:text="@string/order_is_valid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:textOn="@string/valid_order"
android:textOff="@string/all_orders" />
</LinearLayout>
<ListView
android:minWidth="25px"
android:minHeight="25px"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/ordersListView" />
</LinearLayout>
4、参考资料
本文就是对以下文章的“翻译”。原文连接