SwiftUI布局之原理以及GeometryReader

所属分类:ios | 发布于 2024-12-28

SwiftUI布局的核心原理是什么呢?

SwiftUI的布局是一个协商过程,主要分3个步骤

  • 父 view 提供一个建议 size
  • 子 view 根据自身的特性返回一个需求 size
  • 父 view 使用子 view 返回的 size 对子 view 进行布局

怎么理解呢,就一个原则:子 view 是否根据父视图给出的建议尺寸来返回需求尺寸,完全取决于父 view 和子 view 的预设规则。

比如VStack,它会在垂直维度上,分别向子 view 发送具有明确值的建议尺寸、未指定的建议尺寸、最大建议尺寸以及最小建议尺寸的信息,并获得子 view 在不同建议尺寸下的需求尺寸。VStack 会结合视图的优先级,它的父 view 给其建议尺寸,在摆放时对子 view 提出最终的建议尺寸。

先看代码

struct : View {
    var body: some View {
        Text("Hello Wrold!")
    }
}

布局过程是自上而下的,我们计算上面代码的 size

  • ContentView的父 view 为其提供了一个 size 等于全屏幕的建议尺寸
  • ContentView拿着该尺子去问其child,也即使Text,Text返回一个自身需要的size
  • 用返回的size在父view中布局

为什么是这样呢?这就要看view本身的Behaviors,也就是行为规则。

记住这句话:每个view对自己需要的 size,都有自己的想法

Behaviors

在SwiftUI中,view 在计算自己 size 的时候有不同的行为方式,我们分为 5 类:

  • 类似于Stack,他们会尽可能多的占据空间,让自己内部的内容展示完整。
  • 类似于Text,这种只返回自身需要的size,这类 view 的特点是极其“老实本分”,如果 size 不够,它会非常聪明的做一些额外的操作,比如换行、截断文本等等。
  • 类似于Image,默认情况下Image的 size 是固定的,它会忽略到布局系统建议的尺寸而总是返回图片的尺寸。调用.resizable()可让它接受建议尺寸,但是resizable会让图片拉伸,来让它填满建议尺寸的空间,通常图片应该是需要固定宽高比显示的,所以一般还要调用.aspectRatio()在resizable()后面组合使用。
  • 类似于Shape,这种给多大尺寸就使用多大尺寸。
  • 还有一些可能超出父 view 的 view。

来看例子2

struct ContentView: View {
    var body: some View {
        Text("Hello, World!")
            .frame(width: 200, height: 100)
            .background(Color.green)
            .frame(width: 400, height: 200)
            .background(Color.orange.opacity(0.5))
    }
}

上边这段代码基本上能够代表任何一个自定义view的情况了,不要忘记,在考虑布局的时候,是自下而上的

我们先考虑ContentVIew,他的父view给他的建议尺寸为整个屏幕的大小,我们称为size0,他去询问他的child,他的child为最下边的那个background,这个background自己也不知道自己的size,因此他继续拿着size0去询问他自己的child,他的child是个frame,返回了width400, height200, 因此background告诉ContentView他需要的size为width400, height200,因此最终ContentView的size为width400, height200。

很显然,我们也计算出了最下边background的size,注意,里边的Color也是一个view,Color本身是一个Shape,background返回一个透明的view

我们再考虑最上边的background,他父view给的建议的size为width: 400, height: 200,他询问其child,得到了需要的size为width: 200, height: 100,因此该background的size为width: 200, height: 100。

我们在看Text,父View给的建议的size为width: 200, height: 100,但其只需要正好容纳文本的size,因此他的size并不会是width: 200, height: 100

GeometryReader

为了更好的理解,我们引入GeomertryReader。

GeometryReader的主要作用就是能获取到父 view 建议的尺寸。

GeometryReader 是布局容器吗?

GeometryReader的布局逻辑是什么?

GeometryReader以一个布局容器的形式存在,其布局规则如下:

  • 它是一个多视图容器,其默认堆叠规则类似于 ZStack
  • 将父视图的建议尺寸( Proposed size )作为自身的需求尺寸( Required Size )返回给父视图
  • 将父视图的建议尺寸作为自身的建议尺寸传递给子视图
  • 将子视图的原点(0,0)置于 GeometryReader 的原点位置
  • 其理想尺寸( Ideal Size)为 (10,10)

 

 

 

 

文哥博客(https://wenge365.com)属于文野个人博客,欢迎浏览使用

联系方式:qq:52292959 邮箱:52292959@qq.com

备案号:粤ICP备18108585号 友情链接