欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

自定义ViewGroup(一)

程序员文章站 2022-06-08 17:34:42
...

初体验和介绍:

目前常用的布局也就那几种,但是相对于android的发展,那几种布局很明显是不够用的,比如说Banner、流式标签布局、侧滑菜单等等,很多都是需要自定义ViewGroup来进行的。
自定义ViewGroup主要是测量自身和子View(onMeasure),然后是放置子View的View,还有一个LayoutParams(用来设置属性)
先来个简单的,直接抄袭鸿洋大神的:Android 手把手教您自定义ViewGroup(一)


public class XyEasyLayout extends ViewGroup {

    public XyEasyLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     * 设置LayoutParams
     * 当前Test只支持margin就行,所以直接使用系统的LayoutParams
     * 指定当前的LayoutParams为MarginLayoutParams
     */
    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(getContext(), attrs);
    }

    /**
     * 测量
     * 主要是测量子View已经自己的宽高
     * 计算所有ChildView的宽度和高度,然后根据ChildView的计算结果,设置自己的宽和高
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        /**
         * 获得此VIewGroup上级容器为其推荐的宽和高,以及计算模式
         */
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
        int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);

        /**
         * 计算出所有ChildView的宽高
         */
        measureChildren(widthMeasureSpec, heightMeasureSpec);

        /**
         * 针对wrap_content
         */

        /**
         * ViewGroup的宽高
         */
        int width = 0;
        int height = 0;

        /**
         * 子View的个数
         */
        int cCount = getChildCount();

        /**
         * 子View的宽高以及 LayoutParams
         */
        int cWidth = 0;
        int cHeight = 0;
        MarginLayoutParams cParams = null;

        /**
         * 计算左边两个ChildView的高度
         */
        int lHeight = 0;

        /**
         * 计算右边两个ChildView的高度
         */
        int rHeight = 0;

        /**
         * 计算上边两个ChildView的宽度
         */
        int tWidth = 0;

        /**
         * 计算下边两个ChildView的宽度
         */
        int bWidth = 0;

        /**
         * 根据ChildView计算出的宽高,以及设置的margin计算容器的宽高,主要是用于容器是wrap_content时
         */
        for (int i = 0; i < cCount; i++) {
            /**
             * 获取子View测量的宽高和LayoutParams
             */
            View childView = getChildAt(i);
            cWidth = childView.getMeasuredWidth();
            cHeight = childView.getMeasuredHeight();
            cParams = (MarginLayoutParams) childView.getLayoutParams();

            /**
             * 上边两个ChildView
             */
            if (i == 0 || i == 1) {
                tWidth += cWidth + cParams.leftMargin + cParams.rightMargin;
            }

            /**
             * 下边两个ChildView
             */
            if (i == 2 || i == 3) {
                bWidth += cWidth + cParams.leftMargin + cParams.rightMargin;
            }

            /**
             * 左边两个ChildView
             */
            if (i == 0 || i == 2) {
                lHeight += cHeight + cParams.topMargin + cParams.bottomMargin;
            }

            /**
             * 右边两个ChildView
             */
            if (i == 1 || i == 3) {
                rHeight += cHeight + cParams.topMargin + cParams.bottomMargin;
            }

        }

        width = Math.max(tWidth, bWidth);
        height = Math.max(lHeight, rHeight);

        /**
         * 如果是wrap_content则使用计算的值
         * 否则:直接设置为父容器计算的值
         */
        setMeasuredDimension(
                (widthMode == MeasureSpec.EXACTLY) ? sizeWidth : width,
                (heightMode == MeasureSpec.EXACTLY) ? sizeHeight : height
        );
    }

    /**
     * 定位
     */
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int cCount = getChildCount();
        int cWidth = 0;
        int cHeight = 0;
        MarginLayoutParams cParams = null;

        /**
         * 遍历所有ChildView,根据他的宽高以及margin进行布局
         */
        for (int i = 0; i < cCount; i++) {
            View childView = getChildAt(i);
            cWidth = childView.getMeasuredWidth();
            cHeight = childView.getMeasuredHeight();
            cParams = (MarginLayoutParams) childView.getLayoutParams();

            int cl = 0, ct = 0, cr = 0, cb = 0;

            switch (i) {
                case 0:
                    cl = cParams.leftMargin;
                    ct = cParams.topMargin;
                    break;
                case 1:
                    cl = getWidth() - cWidth - cParams.rightMargin;
                    ct = cParams.topMargin;
                    break;
                case 2:
                    cl = cParams.leftMargin;
                    ct = getHeight() - cHeight - cParams.bottomMargin;
                    break;
                case 3:
                    cl = getWidth() - cWidth - cParams.rightMargin;
                    ct = getHeight() - cHeight - cParams.bottomMargin;
                    break;
                default:
                    break;
            }
            cr = cl + cWidth;
            cb = cHeight + ct;
            childView.layout(cl, ct, cr, cb);
        }
    }
}

<?xml version="1.0" encoding="utf-8"?>
<com.xiey94.view.viewgroup.XyEasyLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorPrimaryDark"
    android:orientation="vertical">

    <TextView
        android:layout_width="100dip"
        android:layout_height="100dip"
        android:background="@color/colorAccent" />

    <TextView
        android:layout_width="100dip"
        android:layout_height="100dip"
        android:background="@color/colorAccent" />

    <TextView
        android:layout_width="100dip"
        android:layout_height="100dip"
        android:background="@color/colorAccent" />

    <TextView
        android:layout_width="100dip"
        android:layout_height="100dip"
        android:background="@color/colorAccent" />

</com.xiey94.view.viewgroup.XyEasyLayout>

自定义ViewGroup(一)

换一种布局:

<?xml version="1.0" encoding="utf-8"?>
<com.xiey94.view.viewgroup.XyEasyLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="300dip"
    android:layout_height="300dip"
    android:background="@color/colorPrimaryDark"
    android:orientation="vertical">

    <TextView
        android:layout_width="100dip"
        android:layout_height="100dip"
        android:background="@color/colorAccent" />

    <TextView
        android:layout_width="100dip"
        android:layout_height="100dip"
        android:background="@color/colorAccent" />

    <TextView
        android:layout_width="100dip"
        android:layout_height="100dip"
        android:background="@color/colorAccent" />

    <TextView
        android:layout_width="100dip"
        android:layout_height="100dip"
        android:background="@color/colorAccent" />

</com.xiey94.view.viewgroup.XyEasyLayout>

自定义ViewGroup(一)

这些都算是初级体验,还没有步入正门。