77百科网
当前位置: 首页 生活百科

移动端布局方案(移动端布局原理)

时间:2023-06-28 作者: 小编 阅读量: 1 栏目名: 生活百科

约束就是规则,这个规则能够表示出一个视图相对于另一个视图的位置。DeferredLayoutPass的主要作用是做容错处理。在涉及冲突发生时,AutoLayout会尝试break一些优先级低的约束,尽量满足最多并且优先级最高的约束。layoutIfNeeded:告知页面布局立刻更新。

1. 背景
  • 布局是界面展示的重要一环,前端展示:布局渲染
  • 需要适配多种屏幕
  • 既可以在 iPhone 上使用,又可以在 iPad 上使用
  • 可以在横屏下使用
  • 在不同的屏幕尺寸下,有不同的布局方式(比如屏幕小,就一行放一个,屏幕大一行放两个)
  • 良好的布局方式,可以加快代码的编码,提升扩展性,减轻cpu的压力,增加页面展示渲染速度,提升用户体验。
  • 文字,颜色,字体大小甚至各个视图控件布局都能够在发版之后能够修改以弥补一些前期考虑不周
2.各种布局方式比较2.0 autoresizing

iOS6 之前的自动布局方式,主要解决旋转和缩放问题

autoresizingMask是UIView的属性,使用起来比较简单。如果你的应用的界面比较简单,就可以使用autoresizing进行自动布局

typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {UIViewAutoresizingNone= 0,UIViewAutoresizingFlexibleLeftMargin= 1 << 0,UIViewAutoresizingFlexibleWidth= 1 << 1,UIViewAutoresizingFlexibleRightMargin= 1 << 2,UIViewAutoresizingFlexibleTopMargin= 1 << 3,UIViewAutoresizingFlexibleHeight= 1 << 4,UIViewAutoresizingFlexibleBottomMargin = 1 << 5};

属性值 | 含义UIViewAutoresizingNone 不进行自动布局,不随父视图的改变而改变UIViewAutoresizingFlexibleLeftMargin 自动调整与父视图左边距,保持右边距不变UIViewAutoresizingFlexibleWidth 自动调整本身的宽度,保持和父视图的左右边距不变UIViewAutoresizingFlexibleRightMargin 自动调整与父视图右边距,保持左边距不变UIViewAutoresizingFlexibleTopMargin 自动调整与父视图上边距,保持下边距不变UIViewAutoresizingFlexibleHeight 自动调整本身的高度,保持上边距和下边距不变UIViewAutoresizingFlexibleBottomMargin 自动调整与父视图的下边距,保持上边距不变

UIView的 autoresizesSubviews属性为YES时,上述属性才能生效,默认为YES。

2.1 autoLayout 原理

Auto Layout ,是苹果公司提供的一个基于约束布局,动态计算视图大小和位置的库,并且已经集成到了 Xcode 开发环境里

Auto Layout 的原理就是对线性方程组或者不等式的求解。

2.1.1 布局算法 Cassowary

布局算法 Cassowary:它通过将布局问题(相等关系和不等关系)抽象成线性等式(https://zh.wikipedia.org/wiki/线性方程组)和不等式(https://www.shuxuele.com/algebra/graphing-linear-inequalities.html)约束来进行求解;Cassowary 开发了一种规则系统,通过约束来描述视图间的关系。约束就是规则,这个规则能够表示出一个视图相对于另一个视图的位置。

2.1.2 Auto Layout 的生命周期)

Layout Engine布局引擎系统

Constraints Change 表示的就是约束变化,添加、删除视图时会触发约束变化。Activating 或 Deactivating,设置 Constant 或 Priority 时也会触发约束变化。Layout Engine 在碰到约束变化后会重新计算布局,获取到布局后调用 superview.setNeedLayout(),然后进入 Deferred Layout Pass。Deferred Layout Pass 的主要作用是做容错处理。如果有些视图在更新约束时没有确定或缺失布局声明的话,会先在这里做容错处理。

