Android View绘制3 Layout流程

一 概述

在上篇文章中我们分析了 View 的 Measure 过程,本篇文章我们分析 Layout 过程,通过本篇文章,你将了解到:

  • 关于 Layout 简单类比
  • 一个简单 Demo
  • View Layout 过程
  • ViewGroup Layout 过程
  • View/ViewGroup 常用方法分析
  • 为什么说 Layout 是承上启下的作用

二 关于Layout简单类比

在上篇文章的比喻里,我们说过:

老王给三个儿子,大王(大王儿子:小小王)、二王、三王分配了具体的良田面积,三个儿子(小小王)也都确认了自己的需要的良田面积。这就是:Measure 过程

既然知道了分配给各个儿孙的良田大小,那他们到底分到哪一块呢,是靠边、还是中间、还是其它位置呢?先分给谁呢?

老王想按到这个家的时间先后顺序来分 (对应 addView 顺序),大王是自己的长子,先分配给他,于是从最左侧开始,划出3亩田给大王。现在轮到二王了,由于大王已经分配了左侧的3亩,那么给二王的5亩地只能从大王右侧开始划分,最后剩下的就分给三王。这就是:ViewGroup onLayout 过程。

大王拿到老王给自己指定的良田的边界,将这个边界 (左、上、右、下) 坐标记录下来。这就是:View Layout 过程。

接着大王告诉自己的儿子小小王:你爹有点私心啊,从爷爷那继承的5亩田地不能全分给你,我留一些养老。这就是设置:padding 过程。

如果二王在最开始测量的时候就想:我不想和大王、三王的田离得太近,那么老王就会给大王、三王与二王的土地之间留点缝隙。这就是设置:margin 过程

三 一个简单Demo

自定义 ViewGroup

public class MyViewGroup extends ViewGroup {
   
   
    public MyViewGroup(Context context) {
   
   
        super(context);
    }

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
   
   
        int usedWidth = 0;
        int maxHeight = 0;
        int childState = 0;

        //测量子布局
        for (int i = 0; i < getChildCount(); i++) {
   
   
            View childView = getChildAt(i);
            MarginLayoutParams layoutParams =
                (MarginLayoutParams) childView.getLayoutParams();
            measureChildWithMargins(childView, widthMeasureSpec, usedWidth,
                heightMeasureSpec, 0);
            usedWidth += layoutParams.leftMargin + layoutParams.rightMargin +
                childView.getMeasuredWidth();
            maxHeight = Math.max(maxHeight, layoutParams.topMargin +
                layoutParams.bottomMargin + childView.getMeasuredHeight());
            childState = combineMeasuredStates(childState, childView.getMeasuredState());
        }

        //统计子布局水平,记录尺寸值
        usedWidth += getPaddingLeft() + getPaddingRight();
        maxHeight += getPaddingTop() + getPaddingBottom();
        setMeasuredDimension(
            resolveSizeAndState(usedWidth, widthMeasureSpec, childState),
            resolveSizeAndState(maxHeight, heightMeasureSpec,
                childState << MEASURED_HEIGHT_STATE_SHIFT));
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
   
   
        //父布局传递进来的位置信息
        int parentLeft = getPaddingLeft();
        int left = 0;
        int top = 0;
        int right = 0;
        int bottom = 0;

        //遍历子布局
        for (int i = 0; i < getChildCount(); i++) {
   
   
            View childView = getChildAt(i);
            MarginLayoutParams layoutParams =
                (MarginLayoutParams) childView.getLayoutParams();
            left = parentLeft + layoutParams.leftMargin;
            right = left + childView.getMeasuredWidth();
            top = getPaddingTop() + layoutParams.topMargin;
            bottom = top + childView.getMeasuredHeight();
            //子布局摆放
            childView.layout(left, top, right, bottom);
            //横向摆放
            parentLeft += right;
        }
    }

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
   
   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值