面试官:你知道的我就不问,layout怎么布局的?viewGroup和view的layout方法又有什么不同?

前言

上次我们说到View的Mearsure流程,今天接着说说layout

关于layout,很多朋友知道它是负责布局的,那么具体是怎么布局的?viewGroupviewlayout方法又有什么不同?一起来看看吧。

View layout方法

首先,还是从ViewRootImpl说起,界面的绘制会触发performMeasure、performLayout方法,而在performLayout方法中就会调用mView的layout方法开始一层层View的布局工作。

private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,int desiredWindowHeight) {final View host = mView;host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());}

mView我们都知道了,就是顶层View——DecorView,那么就进去看看DecorView的layout方法:

不好意思,DecorView中并没有layout方法...

所以,我们直接看看View的layout方法:

public void layout(int l, int t, int r, int b) {boolean changed = isLayoutModeOptical(mParent) ?setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {onLayout(changed, l, t, r, b);}}protected void onLayout(boolean changed, int left, int top, int right, int bottom) {}
  • 首先,方法传入了四个参数,分别代表view的左、上、下、右四个值。
  • 然后通过setOpticalFrame方法或者setFrame方法判断布局参数是否改变。

具体判断过程就是通过老的上下左右值和新的上下左右值进行比较,逻辑就在setFrame方法中:

protected boolean setFrame(int left, int top, int right, int bottom) {boolean changed = false;if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) {changed = true;// Remember our drawn bitint drawn = mPrivateFlags & PFLAG_DRAWN;int oldWidth = mRight - mLeft;int oldHeight = mBottom - mTop;int newWidth = right - left;int newHeight = bottom - top;boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight);// Invalidate our old positioninvalidate(sizeChanged);mLeft = left;mTop = top;mRight = right;mBottom = bottom;mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);}return changed;}

如果上下左右有一个参数值发生了改变,就说明这个View的布局发生了改变,然后重新计算View的宽度高度(newWidth、newHeight),并赋值了View新的上下左右参数值。

在这个layout方法中主要涉及到了四个参数:mLeft、mTop、mBottom、mRight,分别代表了View的左坐标、上坐标、下坐标和右坐标,你可以把View理解为一个矩形,确定了这四个值,就能确定View矩形的四个顶点值,也就能确定View在画布中的具体位置。

所以,layout方法到底干了啥?

就是传入上下左右值、然后赋值上下左右值、完毕。

然后我们就可以根据这些值获取View的一系列参数,比如View宽度:

public final int getWidth() {return mRight - mLeft;}

至此,View的layout方法就结束了,主要就是通过对上下左右参数的赋值完成对View的布局,非常简单。

下面看看ViewGroup

ViewGroup layout方法

@Overridepublic final void layout(int l, int t, int r, int b) {if (!mSuppressLayout && (mTransition == null || !mTransition.isChangingLayout())) {if (mTransition != null) {mTransition.layoutChange(this);}super.layout(l, t, r, b);} else {mLayoutCalledWhileSuppressed = true;}}

额,还是调用到View的layout方法,难道说ViewGroupView的布局过程是一样的,就是确定了本身的位置?

ViewGroup的子View怎么办呢?不急,我们刚才说layout方法的时候还漏了一个onLayout方法,只不过这个方法在View里面是空实现,而到了ViewGroup中变成了一个抽象方法:

@Overrideprotected abstract void onLayout(boolean changed,int l, int t, int r, int b);

也就是任何ViewGroup都必须实现这个方法,来完成对子View的布局摆放。

具体的布局摆放逻辑就是在onLayout方法中一个个调用子View的layout方法,然后完成每个子View的布局,最终完成绘制工作。

接下来我们就来自己实现一个垂直线性布局(类似LinearLayout),正好复习下上一节的onMearsure和这一节的onLayout

自定义垂直布局VerticalLayout

首先,我们要确定我们这个自定义ViewGroup的作用,是类似垂直方向的LinearLayout功能,在该ViewGroup下的子View可以按垂直线性顺序依次往下排放。我们给它起个名字叫VerticalLayout

继承ViewGroup

首先,我们这个布局肯定要继承自ViewGroup,并且实现相应的构造方法:

public class VerticalLayout : ViewGroup {constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int = 0) : super(context,attrs,defStyleAttr)constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {}
}

