Xamarin.Android实现自定义RadioGroup

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、参考资料

本文就是对以下文章的“翻译”。原文连接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值