LinearLayout 绘制流程解析

太久没有好好学习Android的基础知识了,趁机好好静下心来学习、输出。

LinearLayout绘制流程解析

RelativeLayout绘制流程解析

ListView绘制流程解析

RecyclerView绘制流程解析


前言

之前《View/ViewGroup 绘制流程和疑惑》写了关于ViewGroup的绘制流程,在此基础上,继续分析LinearLayout的绘制流程,其实无论时LinearLayout还是RelativeLayout,都是继承自ViewGroup,除了Measure流程重写之外,layout和draw基本延续了VIewGroup的一套。

从LinearLayout的绘制,也就是测量开始:

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
   
    if (mOrientation == VERTICAL) {
    // 垂直方向
        measureVertical(widthMeasureSpec, heightMeasureSpec);
    } else {
    // 水平方向
        measureHorizontal(widthMeasureSpec, heightMeasureSpec);
    }
}

根据方向分成垂直和水平测量流程,这里仅讨论垂直方向

测量流程

这才正式开始了真正的垂直方向的测量流程:

  1. 首次测量,遍历测量子View,除了设置weight无法测量的子View;
  2. 计算更新最大的总高度;
  3. 若子View需要重新分配,则重新测量
  4. 计算测量更新最大的宽度
  5. 设置布局宽高

垂直测量

// 垂直测量
void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {
   
	    mTotalLength = 0; // 总高度,子控件累加总高度
    int maxWidth = 0; // 最大子控件的宽度
    int childState = 0; // 子view测量状态
    int alternativeMaxWidth = 0; // 没有设置weight的子view的最大宽度
    int weightedMaxWidth = 0; // 设置weight的子view的最大宽度
    boolean allFillParent = true; // 子控件全设置match_parent
    float totalWeight = 0; // 子控件累加总权重(子控件设置了layout_weight)

    final int count = getVirtualChildCount(); // 子控件总数量

	// 测量模式
    final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    
    boolean matchWidth = false; // 有子View宽度设置为match_parent
    // 是否跳过重新测量
    boolean skippedMeasure = false;
    // 基线子view
    final int baselineChildIndex = mBaselineAlignedChildIndex; 
    
    // 跟setMeasureWithLargestChildEnabled()有关
    // 当设定为true,所有有设定了weight的子View的最小高度是:最大的View的高度
    final boolean useLargestChild = mUseLargestChild;
	// 最大子控件的高度
    int largestChildHeight = Integer.MIN_VALUE;
    
    int consumedExcessSpace = 0;
    // 需要测量的子View总数,不需要测量指的是设定了weight
    int nonSkippedChildCount = 0;

    // 首次测量,测量能测量到的子View的高度和最大宽度,不包括weight的子View
    for (int i = 0; i < count; ++i) {
   
    	/**** 备注:第一次测量,见分析一 ****/        
    }
    
	// 底部是否有分割线,计算最高高度
    if (nonSkippedChildCount > 0 && hasDividerBeforeChildAt(count)) {
   
        mTotalLength += mDividerHeight;
    }
    if (useLargestChild && (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED)) {
   
        mTotalLength = 0;
       //设置了 measureWithLargestChild 且 总高度无法确定,需要重新计算 mToatalLength
        for (int i = 0; i < count; ++i) {
   
     		/**** 备注:见分析二 ****/       
        }
     }
     // 添加padding
     mTotalLength += mPaddingTop + mPaddin
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值