当前位置: 首页 > news >正文

LinearLayout的测量流程

在日常开发中我们常常使用LinearLayout作为布局Group,本文从其源码实现出发分析测量流程。大家可以带着问题进入下面的分析流程,看看是否能找到答案。

垂直测量

View的测量入口方法是onmeasure方法。LinearLayout的onMeasure方法根据其方向而做不同的处理。本文我们选择垂直布局测量看下。

	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {if (mOrientation == VERTICAL) {measureVertical(widthMeasureSpec, heightMeasureSpec);} else {measureHorizontal(widthMeasureSpec, heightMeasureSpec);}}

而measureVertical方法整体上分为2个部分。即两次测量。

第一次测量
	for (int i = 0; i < count; ++i) {final View child = getVirtualChildAt(i);if (child == null) {mTotalLength += measureNullChild(i);continue;}if (child.getVisibility() == View.GONE) {//GONE的View不用测量,注意INVISIBLE还是会测量的i += getChildrenSkipCount(child, i);continue;}nonSkippedChildCount++;if (hasDividerBeforeChildAt(i)) {//mTotalLength为总的使用高度,这里加上分割线的高度mTotalLength += mDividerHeight;}final LayoutParams lp = (LayoutParams) child.getLayoutParams();//totalWeight为总的weight,这里主要是统计所有使用weight的view的总weight,为后续测量weight>0的View作准备totalWeight += lp.weight;final boolean useExcessSpace = lp.height == 0 && lp.weight > 0;if (heightMode == MeasureSpec.EXACTLY && useExcessSpace) {// 优化:不必费心测量仅使用多余空间布局的子视图。如果我们有空间可供分配,这些视图将在稍后进行测量。//这里是指当LinearLayout为精确模式&&子View使用了weight。那么本次就不用测量该View,而只是将其margin统计到已使用的高度上final int totalLength = mTotalLength;mTotalLength = Math.max(totalLength, totalLength + lp.topMargin + lp.bottomMargin);skippedMeasure = true;} else {if (useExcessSpace) {// heightMode 为 UNSPECIFIED 或 AT_MOST,并且此子项仅使用多余的空间进行布局。使用 WRAP_CONTENT 进行测量以便我们能够找出视图的最佳高度。测量后,我们将恢复原始高度 0lp.height = LayoutParams.WRAP_CONTENT;}// 确定此子项想要有多大。如果此子项或先前的子项已指定weight权重,则我们允许它使用所有可用空间(如果需要,我们稍后会缩小空间)。final int usedHeight = totalWeight == 0 ? mTotalLength : 0;//测量子View的宽高measureChildBeforeLayout(child, i, widthMeasureSpec, 0,heightMeasureSpec, usedHeight);final int childHeight = child.getMeasuredHeight();if (useExcessSpace) {// 恢复原始高度并记录我们为多余的子项分配了多少空间,以便我们能够匹配精确测量的行为。lp.height = 0;consumedExcessSpace += childHeight;}final int totalLength = mTotalLength;//更新当前总的高度mTotalLength = Math.max(totalLength, totalLength + childHeight + lp.topMargin +lp.bottomMargin + getNextLocationOffset(child));if (useLargestChild) {//这个largestChildHeight可以理解成所有子View中的高度最大的View的高度,主要是为了在当前View使用weight>0,但是父View的高度不确定的情况下确定子View的高度,比如LinearLayout是wrap_content,largestChildHeight = Math.max(childHeight, largestChildHeight);}}if ((baselineChildIndex >= 0) && (baselineChildIndex == i + 1)) {mBaselineChildTop = mTotalLength;}boolean matchWidthLocally = false;if (widthMode != MeasureSpec.EXACTLY && lp.width == LayoutParams.MATCH_PARENT) {// 线性布局的宽度将缩放,并且至少有一个子视图表示它想要匹配我们的宽度。设置一个标志表示当我们知道我们的宽度时,我们至少需要重新测量该视图。matchWidth = true;matchWidthLocally = true;}final int margin = lp.leftMargin + lp.rightMargin;final int measuredWidth = child.getMeasuredWidth() + margin;maxWidth = Math.max(maxWidth, measuredWidth);childState = combineMeasuredStates(childState, child.getMeasuredState());allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT;if (lp.weight > 0) {/** 计算最大宽度*/weightedMaxWidth = Math.max(weightedMaxWidth,matchWidthLocally ? margin : measuredWidth);} else {alternativeMaxWidth = Math.max(alternativeMaxWidth,matchWidthLocally ? margin : measuredWidth);}i += getChildrenSkipCount(child, i);}

从第一测量的源码得知,其第一次测量主要是测量weight==0的子View的宽高,并为第二次测量做准备:统计weight的和、统计已使用的高度(为weight能分配的高度做准备)
统计最大的子View的高度。

第二次测量
        //remainingExcess为剩余可以为weight>0的子View分配高度的总和int remainingExcess = heightSize - mTotalLength+ (mAllowInconsistentMeasurement ? 0 : consumedExcessSpace);
if (skippedMeasure|| ((sRemeasureWeightedChildren || remainingExcess != 0) && totalWeight > 0.0f)) {//如果有weight>0的子View。则走这个分支float remainingWeightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;mTotalLength = 0;for (int i = 0; i < count; ++i) {final View child = getVirtualChildAt(i);if (child == null || child.getVisibility() == View.GONE) {continue;}final LayoutParams lp = (LayoutParams) child.getLayoutParams();final float childWeight = lp.weight;if (childWeight > 0) {// 按照权重计算每个weight>0的子View的高度final int share = (int) (childWeight * remainingExcess / remainingWeightSum);remainingExcess -= share;remainingWeightSum -= childWeight;final int childHeight;if (mUseLargestChild && heightMode != MeasureSpec.EXACTLY) {childHeight = largestChildHeight;} else if (lp.height == 0 && (!mAllowInconsistentMeasurement|| heightMode == MeasureSpec.EXACTLY)) {// This child needs to be laid out from scratch using// only its share of excess space.childHeight = share;} else {// This child had some intrinsic height to which we// need to add its share of excess space.childHeight = child.getMeasuredHeight() + share;}//生成子View的高度MeasureSpec,模式为精确final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(Math.max(0, childHeight), MeasureSpec.EXACTLY);final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin,lp.width);//重新测量子Viewchild.measure(childWidthMeasureSpec, childHeightMeasureSpec);// Child may now not fit in vertical dimension.childState = combineMeasuredStates(childState, child.getMeasuredState()& (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT));}final int margin =  lp.leftMargin + lp.rightMargin;final int measuredWidth = child.getMeasuredWidth() + margin;maxWidth = Math.max(maxWidth, measuredWidth);boolean matchWidthLocally = widthMode != MeasureSpec.EXACTLY &&lp.width == LayoutParams.MATCH_PARENT;alternativeMaxWidth = Math.max(alternativeMaxWidth,matchWidthLocally ? margin : measuredWidth);allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT;final int totalLength = mTotalLength;mTotalLength = Math.max(totalLength, totalLength + child.getMeasuredHeight() +lp.topMargin + lp.bottomMargin + getNextLocationOffset(child));}// Add in our paddingmTotalLength += mPaddingTop + mPaddingBottom;// TODO: Should we recompute the heightSpec based on the new total length?} else {alternativeMaxWidth = Math.max(alternativeMaxWidth,weightedMaxWidth);// We have no limit, so make all weighted views as tall as the largest child.// Children will have already been measured once.if (useLargestChild && heightMode != MeasureSpec.EXACTLY) {for (int i = 0; i < count; i++) {final View child = getVirtualChildAt(i);if (child == null || child.getVisibility() == View.GONE) {continue;}final LinearLayout.LayoutParams lp =(LinearLayout.LayoutParams) child.getLayoutParams();float childExtra = lp.weight;if (childExtra > 0) {child.measure(MeasureSpec.makeMeasureSpec(child.getMeasuredWidth(),MeasureSpec.EXACTLY),MeasureSpec.makeMeasureSpec(largestChildHeight,MeasureSpec.EXACTLY));}}}}

相关文章:

LinearLayout的测量流程

在日常开发中我们常常使用LinearLayout作为布局Group&#xff0c;本文从其源码实现出发分析测量流程。大家可以带着问题进入下面的分析流程&#xff0c;看看是否能找到答案。 垂直测量 View的测量入口方法是onmeasure方法。LinearLayout的onMeasure方法根据其方向而做不同的处…...

数据无忧:Ubuntu 系统迁移备份全指南

唠唠闲话 最近电脑出现了一些故障&#xff0c;送修期间&#xff0c;不得不在实验室的台式机上重装系统&#xff0c;配环境的过程花费了不少时间。为避免未来处理类似事情时耗费时间&#xff0c;特此整理一些备份策略。 先做以下准备&#xff1a; U盘启动盘&#xff0c;参考 …...

中国IDC圈探访北京•光子1号金融算力中心

今天&#xff0c;“AI”、“大模型”是最炙手可热的话题&#xff0c;全球有海量人群在工作生活中使用大模型&#xff0c;大模型产品涉及多模态&#xff0c;应用范围已涵盖电商、传媒、金融、短视频、制造等众多行业。 而回看2003年的互联网记忆&#xff0c; “上网”“在线”是…...

[Unity入门01] Unity基本操作

参考的傅老师的教程学了一下Unity的基础操作&#xff1a; [傅老師/Unity教學] Unity3D基礎入門 [華梵大學] 遊戲引擎應用基礎(Unity版本) Class#01 移动&#xff1a;鼠标中键旋转&#xff1a;鼠标右键放大&#xff1a;鼠标滚轮飞行模式&#xff1a;右键WASDQEFocus模式&…...

vivado DELAY_VALUE_XPHY、DIFF_TERM

延迟_值_XPHY PORT对象上的DELAY_VALUE_XPHY属性指定要添加的延迟量 Versal XPHY逻辑接口的输入或输出路径。在的早期阶段 opt_design在重新生成高级I/O向导IP时 DELAY_VALUE_XPHY值将从PORT复制到的XPHY实例上 输入或输出路径。Vivado设计套件中存在DRCs&#xff0c;以确保 DE…...

C++语言相关的常见面试题目(三)

1. List底层实现原理 省流&#xff1a; list底层实现了一个双向循环链表。 每个元素&#xff08;或节点&#xff09;包含三个部分&#xff1a;数据域(_M_Storage)、前驱指针(_M_prev)、后继指针(_M_next)。 数据域&#xff1a;存储实际数据。 前驱指针&#xff1a;指向链表中…...

代码随想录-Day53

739. 每日温度 给定一个整数数组 temperatures &#xff0c;表示每天的温度&#xff0c;返回一个数组 answer &#xff0c;其中 answer[i] 是指对于第 i 天&#xff0c;下一个更高温度出现在几天后。如果气温在这之后都不会升高&#xff0c;请在该位置用 0 来代替。 示例 1: …...

Android 如何通过代码实时设置EditTextView光标

背景&#xff1a;换肤框架下&#xff0c;QA进行深色浅色切换说输入框光标颜色没有改变&#xff0c;转UI结果UI说需要修改&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 本来有方法可以设置&#xff0c;但是 设置后未生效。重新进入该页面才生效&#xff01;&a…...

202488读书笔记|《365日创意文案》——无聊的 到底是这世间, 还是自己?懂得忘却的人才能前进

202488读书笔记|《365日创意文案》——无聊的 到底是这世间&#xff0c; 还是自己&#xff1f;懂得忘却的人才能前进 1月2月3月4月5月6月7月8月9月10月11月12月 《365日创意文案》WRITES PUBLISHING&#xff0c;一些日常&#xff0c;是烟火&#xff0c;也是幸福的印记。 当下也…...

iperf3: error - unable to connect to server: No route to host

1.确认iperf3版本是否统一。 2.确认防火墙是否关闭。 关闭防火墙 : systemctl stop firewalld 查看防火墙状态: systemctl status firewalld 3.重新建起链接...

正则表达式中的贪心匹配

在正则表达式中&#xff0c;&#xff1f;既可以表示数量&#xff0c;0次或1次&#xff0c;等效于 {0&#xff0c;1}&#xff0c;也可以跟在其它数量限定符之后&#xff0c;表示非贪心匹配&#xff0c;即匹配时匹配搜索到的尽可能短的字符串。 下面来看一个例子&#xff1a; T…...

线程相关概念及操作

【1】线程的概念 1.线程-->进程会得到一个内存地址&#xff0c;进程是资源分配的基本单位线程才是真正进程里处理数据与逻辑的东西进程---》被分配一定的资源线程---》利用进程资源处理数据与逻辑 【2】进程和线程关系&#xff1a; 进程与进程之间是竞争关系&#xff0c;竞…...

2024最新版若依-RuoYi-Vue3-PostgreSQL前后端分离项目部署手册教程

项目简介: RuoYi-Vue3-PostgreSQL 是一个基于 RuoYi-Vue3 框架并集成 PostgreSQL 数据库的项目。该项目提供了一套高效的前后端分离的开发解决方案&#xff0c;适用于中小型企业快速构建现代化的企业级应用。此项目结合了 RuoYi-Vue-Postgresql 和 RuoYi-Vue3 的优点&#xff0…...

PHP源码:新闻门户系统(附管理后台+前台)

一. 前言 今天小编给大家带来了一款可学习&#xff0c;可商用的&#xff0c;新闻门户系统 源码&#xff0c;支持二开&#xff0c;无加密。项目可以扩展为个人博客&#xff0c;和一些社交论坛网址。主要功能&#xff1a;支持文章管理&#xff0c;评论管理&#xff0c;分类管理等…...

15kg级弹簧刀高速巡飞无人机技术详解

弹簧刀高速巡飞无人机&#xff0c;作为一种先进的战术导弹系统&#xff0c;融合了无人机与导弹的双重特性&#xff0c;成为了现代战争中不可或缺的侦察与打击利器。该无人机以其小巧的外形设计、优异的性能表现和广泛的适用领域&#xff0c;受到了全球军事领域的广泛关注。弹簧…...

中国东方资产管理25届秋招北森测评笔试如何高分通过?真题考点分析看完这篇就够了

一、东方资管校招测评题型分析 中国东方资产管理股份有限公司&#xff08;中国东方资管&#xff09;的校园招聘测评题型主要包括以下几个部分&#xff1a; 1. **计分题&#xff0c;行测知识**&#xff1a;这部分题量大约在56-57题左右&#xff0c;分为不同的模块进行计时测试。…...

简写单词BC149

BC149 简写单词 题目描述输入描述&#xff1a;输出描述&#xff1a; 题目描述 规定一种对于复合词的简写方式为只保留每个组成单词的首字母&#xff0c;并将首字母大写后再连接在一起 比如 “College English Test”可以简写成“CET”&#xff0c;“Computer Science”可以简写…...

Chapter11让画面动起来——Shader入门精要学习笔记

Chapter11让画面动起来 一、Unity Shader中的内置变量&#xff08;时间篇&#xff09;二、纹理动画1.序列帧动画2.滚动背景 三、顶点动画1.流动的河流2.广告牌3.注意事项①批处理问题②阴影投射问题 一、Unity Shader中的内置变量&#xff08;时间篇&#xff09; Unity Shader…...

c++之命名空间详解(namespace)

引例 在学习之前我们首先了来看这样一个情形: 在c语言下&#xff0c;我们写了两个头文件&#xff1a;链表和顺序表的。我们会定义一个type(typedef int type)方便改变数据类型&#xff08;比如将int改成char&#xff09;&#xff0c;来做到整体代换。 但是我们两个头文件里面…...

【大模型】在大语言模型的璀璨星河中寻找道德的北极星

在大语言模型的璀璨星河中寻找道德的北极星 引言一、概念界定二、隐私保护的挑战2.1 数据来源的道德考量2.2 敏感信息的泄露风险 三、偏见与歧视的隐忧3.1 训练数据的偏见传递3.2 内容生成的不公倾向 四、责任归属的模糊地带4.1 生成内容的责任界定4.2 自动化决策的伦理考量 五…...

论文创新点像挤牙膏?导师强推这几个AI论文平台

想写论文又快又好&#xff0c;关键是用对 AI 工具、走对流程——资深教授普遍推荐&#xff1a;千笔AI&#xff08;中文全流程首选&#xff09; 豆包学术版&#xff08;轻量高效&#xff09; DeepSeek 学术版&#xff08;理工 / 长文本&#xff09; Grammarly Academic&#xff…...

3分钟开启PC游戏分屏派对:NucleusCoop让单机游戏秒变多人同屏神器

3分钟开启PC游戏分屏派对&#xff1a;NucleusCoop让单机游戏秒变多人同屏神器 【免费下载链接】nucleuscoop Starts multiple instances of a game for split-screen multiplayer gaming! 项目地址: https://gitcode.com/gh_mirrors/nu/nucleuscoop 还在为热门PC游戏不支…...

我们公司全员把 Cursor 换成了自研的 全开源AtomCode

【引子】这是一篇实录——一位 CTO 用 28 天,用 Claude GLM 双模型调度,造出了一个让全公司放弃 Cursor 的工具。然后我意识到我们正在经历的事情,比"换工具"大得多。【读者承诺】接下来 15 分钟,你会拿到三件东西:一个真实案例(28 天 1,146 commits 是怎么做出来的…...

告别杂乱!用FileMenu Tools 8.4.2一键清理Windows 11右键菜单(附隐藏技巧)

Windows 11右键菜单精简指南&#xff1a;用FileMenu Tools打造高效工作流每次在文件上点击右键时&#xff0c;那个缓慢弹出的冗长菜单是否让你感到烦躁&#xff1f;随着安装的软件越来越多&#xff0c;Windows的右键菜单往往会变得臃肿不堪&#xff0c;严重影响工作效率。今天&…...

别再乱建索引了!用Explain的key_len字段,一眼看穿你的MySQL联合索引到底生效了几个字段

解密MySQL联合索引&#xff1a;用key_len精准判断索引生效范围 在数据库性能优化领域&#xff0c;联合索引的使用一直是个既基础又容易踩坑的话题。很多开发者虽然知道"最左匹配原则"这个名词&#xff0c;但在实际业务场景中&#xff0c;面对复杂的查询条件组合时&a…...

量子机器学习与傅里叶分析:革新期权定价的混合计算范式

1. 项目概述&#xff1a;当量子机器学习遇见金融定价在金融工程的核心地带&#xff0c;期权定价一直是个计算密集型的硬骨头。传统的蒙特卡洛模拟虽然通用&#xff0c;但为了达到足够的精度&#xff0c;动辄需要百万甚至千万次的路径模拟&#xff0c;计算成本高昂。近年来&…...

AI Agent 为什么必须有“记忆系统”?

导语&#xff1a;大模型不是没有智商&#xff0c;而是经常没有“记性”。真正能长期干活的 Agent&#xff0c;不是靠无限拉长上下文&#xff0c;而是靠一套会压缩、会检索、会遗忘、会治理的外置记忆系统。一、先给结论&#xff1a;Agent 的记忆系统&#xff0c;本质是“上下文…...

Actor Framework里的“多米诺骨牌”:一个错误如何让整个嵌套操作者链崩溃?

Actor Framework中的“多米诺效应”&#xff1a;如何避免嵌套操作者链的崩溃 在分布式系统设计中&#xff0c;Actor模型因其天然的并发处理能力而备受青睐。LabVIEW的Actor Framework(AF)通过操作者(actor)的嵌套结构&#xff0c;为复杂系统提供了模块化解决方案。然而&#x…...

白嫖Codex!一行代码不花接入国产DeepSeek-v4-pro,从此告别ChatGPT月费

Codex 如何接入国产模型 DeepSeek-v4-pro 保姆级教程 使用 Claude Code、Codex 已经好几个月了&#xff0c;不得不感叹现在的 AI 工具真的太强大了。目前市面上很多 Claude Code 如何接入大模型的教程&#xff0c;但 Codex 却比较少&#xff0c;一方面因为 Codex 需要 ChatGPT …...

【独家首发】国内23家AI语音服务商最新报价数据库(含教育/医疗/金融行业专属折扣码及最小起订量红线)

更多请点击&#xff1a; https://kaifayun.com 第一章&#xff1a;AI语音合成价格与性价比分析 AI语音合成&#xff08;TTS&#xff09;服务的定价模式日益多样化&#xff0c;从按字符/音频时长计费到订阅制、API调用包、企业定制方案并存。理解不同服务商的成本结构与实际输出…...