SwiftUI 中布局的工作原理

1. SwiftUI 布局简介

在这个技术项目中,我们将探讨 SwiftUI 如何处理布局。有些事情已经解释过了,有些可能是你自己弄明白的,但更多的是你在这一点上想当然的事情,所以我希望一个详细的探索能真正为 SwiftUI 的工作方式提供一些启示。

在此过程中,您还将学习如何创建更高级的布局对齐,使用GeometryReader构建特殊效果,以及更多——我知道您会热衷于在自己的应用程序中部署的一些真正强大的功能。

继续使用单视图应用程序模板创建一个新的 iOS 项目,并将其命名为 layoutDageMetricy。您需要在资源目录中提供一个图像,以便遵循有关自定义对齐指南的章节,但它可以是任何您想要的——它实际上只是一个占位符。

2. SwiftUI 中布局的工作原理

所有的 SwiftUI 布局都有三个简单的步骤,理解这些步骤是每次获得优秀布局的关键。步骤如下:

  1. 父视图提供一个大小并询问其子视图的大小。

  2. 子视图根据自己的信息,它会选择自己的尺寸,而父视图必须尊重这个选择。

  3. 然后父视图在其坐标空间中定位子视图。

在幕后,SwiftUI 执行第四步:尽管它将位置和大小存储为浮点数,但在渲染时,SwiftUI 会将所有像素舍入到最接近的值,这样我们的图形仍然清晰。

这三条规则看起来很简单,但它们允许我们创建非常复杂的布局,每个视图都可以决定如何以及何时调整大小,而无需父级参与。

为了演示这些规则的实际操作,我希望您修改默认的 SwiftUI 模板以添加background()修饰符,如下所示:

struct ContentView: View {    var body: some View {        Text("Hello, World!")            .background(Color.red)    }}
复制代码

你会看到背景色紧紧围绕着文本本身——它只占用足够的空间来适应我们提供的内容。

hello,world

现在,想想这个问题:ContentView有多大?如您所见,ContentView的主体(它呈现的内容)是一些带有背景色的文本。所以ContentView的大小总是和它的主体大小一样,不多不少。这被称为 布局中立 (layout neutral):ContentView本身没有任何大小,而是可以根据需要进行调整以适应任何大小。

在 Project3 为什么 SwiftUI 的修饰符顺序很重要?中,我向您解释过,当您对视图应用修饰符时,我们实际上会得到一个名为ModifiedContent的新视图类型,它存储了原始视图及其修饰符。这意味着当我们应用修饰符时,进入层次结构的实际视图是修改后的视图,而不是原始视图。

在我们的简单background()示例中,这意味着ContentView中的顶层视图是背景,而内部是文本。背景和ContentView一样是布局中立的,因此它只会根据需要传递布局信息——您可以最终得到一系列布局信息,直到最终得到确定的答案。

如果我们把这个放到三步布局系统中,我们最终会有一个类似这样的对话:

  • SwiftUI:“嘿,ContentView,你自己拥有整个屏幕——你需要多少?“(父视图询问大小)

  • ContentView:“我不在乎;我是布局中立的。让我问我的孩子:嘿,背景,你可以使用整个屏幕——你需要多少?“(父父视图询问大小)

  • 背景:“我也不在乎;我的布局也是中性的。让我问我的孩子:嘿,Text,你可以把整个屏幕留给你自己——你需要多少?“(父视图询问大小)

  • Text:“嗯,我的文本是默认字体的‘Hello,World’,所以我需要X像素宽Y像素高。我不需要整个屏幕,只需要这个。”(孩子选择它的大小。)

  • 背景:“明白了。嘿,ContentView:我需要X * Y像素。”

  • ContentView:“了解。嘿,SwiftUI:我需要X * Y像素。”

  • SwiftUI:“好的。那么,这会留下很多空间,所以我会把你的尺寸放在中间。”(父视图在其坐标空间中定位子视图。)

所以,当我们说TText("Hello, World!").background(Color.red)),文本视图成为其背景的子视图。当涉及到视图及其修改器时,SwiftUI有效地从下到上工作。

现在考虑一下这个布局:

Text("Hello, World!")    .padding(20)    .background(Color.red)
复制代码

这一次对话更为复杂:padding()不再为其子级提供所有空间,因为它需要从每边减去20点,以确保有足够的空间填充。然后,当答案从文本视图返回时,padding()根据请求在每侧添加20个点来填充它。

所以,更像这样:

  • SwiftUI:ContentView,你可以拥有整个屏幕,你需要多少?

  • ContentView:背景,你可以有整个屏幕,你需要多少?

  • 背景:填充, 你可以有整个屏幕,你需要多少?

  • 填充:文本,你可以拥有整个屏幕每边减20点之后的大小,你需要多少?

  • 文本:我需要X * Y。

  • 填充:我需要X * Y加上每边20个点。

  • 背景:我需要X * Y加上每边20个点。

  • ContentView:我需要X * Y加上每边20个点。

  • SwiftUI:好的,我把你放在中间。

ps;iOS开发交流技术:欢迎你的加入,不管你是大牛还是小白都欢迎入驻 ,分享BAT,阿里面试题、面试经验,讨论技术, 大家一起交流学习成长

hello,world

如果你还记得为什么 SwiftUI 的修饰符顺序很重要?。也就是说,这个代码:

Text("Hello, World!")    .padding()    .background(Color.red)
复制代码

和这个:

Text("Hello, World!")    .background(Color.red)    .padding()
复制代码

产生两种不同的结果。希望现在您可以理解为什么:background() 是布局无关的,所以它通过询问子对象需要多少空间并使用相同的值来确定需要多少空间。如果 background() 的子级是文本视图,那么背景将非常适合文本,但是如果子级是 padding(),那么它将接收回调整后的值,包括填充量。

点击可获取Swift资料大全

这些布局规则带来了两个有趣的副作用。

首先,如果视图层次结构完全是布局中立的,那么它将自动占用所有可用空间。例如,形状和颜色是与布局无关的,因此,如果视图包含颜色而没有其他内容,它将自动填充屏幕,如下所示:

var body: some View {    Color.red}
复制代码

记住,Color.red本身就是一个视图,但由于它是布局中立的,所以可以以任何大小绘制。当我们在background()中使用它时,简化的布局对话是这样工作的:

  • 背景:嘿,文本,你可以有整个屏幕,你想要多少?

  • 文本:我需要X乘Y点;我不需要其余的。

  • 背景:好的。嘿,红色,你可以有X乘Y点,你想要多少?

  • 红色:我不在乎;我的布局是中性的,所以X乘Y点听起来不错。

第二个有趣的副作用是我们前面遇到的:如果我们在一个不能调整大小的图像上使用 frame(),我们会得到一个更大的 Frame,而图像内部没有改变大小。这在以前可能会令人困惑,但一旦将 Frame 视为图像的父对象,这就完全有意义了:

  • ContentView 提供了整个屏幕。

  • frame 报告它想要300x300。

  • 然后 frame 会询问里面的图像它想要什么尺寸。

  • 不可调整大小的图像返回固定大小例如:64x64。

  • 然后 frame 将图像定位在其自身的中心。

当你听苹果公司的 SwiftUI 工程师谈论修饰符时,你会听到他们把它们称为视图——“the frame view”、“ the background view”等等。我认为这是一个很好的心理模型,有助于准确地理解到底发生了什么:应用修饰符创建新的视图,而不仅仅是修改现有的视图。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容