自定义ViewGroup

(自定义ViewGroup)

自定义布局主要是重写两个方法:

  • onMeasure() 这个是写自定义容器的大小。
  • onLayout() 这个是写子元素的布局。 
    我自己写了一个自定义布局,是顺序填充会延对角线进行排列。

3.1onMeasure()

 @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);
        /**
         * width和height是当wrap_content时使用的属性。
         */
        int width = 0;
        int height = 0;
        int cCount = getChildCount();
        int cWidth = 0;
        int cHeight = 0;
        /**
         * 在这里计算当wrap_content时,布局的大小。
         */
        for (int i = 0; i < cCount; i++) {
            View childView = getChildAt(i);
            cWidth = childView.getMeasuredWidth();
            cHeight = childView.getMeasuredHeight();
            width += cWidth;
            height += cHeight;
        }
        /**
         * 如果是wrap_content设置为我们计算的值
         * 否则:直接设置为父容器计算的值
         */
        setMeasuredDimension((widthMode == MeasureSpec.EXACTLY) ? sizeWidth
                : width, (heightMode == MeasureSpec.EXACTLY) ? sizeHeight
                : height);

    }

首先要说一下布局计算模式,即最后的EXACTLY。一共有三种计算模式:

  • MeasureSpec.EXACTLY:精确尺寸,相当于具体数值和match_parent。
  • MeasureSpec.AT_MOST:最大尺寸,相当于 warp_content。
  • MeasureSpec.UNSPECIFIED:未指定尺寸,这种情况不多,一般用于AdapterView。

最后的设定大小时,如果是精确尺寸就是用sizeWidth即获取的尺寸,如果是最大尺寸就是要我们自己计算的那个尺寸了。 
onMeasure()最主要的功能就是计算wrap_content的尺寸设置尺寸。 
我将这个方法称为“建画布”,先建了画布才能在上面绘图嘛。

3.2 onLayout()

@Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int cCount = getChildCount();

        /**
         * 遍历所有childView根据其宽和高,以及margin进行布局
         */
        for (int i = 0; i < cCount; i++) {
            View childView = getChildAt(i);
            r = l + childView.getMeasuredWidth();
            b = t + childView.getMeasuredHeight();
            childView.layout(l, t, r, b);
            l += childView.getMeasuredWidth();
            t += childView.getMeasuredHeight();
        }
    }

这个方法的作用是设置摆放子元素的位置。其中onLayout()传入的l、t、r、b分别是这样 

  • l,t分别对应子元素左上角的left,top坐标
  • r,b分别对应子元素右下角的right,bottom坐标

并且可以使用childview.getMeasuredWidth()和childView.getMeasureHeight()得到子元素的宽和高。 
这样就可以来对每个子元素进行布局了。 
我称这个方法为“定位置”。定完位置后那么子元素就被放到了我们想要的地方。 
这样一个自定义ViewGroup就可以使用了。 
xml文件如下:

<?xml version="1.0" encoding="utf-8"?>
<com.example.layoutdemo.MyLayout.MyLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    >

        <TextView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:background="#b2dfdb" />

        <TextView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:background="#80cbc4" />

        <TextView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:background="#4db6ac" />

        <TextView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:background="#26a69a" />

</com.example.layoutdemo.MyLayout.MyLayout>

最后效果如图: 
MyLayout

原文地址:https://www.cnblogs.com/feng9exe/p/7930742.html