接下来,Layout Engine 会从上到下调用 layoutSubviews() ,通过 Cassowary 算法计算各个子视图的位置,算出来后将子视图的 frame 从 Layout Engine 里拷贝出来。在这之后的处理,就和手写布局的绘制、渲染过程一样了。所以,使用 Auto Layout 和手写布局的区别,就是多了布局上的这个计算过程。

关于界面的渲染我感觉有必要在这里说下 Render Loop.Render Loop 是一个每秒钟跑120次的一个进程,是为了确保所有的内容都能为每一个frame做好准备。Render Loop 一共包括三个步骤来更新约束,布局和渲染。

首先,每一个需要接收到更新约束的 view 会从子 view 向上传递,直到 window; 然后,每一个接收到的 view 开始 layoutsubviews,和更新约束是从相反的方向开始,layout 从 window 开始到每一个子 view 进行 layout。最后,每一个需要渲染的 view,和 layout 相同,从父 view 向子view 开始渲染。如下图:

Render Loop 布局和渲染

  1. 更新约束:从子视图向外层逐级更新约束,直到 window;
  2. Layout 调整:从外部向内,逐级视图获得自身的 Layout,每一个接收到的 view 开始 layoutsubviews;
  3. 渲染与展示:与 Layout 相同,呈现顺序从外向内,使得视图呈现出来;

Render Loop目的是为了避免重复的工作。举一个例子:一个UILable 需要一个约束来描述它的大小,但是有很多属性会影响他的大小,设置它的font,text size等等都会受到影响。当一个属性改变的时候,可能text其他属性也会被重新赋值,很有可能调用一堆属性的setter方法,这样效率会很低。

只需要调用updateConstraints 并指定好要更新的属性,Render Loop会帮助你计算好它的frame并完成渲染,从而避免多次设置的重复工作。

Render Loop的方法调用

在使用 Auto Layout 进行布局时,可以指定一系列的约束,比如视图的高度、宽度等等。而每一个约束其实都是一个简单的线性等式或不等式,整个界面上的所有约束在一起就明确地(没有冲突)定义了整个系统的布局。

在涉及冲突发生时,Auto Layout 会尝试 break 一些优先级低的约束,尽量满足最多并且优先级最高的约束。

  • setNeedsLayout:告知页面需要更新,但是不会立刻开始更新。执行后会立刻调用layoutSubviews。
  • layoutIfNeeded:告知页面布局立刻更新。所以一般都会和setNeedsLayout一起使用。如果希望立刻生成新的frame需要调用此方法,利用这点一般布局动画可以在更新布局后直接使用这个方法让动画生效。
  • layoutSubviews:系统重写布局。
  • setNeedsUpdateConstraints:告知需要更新约束,但是不会立刻开始。
  • updateConstraintsIfNeeded:告知立刻更新约束。
  • updateConstraints:系统更新约束。

约束内部原理

  1. 尽量不要删除所有的约束(Avoid removing all constraints);
  2. 若是一个静态约束,仅做一次添加操作即可;
  3. 仅改变需要改变的约束;
  4. 尽量不要做删除视图的操作,反之用 hide() 方法替代;

Q:到底应该使用苹果自己的布局还是第三方工具比如 Texture ?A:使用苹果公司的技术得到的技术升级是持续的,而第三方不再维护的可能性是很高的。苹果公司经过一番努力,终于在 iOS 12 上用到了 Cassowary 算法的界面更新策略,使得 Auto Layout 的性能得到了大幅提升;你的代码一行不变就能享受到耗时从指数级下降到线性的性能提升。而很多第三方库,会随着 iOS 系统升级失去原有的优势。

Q: A依赖B,B依赖C,C依赖D,BC有可能不存在,所以D的依赖有可能是ABC;A: B、C不存在即将其设置隐藏,高度为0或0.1; 表象不存在,深层存在,高或宽为0

2.1.2 约束优先级