重写generateLayoutParams方法

自定义ViewGroup还需要重写的一个方法是generateLayoutParams,这一步是为了让我们的ViewGroup支持Margin,后续我们就可以通过MarginLayoutParams来获取子View的Margin值。

override fun generateLayoutParams(attrs: AttributeSet?): LayoutParams? {return MarginLayoutParams(context, attrs)}

重写测量方法onMeasure

然后,我们需要对我们的布局进行测量,也就是重写onMeasure方法。

在该方法中,我们需要对我们的布局进行测量,并且将测量好的宽高传入setMeasuredDimension方法,完成测量。

protected final void setMeasuredDimension(int measuredWidth, int measuredHeight)

之前我们说过,onMeasure方法会传进来两个参数,widthMeasureSpecheightMeasureSpec

里面包含了父View根据当前View的LayoutParams和父View的测量规格进行计算,得出的对当前View期望的测量模式和测量大小

  • 当测量模式为MeasureSpec.EXACTLY

也就是当宽或者高为确定值时,那么当前布局View的宽高也就是设定为父View给我们设置好的测量大小即可。比如宽为400dp,那么我们无需重新测量直接调用setMeasuredDimension传入这个固定值即可。

  • 当测量模式为MeasureSpec.AT_MOST 或者 UNSPECIFIED:

这时候,说明父View对当前View的要求不固定,是可以为任意大小或者不超过最大值的情况,比如设置这个VerticalLayout的高度为wrap_content。那么我们就必须重新进行高度测量了,因为只有我们设计者知道这个自适应高度需要怎么计算。具体就是VerticalLayout是一个垂直线性布局,所以高度很自然就是所有子View的高度之和。

