自定义ViewGroup,你真正懂了吗?

背景

自定义View简单,因为它只需管好自己即可,而自定义ViewGroup不仅仅要管好自己,还要管好子View。接触过ViewGroup的童鞋应该都清楚,ViewGroup是作为一个View的容器,它装着子View并将子View放到指定位置上去。

目的

让大家举一反三地去自定义定制化的GroupView

思路

自定义GroupView思路

  • 首先需要知道子View大小,然后才能确定自定义的GroupView如何设置才能容纳它们。
  • 根据子View的大小和ViewGroup需要实现的效果,确定最终ViewGroup的大小。
  • ViewGroup和子View的大小确定后,接着就是如何去摆放子View,你可以按照自己特定的规则去摆放。
  • 然后将子View对号入座放入已知的分割单元。

实践

接下来我做一个示例将子View按从左到右顺序一个挨着一个摆放,即模仿实现LinearLayout的横向布局。

首先重写onMeasure,测量子View大小以及设定ViewGroup最终大小,代码如下:

 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // 对所有子view进行测量,触发所有子view的onMeasure函数
        measureChildren(widthMeasureSpec, heightMeasureSpec);

        // 宽度模式
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        // 测量宽度
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        // 高度模式
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        // 测量高度
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        // 子view数目
        int childCount = getChildCount();
        if (childCount == 0){
            // 如果当前ViewGroup没有子View,就没有存在的意义,无需占空间
            setMeasuredDimension(0, 0);
        }else {
            // 如果宽高都是包裹内容
            if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST){
                // 宽度为所有子view宽度相加,高度取子view最大高度
                int width = getTotalWidth();
                int height = getMaxHeight();
                setMeasuredDimension(width, height);
            }else if (widthMode == MeasureSpec.AT_MOST){
                // 宽度为所有子View宽度相加,高度为测量高度
                setMeasuredDimension(getTotalWidth(), heightSize);
            }else if (heightMode == MeasureSpec.AT_MOST){
                // 宽度为测量宽度,高度为子view最大高度
                setMeasuredDimension(widthSize, getMaxHeight());
            }
        }
    }
    
      /**
     * 获取子view最大高度
     * @author leibing
     * @createTime 2016/09/19
     * @lastModify 2016/09/19
     * @param
     * @return
     */
    private int getMaxHeight() {
        // 最大高度
        int maxHeight = 0;
        // 子view数目
        int childCount = getChildCount();
        // 遍历子view拿取最大高度
        for (int i=0;i<childCount;i++){
            View childView = getChildAt(i);
            if (childView.getMeasuredHeight() > maxHeight)
                maxHeight = childView.getMeasuredHeight();
        }

        return maxHeight;
    }

    /**
     * 所有子view宽度相加
     * @author leibing
     * @createTime 2016/09/19
     * @lastModify 2016/09/19
     * @param
     * @return
     */
    private int getTotalWidth() {
        // 所有子view宽度之和
        int totalWidth = 0;
        // 子View数目
        int childCount  = getChildCount();
        // 遍历所有子view拿取所有子view宽度之和
        for (int i=0;i<childCount;i++){
            View childView = getChildAt(i);
            totalWidth += childView.getMeasuredWidth();
        }
        return totalWidth;
    }

接下来将子View摆放到合适的位置上去,代码如下:

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        // 子view数目
        int childCount = getChildCount();
        // 记录当前宽度位置
        int currentWidth = l;
        // 逐个摆放子view
        for (int i = 0;i<childCount;i++){
            View childView = getChildAt(i);
            int height = childView.getMeasuredHeight();
            int width = childView.getMeasuredWidth();
            // 摆放子view,参数分别是子view矩形区域的左、上,右,下。
            childView.layout(currentWidth, t, currentWidth + width, t + height);
            currentWidth += width;
        }
    }

运行效果图如下所示:

《自定义ViewGroup,你真正懂了吗?》 CustomViewGroup.gif

童鞋们,看完后,自定义ViewGroup是不是很简单了?

demo地址:[CustomView Demo]

作者

    原文作者:码无止境
    原文地址: https://www.jianshu.com/p/07ac5921fed8
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