约束优先级 – 为什么约束需要优先级?因为有的时候2个约束可能会有冲突。 比如:有一个UIView 距离父UIView的左右距离都是0,这是2个约束,此时再给此UIView加一个宽度约束,比如指定宽度为100,那么就会产生约束冲突了

content Hugging/content Compression Resistance就是2个UIView自带的模糊约束。而这两个约束存在的条件则是UIView必须指定了 Intrinsic Content Size

compression resistance为抗压缩约束,防止视图被压缩,约束默认的优先级为750(UILayoutPriorityDefaultHigh)。设置的API为:

- (void)setContentCompressionResistancePriority:(UILayoutPriority)priority forAxis:(UILayoutConstraintAxis)axis

axis参数表示方向,水平或者垂直

content hugging约束防止视图被拉伸,约束的默认优先级为250(UILayoutPriorityDefaultLow)。设置的API为:

- (void)setContentHuggingPriority:(UILayoutPriority)priority forAxis:(UILayoutConstraintAxis)axis

官方文档给出的视图与intrinsic content size:

View

Intrinsic content size

UIView and NSView

No intrinsic content size.

Sliders

Defines only the width

Labels, buttons, switches, and text fields

Defines both the height and the width.

Text views and image views

Intrinsic content size can vary.

链接:https://www.jianshu.com/p/8acbe2885731

2.1.3 Mansony

对autoLAyout的一层封装,使用函数式编程更加方便

actionmakeupdateremake 已有某类型约束,再添加不更新更新更新 没有某类型约束,再添加更新更新更新 是否删除已有约束不删除不删除全删

2.2 Flex-box 原理(web 布局方式)

盒装模型: 盒子的尺寸=内容尺寸(width height)内边距(padding)边框粗细(border)外边距(margin)

网页布局(layout)是 CSS 的一个重点应用。

2009年,W3C 提出了一种新的方案----Flex 布局,可以简便、完整、响应式地实现各种页面布局。目前,它已经得到了所有浏览器的支持,这意味着,现在就能很安全地使用这项功能。

Flex 是 Flexible Box 的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性。

flex-box 是web上的一种布局方式,也叫弹性布局

Flexbox解决了什么?

  1. 方向性 (传统布局方向是从左到右,从上至下)
  2. 弹性伸缩 (传统尺寸定义是通过像素等来精确定义)
  3. 元素对齐(可以做到插拔)

任何一个容器都可以指定为 Flex 布局。

采用 Flex 布局的元素,称为 Flex 容器(flex container),简称"容器"。它的所有子元素自动成为容器成员,称为 Flex 项目(flex item),简称"项目"。

领域特定语言(英语:domain-specific language、DSL)指的是专注于某个应用程序领域的计算机语言

2.3 Android的五大容器布局体系

Android中有六大布局,分别是:

2.3.1. LinearLayout(线性布局),

屏幕适配的使用 用的比较多的就是LinearLayout的weight(权重属性)

线性布局的话是我们用的最多的一个布局方式,一种好的布局习惯是利用LinearLayout的weight布局参数和RelativeLayout相对布局来完成界面的布局

线性布局是按照水平或垂直的顺序将子元素(可以是控件或布局)依次按照顺序排列,每一个元素都位于前面一个元素之后。线性布局分为两种:水平方向和垂直方向的布局。分别通过属性 android:orientation="vertical" 和 android:orientation="horizontal" 来设置。 android:layout_weight 表示子元素占据的空间大小的比例。

2.3.2. RelativeLayout(相对布局),

RelativeLayout 继承于 android.widget.ViewGroup,其按照子元素之间的位置关系完成布局的,作为 Android 系统五大布局中最灵活也是最常用的一种布局方式,非常适合于一些比较复杂的界面设计。

2.3.3. TableLayout(表格布局)

