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

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

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

约束就是规则,这个规则能够表示出一个视图相对于另一个视图的位置。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
    推荐阅读
  • 莲子搭配什么煮去火(为健康做加法)

    莲子性寒,容易腹痛、腹泻的人食用莲子,会使胃部更加寒凉,从而会加重病情,加重身体的不适状况,所以最好不要服用。

  • 第三排折叠座椅(第三排折叠座椅靠背改装)

    通常只在MPV和SUV上会配有第三排座椅。车长较短的车型,第三排座椅对成年人来说腿部空间较局促,坐时间长了会感到疲劳。收折型的第三排座椅通常没有预留过道,上下车不够便利。但也有部分车型可从行李舱盖即后车门进入车厢,后车门采用整体向上掀、单扇侧开或左右对开,以方便乘客进入车厢。当然,要从后车门进入行李舱,第三排座椅只能采取左右折叠对挂式第三排座椅,否则不方便乘客进入第三排座椅。

  • 现磨豆浆做法和配方(现磨豆浆技术配方)

    可根据实际需要酌情选择是否加入豆浆增香剂或增稠剂。将黄豆用机器磨成黄豆粉,花生不用磨碎。则需要将制作好的特制玉米汁液放入容器中上锅蒸10分钟,后放入干净容器盛装,待第2天备用。

  • 墓地风水入门基础知识(墓地风水有猫腻)

    以人盘二十四方位对准外围盘二十八宿度数为基准。主灾祸疾病、事业败北、遭人杀害、或自己杀人犯罪被枪决、绝后无嗣。若旺砂与泄砂相连者,出女贵,外家落。土见乾、坤、艮、巽四木宿为"四煞砂"。罗经盘上二十四向,配二十八宿,有四金、四土、四水、四木。而火有八者,包括子午四甲庚丙王日月之火。又或前案及文笔峰高拱,其峰偏于井木犴,此为水去生木,旺中带泄之砂,文学虽好,不免书生潦倒贫寒,家徒四壁。

  • 护肤品的正确使用顺序和手法(护肤品使用顺序是什么)

    洗面奶有很多种,一定要使用对自己皮肤不过敏的,还有草本植物成分的不刺激皮肤的洗面奶。也可以取适量的化妆棉,轻轻擦拭,在脸部进行适度按压。但是不同的季节,要使用自己不一样的乳液,这样对皮肤的保护效果会更加的好,可以选择含有牛奶精华,美白成分,珍珠粉成分的乳液。乳液里面有其他护肤品所没有的高效保湿功能,防止皮肤过快的氧化。

  • 网纹吊兰怎么养 网纹吊兰图片

    网纹吊兰可以用吊盆的方式土栽,也可以利用珍珠岩、椰壳等材料无土栽植。生长期及时追加肥料营养,但肥液尽量不要溅到株体上。强光直射暴晒的环境下,网纹吊兰的叶片可能会被晒伤,出现打蔫、发黄、脱落的情况。

  • 怎样烤起司土豆(起司烤土豆需要用到哪些酱料)

    怎样烤起司土豆主料:浓缩车打芝士酱100克、土豆4个、红拉达酱120克、芸豆400克、墨西哥辣椒圈30克、葱片30克、冷冻玉米粒120克。辅料:植物油2茶匙。土豆涂上植物油,然后用叉子戳几次。烤土豆期间,拉达调味酱加入50ml水煮开即可,备用。切好葱片,洗净的红芸豆,蒸熟,解冻玉米粒。每个土豆淋上2汤匙拉达酱。将土豆放回烤箱3-5分钟,从烤箱中取出土豆,如果需要的话,可以淋上更多的拉达酱,然后撒上葱片。

  • 数控刀具原则有哪些(学会数控刀具命名编码规则)

    1984年,ISO国际标准化组织启动了ISO10303《工业自动化系统–产品数据表达与交换》项目,在ISO10303体系下有关于数控刀具的标准的ISO13399《切削刀具数据表达与交换》。这个标准的作用使不同牌子的数控刀具可以拥有相同的命名规则,当整个行业都使用相同的参数和定义时,从而使刀具数据在不同的软件及系统平台之间无缝转换变得更加容易,举个例子,下图可以看到三个不同牌子铣刀分别将直径称作D3、DC和D,在ISO13399标准中,铣刀直径将始终称作DCX。

  • 怀孕28天可以看得到孕囊么(怀孕几周能看到孕囊)

    怀孕后停经35天就可以看到孕囊。孕囊也叫“胎囊”,受精卵完成着床之后一边快速进行细胞分裂一边向四周扩占地盘,这些细胞形成细胞团形成胚层,然后组成羊膜和血管网包裹住非常幼小的小胚胎,所以说孕囊是胎盘的最原始形态,胎儿的发育需要胎囊(孕囊)的保护。伴随着孕囊长大到再消失的过程,我们可爱的宝宝也就出现啦。

  • 描写菊花的诗句 描写菊花的优美句子

    露水阳光让菊花更丰润,香满池岸绿满池岸,因此它从来不用羡慕寄生的瓦松是不是很高。耐寒唯有东篱菊,金粟初开晓更清。耐寒的只有东边篱笆旁的菊花,它花蕊初开,让早晨多了一份清香。