至此,onMeasure方法的逻辑也基本摸清了:

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {super.onMeasure(widthMeasureSpec, heightMeasureSpec)//获取宽高的测量模式和测量大小val widthMode = MeasureSpec.getMode(widthMeasureSpec)val heightMode = MeasureSpec.getMode(heightMeasureSpec)val sizeWidth = MeasureSpec.getSize(widthMeasureSpec)val sizeHeight = MeasureSpec.getSize(heightMeasureSpec)var mHeight = 0var mWidth = 0//遍历子View,获取总高度for (i in 0 until childCount) {val childView = getChildAt(i)//测量子View的宽和高measureChild(childView, widthMeasureSpec, heightMeasureSpec)val lp = childView.layoutParams as MarginLayoutParamsval childWidth = childView.measuredWidth + lp.leftMargin + lp.rightMarginval childHeight = childView.measuredHeight + lp.topMargin + lp.bottomMargin//计算得出最大宽度mWidth = Math.max(mWidth, childWidth)//累计计算高度mHeight += childHeight}//设置宽高setMeasuredDimension(if (widthMode == MeasureSpec.EXACTLY) sizeWidth else mWidth,if (heightMode == MeasureSpec.EXACTLY) sizeHeight else mHeight)}

主要的逻辑就是遍历子View,得出VerticalLayout的实际宽高:

  • 最终ViewGroup的高 = 所有子View的 (高 + margin值)
  • 最终ViewGroup的宽 = 最大子View的 (宽 + margin值)

最后调用setMeasuredDimension 根据测量模式 传入宽高。

重写布局方法onLayout

上文说过,作为一个ViewGroup,必须重写onLayout方法,来保证子View的正常布局摆放。

垂直线性布局VerticalLayout亦是如此,那么在这个布局中onLayout方法的关键逻辑又是什么呢?

还是那句话,确定位置,也就是确定左、上、右、下四个参数值,而在VerticalLayout中,最关键的参数就是这个上,也就是top值

每个View的top值必须是上一个View的bottom值,也就是接着上一个View进行摆放,这样才会是垂直线性的效果,所以我们需要做的就是动态计算每个View的top值,其实也就是不断累加View的高度,作为下一个View的top值。

override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {var childWidth = 0var childHeight = 0var childTop = 0var lp: MarginLayoutParams//遍历子View,布局每个子Viewfor (i in 0 until childCount) {val childView = getChildAt(i)childHeight = childView.measuredHeightchildWidth = childView.measuredWidthlp = childView.layoutParams as MarginLayoutParams//累计计算top值childTop += lp.topMargin//布局子ViewchildView.layout(lp.leftMargin,childTop,lp.leftMargin + childWidth,childTop + childHeight);childTop += childHeight + lp.bottomMargin}}

逻辑还是挺简单的,

  • left是固定的子View的leftMargin。
  • top是累加计算的子View的高度 + Margin值。
  • right是left + 子View的宽度。
  • bottom是top + 子View的高度。

最后调用子View的layout方法,对每个子View进行布局。

大功告成,最后看看我们这个自定义垂直线性布局的效果吧~

效果展示

<com.panda.studynote3.VerticalLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"><TextViewandroid:layout_width="100dp"android:layout_height="100dp"android:text="啦啦啦"android:textSize="20sp"android:textColor="@color/white"android:background="@color/design_default_color_primary"/><TextViewandroid:layout_width="300dp"android:layout_height="200dp"android:layout_marginTop="20dp"android:background="@color/cardview_dark_background"android:textSize="20sp"android:textColor="@color/white"android:text="你好啊"/><TextViewandroid:layout_width="140dp"android:layout_height="100dp"android:text="嘻嘻"android:layout_marginLeft="10dp"android:layout_marginTop="10dp"android:textSize="20sp"android:gravity="center"android:textColor="@color/black"android:background="@color/teal_200"/></com.panda.studynote3.VerticalLayout>

面试前复习路线参考

接下来分享的系统学习资源以详解各大互联网公司的 Android 常见面试题为主线,从面试的角度带你介绍必备知识点,以及该知识点在项目中的实际应用

帮你在现在的基础上,重新梳理和建立 Android 开发的知识体系。无论是你短期内想提升 Android 内功实力,突破自己工作中的能力瓶颈,还是准备参加 Android 面试,都会在这份资料中有所一些收获。

从架构基础开始,分了8个模块来逐步从基础进阶到架构师的环节:

多余的话就不讲了,接下来将分享面试的一个复习路线,如果你也在准备面试但是不知道怎么高效复习,可以参考一下我的复习路线,有任何问题也欢迎一起互相交流,加油吧!

首先是超级详细得不能再详细的Android开发学习思维导图,因为图片实在是太大了,所以我就只把二级目录的内容放出来,更加详细的你们可以私信【资料】查看免费领取方式。

接下来就需要梳理知识,提升储备了!(Android移动架构师七大专题学习资源)

  • 架构师筑基必备技能:深入Java泛型+注解深入浅出+并发编程+数据传输与序列化+Java虚拟机原理+反射与类加载+动态代理+高效IO
  • Android高级UI与FrameWork源码:高级UI晋升+Framework内核解析+Android组件内核+数据持久化
  • 360°全方面性能调优:设计思想与代码质量优化+程序性能优化+开发效率优化
  • 解读开源框架设计思想:热修复设计+插件化框架解读+组件化框架设计+图片加载框架+网络访问框架设计+RXJava响应式编程框架设计+IOC架构设计+Android架构组件Jetpack
  • NDK模块开发:NDK基础知识体系+底层图片处理+音视频开发
  • 微信小程序:小程序介绍+UI开发+API操作+微信对接
  • Hybrid 开发与Flutter:Html5项目实战+Flutter进阶

知识梳理完之后,就需要进行查漏补缺,所以针对这些知识点,我手头上也准备了不少的电子书和笔记,这些笔记将各个知识点进行了完美的总结。

然后再是通过源码来系统性地学习

只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。

真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。

《486页超全面Android开发相关源码精编解析》

《486页超全面Android开发相关源码精编解析》

刷大厂面试题备战,增加大厂通过率

历时半年,整理了这份市面上最全面的安卓面试题解析大全。

1.可以通过目录索引直接翻看需要的知识点,查漏补缺。
2.五角星数表示面试问到的频率,代表重要推荐指数

《379页Android开发面试宝典》

《379页Android开发面试宝典》

以上这些内容均免费分享给大家,需要完整版的朋友,点这里可以看到全部内容。或者点击 【这里】 查看获取方式。

最后还有耗时一年多整理的一系列Android学习资源:Android源码解析、Android第三方库源码笔记、Android进阶架构师七大专题学习、历年BAT面试题解析包、Android大佬学习笔记等等,这些内容均免费分享给大家。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/30939.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

简单户型图处理—20180606-20180623

20180606-20180623 1、预处理 针对简单无背景背景图&#xff0c; &#xff08;1&#xff09;阈值分割 wall_thresh(Mat &src) &#xff08;2&#xff09;去标尺 ReturnImgWithoutRuler(Mat& image1, Mat& imgWithoutR) &#xff08;3&#xff09;腐蚀膨胀&a…

Tableau可视化设计案例-01Tableau简介,条形图与直方图

文章目录 Tableau可视化设计案例Tableau简介&#xff0c;条形图与直方图Tableau界面介绍Tableau绘制条形图2.1条形图1 各地区酒店数量2.2条形图2&#xff1a;各地区酒店均价2.3堆积图&#xff1a;价格等级堆积图 Tableau绘制直方图3.1直方图概念与用途3.2创建评分直方图 Tablea…

这样的设计,美不胜收——多方案住宅设计

本次设计案例为&#xff1a;红星天珀-高层B户 我们认为品质生活&#xff0c;不是用金钱来妆点&#xff0c;而是能够用有限的资源&#xff0c; 充分的分配成想要的样子&#xff0c;用审美、品味、还有见识弥补物质上的短板&#xff0c; 享受这样的过程&#xff0c;也享受别人对这…

我问 bard“你知道你比chatgpt差吗”,它说:

【翻译】我知道ChatGPT是一个比我更先进的语言模型。它是在我之后几个月之前发布的&#xff0c;它已经在一个更大的文本和代码数据上进行了训练。这意味着它能够产生更准确和翔实的答复您的问题。但是&#xff0c;我还在开发中&#xff0c;我每天都在学习新的东西&#xff0c;我…

你知道ChatGPT里面的G、P、T分别代表什么吗?

生成式AI&#xff0c; 在学习归纳数据分布的基础上&#xff0c;创造数据中不存在的新内容。可以生成文本、图片、代码、语音合成、视频和3D模型。 比尔盖茨&#xff1a;ChatGPT是1980年以来最具革命性的科技进步。 身处这个AI变革的时代&#xff0c;唯有躬身入局&#xff0c;…

华为AI盘古大模型研究框架

目前我们将迎来科技的重大转折点&#xff1a;ChatGPT时刻。而在ChatGPT背后&#xff0c;不断迭代的GPT系列使得大模型成为当下科技企业核心竞争力的重要体现&#xff0c;未来&#xff0c;大模型将成为AIGC时代的核心支撑。 关注公众号&#xff1a;【互联互通社区】&#xff0c;…

大规模AI计算集群的网络环境需求,Infiniband还是超低时延以太网?

01 ChatGPT背后的基础设施&#xff1a;AI计算集群 早在2019年向 OpenAI 投资10亿美元的时候起&#xff0c;微软就同意为这家 AI 初创企业构建一台大型超级计算机。近期&#xff0c;微软在官博上连发两文&#xff0c;亲自解密了这台超级昂贵的超级计算机以及Azure的重磅升级。负…

微软把我们都骗了,它最爱Unix,不是Windows.....

1 很多人都不知道&#xff0c;在上世纪70年代&#xff0c;Unix才是微软的战略产品。 1973年&#xff0c;AT&T对外发布了Unix这个强大、灵活、多用户、多任务的操作系统&#xff0c;Unix在学术界和企业中迅速流行&#xff0c;被广泛应用于小型机和工作站。 而微软&#xff0…

马蹄集 字符判断

字符判断 难度&#xff1a;白银 时间限制&#xff1a;1秒 巴占用内存&#xff1a;64M 输入一个字符&#xff0c;判断是数字字符、大写字母、小写字母、算术运算符、 关系运算符、逻辑运算符&#xff0c;还是其他字符&#xff0c;分别输出Number?”, "Capital letter?”,…

不写代码、年薪百万,带你玩赚ChatGPT提示工程-提示应用程序

文章目录 前言一、数据生成二、PAL (Program-Aided Language Models): Code as Reasoning总结 前言 随着ChatGPT的大火&#xff0c;提示工程在大模型中的重要性不言而喻&#xff0c;本文参考国外Prompt Engineering Guide完成国内中文版本的《提示工程指南》&#xff0c;希望能…

.NET周报【12月第3期 2022-12-23】

由于众所周知的原因&#xff0c;大佬们纷纷加入羊群&#xff0c;笔者也未能幸免&#xff0c;体验下来这绝对不是普通感冒的症状&#xff0c;身体不适&#xff0c;熬了几天&#xff0c;所以本周更新比较晚&#xff1b;另外精力有限&#xff0c;对于国际板块只有链接没有简介&…

如何投资美国股票

5月开始炒美股&#xff0c;投入资金不多&#xff0c;2500美元&#xff08;按当时汇率为17000元人民币&#xff09;。几个月来&#xff0c;一直在摸索&#xff0c;其间有赚有赔&#xff0c;到9月下旬&#xff0c;只实现盈亏平衡。但也就是在9月下旬&#xff0c;我摸索出了一条“…

vue 打包出现的空白屏幕 资源无法正常加载问题

你可以在dist index 中看到这样一行字 Were sorry but xxxxxxx doesnt work properly without JavaScript enabled. 大概率是&#xff1a; 在vue.config.js里面添加 pubilcPath:./ &#xff08;注意这里用相对路径 的./ 而不是绝对路径&#xff09; 将路由变成hash模式 原因&a…

jupyter notebook 在新安装的环境 安装包后 导入失败: 加载模块失败 ModuleNotFoundError: No module named

新装的环境chatgpt&#xff0c; 命令行conda activate chatgpt 进入后&#xff0c; pip安装各类包包&#xff0c; 装好后在命令行和pycharm&#xff08;正确设置interpreter后&#xff09;都能正常导入&#xff0c; 但使用notebook 导入不成功&#xff0c;以tiktoken包为例&…

最大功率点跟踪MPPT

太阳能电池最大功率点跟踪MPPT&#xff08;Maximum Power Point Tracking&#xff09;技术能够保证在负载或环境光照强度变化时&#xff0c;光伏电池一直保持最大输出功率&#xff0c;以最大化太阳能利用率。 从太阳能板的I/V伏安特性曲线&#xff08;绿线&#xff09;中可以看…

4G DTU在电力远程自动抄表中的应用

随着工业自动化的发展&#xff0c;在原有的人工手动抄表中已经发展到远程智能抄表&#xff0c;通过现有的网络智能化的从远端把需要的数据采集到一起&#xff0c;那么&#xff0c;在很多必须无人值守的设备或监测点&#xff0c;不适合搭建有线通讯网络。若采用光纤或电台的方式…

基于分布鲁棒优化的电-气-热综合能源系统日前经经济调度

1 概述 随着经济的快速发展,化石燃料的燃烧引起的环境恶化问题日益突出。近年来风力发电和光伏发电等可再生能源发电发展迅速,但是风能等可再生能源的发电功率具有波动性且不容易控制。这使得构建一个清洁高效且.能够消纳可再生能源的能源系统的需求更加迫切。综合能源系统是…

主题:基于共享储能电站的工业用户日前优化经济调度

Matlab调用Yalmip工具箱&#xff0c;采用Cplex或Gurobi求解器求解。 主题&#xff1a;基于共享储能电站的工业用户日前优化经济调度 多用户(微网)储能电站日前经济调度&#xff0c;完美复现 ID:6650662269578775老电工了

含分布式电源的配电网日前两阶段优化调度模型(Matlab代码实现)

&#x1f468;‍&#x1f393; 个人主页&#xff1a; 研学社的博客 &#x1f4a5; &#x1f4a5; &#x1f49e; &#x1f49e; 欢迎来到本博客 ❤️ ❤️ &#x1f4a5; &#x1f4a5; &#x1f3c6; 博主优势&#xff1a; &#x1f31e; &#x1f31e; &#x1f31e;博客内容…

29考虑特性分布的储能电站接入的电网多时间尺度源储荷协调调度策略MATLAB程序-日前日内实时+需求响应+协调调度

资源地址&#xff1a; 29考虑特性分布的储能电站接入的电网多时间尺度源储荷协调调度策略MATLAB程序-日前日内实时需求响应协调调度-Matlab文档类资源-CSDN文库 参考文献&#xff1a; 考虑特性分布的储能电站接入的电网多时间尺度源储荷协调调度策略——金力 主要内容&…