表格布局,适用于多行多列的布局格式,每个 TableLayout 是由多个 TableRow 组成,一个 TableRow 就表示 TableLayout 中的每一行,这一行可以由多个子元素组成。实际上 TableLayout 和 TableRow 都是 LineLayout 线性布局的子类。但是 TableRow 的参数 android:orientation 属性值固定为 horizontal,且 android:layout_width=MATCH_PARENT,android:layout_height=WRAP_CONTENT。所以 TableRow 实际是一个横向的线性布局,且所以子元素宽度和高度一致。

2.3.4. FrameLayout(帧布局),

FrameLayout 是最简单的布局了。所有放在布局里的控件,都按照层次堆叠在屏幕的左上角。后加进来的控件覆盖前面的控件。在 FrameLayout 布局里,定义任何空间的位置相关的属性都毫无意义。控件自动地堆放在左上角,根本不听你的控制。但是控件本身是可以控制自己内部的布局的。

2.3.5. AbsoluteLayout(绝对布局),

绝对布局中将所有的子元素通过设置 android:layout_x 和 android:layout_y 属性,将子元素的坐标位置固定下来,即坐标 (android:layout_x, android:layout_y) ,layout_x 用来表示横坐标,layout_y 用来表示纵坐标。屏幕左上角为坐标 (0,0),横向往右为正方,纵向往下为正方。实际应用中,这种布局用的比较少,因为 Android 终端一般机型比较多,各自的屏幕大小。分辨率等可能都不一样,如果用绝对布局,可能导致在有的终端上显示不全等。

2.3.6. GridLayout(网格布局)

GridLayout 使用虚细线将布局划分为行,列和单元格,同时也支持在行,列上进行交错排列 (虚线不存在的,是我们想象出来的)

一般使用 GridLayout 的流程如下

先定义组件的对齐方式 android:orientation 水平或者竖直,设置多少行与多少列设置组件所在的行或者列,记得是从 0 开始算的,不设置默认每个组件占一行一列设置组件横跨几行或者几列;设置完毕后,需要在设置一个填充:android:layout_gravity = "fill"

3. 性能比较

frame > flexBox > autoLayout/masony

测试布局的项⽬代码上传在 https://github.com/zhoujian12/MyDemos/tree/master/LayoutTest

4. 总结
  • 简单布局 可以直接frame解决
  • 追求性能和动态化;可以使用flexBox
  • 一般嵌套的布局autoLayout/masony 解决即可
5. 参考
  • Auto Layout 的生命周期
  • 自动布局 Auto Layout (原理篇)
  • WWDC 2018:高性能 Auto Layout
  • iOS 上的 FlexBox 布局
  • UIView中frame属性的内部实现
  • iOS 上的 FlexBox 布局
  • https://juejin.im/post/5caec612e51d456e4514f524
  • https://github.com/youngsoft/MyLinearLayout
    推荐阅读
  • 波士顿龙虾怎么做好吃又简单(波士顿龙虾好吃又简单的做法)

    我们一起去了解并探讨一下这个问题吧!波士顿龙虾怎么做好吃又简单准备食材:龙虾、奶油蘑菇汁、奶酪丝。龙虾虾背和胸前用剪刀剪开,掰开两半,挑出虾线,剪掉腮。龙虾泡30分钟,期间换几次水。烧开水,把龙虾放蒸屉中蒸10分钟取出,放在铺好锡纸的烤盘上。在龙虾上铺满奶油蘑菇汁,撒上马苏里拉奶酪丝放入烤箱,180度烤10-15分钟,至金黄即可。

  • 私人飞机空姐注意事项(空姐不会告诉你)

    私人飞机空姐注意事项如今人们的生活与大几十年前发生了翻天覆地的改变,人们的生活逐渐富足,交通便利了网络科技更是在生活之中随处可见,这些都能够感受到人类的进步中国的崛起。但如果是长途旅行,飞机一定是最为舒适快速的。飞机的价格比较昂贵,但是在搭乘飞机中往往也能够得到最为舒适的体验,还有诸多服务。

  • 柿子能和咸鸭蛋一起吃吗(柿子是可以咸鸭蛋一起吃吗)

    接下来我们就一起去了解一下吧!咸鸭蛋的原材料是鸭蛋,而正常情况下,柿子跟鸭蛋不建议一起吃。因为鸭蛋富含蛋白质还有钙元素等矿物质,在柿子中的鞣酸的作用下,很易凝固成块,即胃柿石,可能会出现呕吐、腹胀、腹痛、腹泻等。所以两种尽量避免食用。

  • 标新立异什么意思(标新立异的解释)

    我们一起去了解并探讨一下这个问题吧!标新立异什么意思标新立异,汉语成语,拼音是biāoxīnlìyì,通常指提出新的主张、见解或创造出新奇的样式。也指为了显示自己,故意显出自己的与众不同或者用往常不同的表达方式来吸引人。

  • 除痔疮妙招经验分享(只需要这个简单的动作)

    除痔疮妙招经验分享痔疮是肛肠科的常见疾病,虽然算不上什么大病,却困扰着很多人。提肛运动,也称撮谷道,就是有规律地向上提收肛门,然后放松,一提一松便是提肛运动。提肛运动的最佳时间是晚睡前或起床前,大小便后。提肛运动可以锻炼和强化支撑膀胱、大肠的肌肉,促进肛周血液循环,防治痔疮等肛肠科疾病。另外,还能提升中气,固肾缩尿。提肛运动可配合坐浴,效果更好。煎煮后,睡前外洗坐浴,每日1次。坐浴后做提肛运动。

  • 莲雾水果为啥那么难吃(一个莲雾八杯水)

    莲雾吃了有什么效果莲雾的味道比较平和,营养价值很高,含有的成分有膳食纤维、糖类、蛋白质、维生素B、C等,带有莲雾本身的香味,是天然的消热剂。小孩有消化不良时,可以用莲雾和食盐一起食用。莲雾有几种食法1、莲雾可以洗净直接食用。莲雾果实汁多味美,含营养物质脂肪、蛋白质、矿物质,莲雾的味道有清甜、淡香、丰富水分等特性,不但好吃,还清凉解渴,具有开胃、爽口及助消化等功能。

  • 怎样祛眼袋最有效(如何才能快速祛眼袋呢)

    怎样祛眼袋最有效现实生活中,相信有很多朋友都有眼袋,尤其是经常加班、熬夜的朋友,眼袋会更加明显,而眼袋的出现会让眼睛显得更苍老,想必很多爱美的朋友也希望自己可以拥有一双年轻美丽动人的眼睛,所以去眼袋成了很多人非常关心的一个问题,为此下面长小编将会为大家推荐一些快速祛眼袋的方法,如果你也有眼袋,就赶紧来看看吧。电波拉皮去眼袋快速便捷,很适合上班族朋友。

  • 银龙鱼和什么鱼混养好(银龙鱼有什么特点)

    跟着小编一起来看一看吧!银龙鱼和什么鱼混养好银龙鱼可以和地图鱼、鹦鹉鱼、刀鱼、飞凤、泰国虎、鲶鱼等鱼类混养,需要注意它们的生活环境。银龙鱼性情猛烈,能吞食小型鱼类,一般不宜与其它鱼混养,如果要混养,能与龙鱼饲养在同一个水族需要技巧,当然,如果鱼不能和谐相处的话就得立刻将它们分开。

  • 怎么查限号(高德地图怎么查限号)

    限号出行之电话查询可以通过国家专业的查询电话号码114进行相关查询,主要是通过向客服询问相关限号出行管理部门的电话号码,然后进行拨打相关号码进行询问。限号出行之交通管理局网站因为每个城市的规定不同,在查询的过程中要选择车牌相应城市的交通管理局网站进行登录查询。限号出行之手机违章软件随着手机时代的发展,很多相应的文章APP也出现于手机中。但若一天内连续出行,则将会被连续处罚。