SwiftUI中@ViewBuilder的相关知识点解密

前言

在SwiftUI框架中使用很多的注解,虽然使语法看上去非常简洁,但是增加了初学者的理解难度,这篇文章我们来看一下@ViewBuilder的相关知识。主要包括以下内容:

  1. resultBuilder/functionBuilder是什么以及用法
  2. ViewBuilder结构体
  3. @ViewBuilder修饰符的用法
  4. 使用@ViewBuilder完成一个自定义视图

@resultBuilder注解

@resultBuilder是在Swift5.4添加的,之前是叫@_functionBuilder,在这里我们可以简单了解一下它的作用。

一个类、结构体添加@resultBuilder注解时必须包含至少一个buildBlock方法,并且这个方法是static静态的。这个方法可以接收0个或多个参数,在函数内部确定了参数的组成形式。

比如下面这个例子:

@resultBuilder struct StringBuilder {
    static func buildBlock(_ string1: String, _ string2: String, _ string3: String) -> String {
        string1 + " - " + string2 + " - " + string3
    }
}

func test(@StringBuilder strings: () -> String) {
    print(strings())
}

test {
    "1"
    "2"
    "3"
}

StringBuilder是一个字符串构建者结构体,里面的buildBlock方法接收3个参数,并且在3个参数中间插入” - “作为函数的返回值。

test函数接收一个使用@StringBuilder修饰的名为strings的闭包作为参数,函数体是调用这个闭包并打印到控制台。

最后使用3个字符串作为参数调用test函数,执行这段代码后会得到”1 - 2 - 3”的输出结果

@ViewBuilder定义

先来看ViewBuilder的定义:

@resultBuilder struct ViewBuilder

ViewBuilder本质上是一个结构体,并且被@resultBuilder注解,也就是说ViewBuilder是一个reult builder(结果建造者)类型了。

ViewBuilder结构体有11个名为buildBlock的函数,分别接收从0到10个View类型的参数,因此在SwiftUI中一个接收@ViewBuilder类型参数的视图容器最多能接收10个子视图,如果不能满足需求可以通过拆分来增加子视图的个数。

@ViewBuilder的用法

使用@resultBuilder注解ViewBuilder结构体后,就可以用@ViewBuilder修饰闭包,这个闭包可以接收多个指定类型的对象,而这些对象会按照buildBlock函数的实现进行组织。

A custom parameter attribute that constructs views from closures.

这是Apple的官方文档对ViewBuilder的定义,简单来说ViewBuilder就是一个包含多个视图的闭包。

在SwiftUI框架中,所有的容器视图都是使用@ViewBuilder来修饰最后一个参数,因此这些容器视图可以接受多个子视图作为参数。比如HStack/VStack/ScrollView等。

// HStack
public struct HStack<Content> : View where Content : View {
    ...

    @inlinable public init(alignment: VerticalAlignment = .center, spacing: CGFloat? = nil, @ViewBuilder content: () -> Content)

    ...
}

这是HStack的初始化方法,其中前面的几个参数都是可选项,它们不在本篇文章的讨论范围内。

它的最后一个参数content的类型是一个返回值为Content的闭包,单看()->Content是一个没有参数的闭包,但是前面使用了@ViewBuilder修饰,这就是一个可以接收多个视图的闭包了,最终看起来像是这样的:(view1: Content, view2: Content....) -> Content。

下面我们通过自定义一个视图来看@ViewBuilder的用法。

实践

下面通过实现一个自定义的容器视图来展示@ViewBuilder的用法:

@ViewBuilder示例

自定义一个继承自View名为CustomContainerView的视图,它仅有一个接收@ViewBuilder类型参数的初始化方法,并使用常量content接收这个参数。

在body中构建当前视图:@ViewBuilder中可能包含多个子视图,因此使用VStack把这些子视图纵向排列,之后使用多个视图修改器自定义子视图的外观。

在源文件的第29行,ContentView中创建了CustomContainerView并给它传递了3个Text子视图。通过Xcode右侧的即时预览可以看到这三个子视图正是以我们在CustomContainerView中要求的方式展现出来——纵向排列、绿色的背景色、红色的文字颜色等。

总结

至此,关于@ViewBuilder的相关知识基本都涉及到了,相信通过本篇文章的学习你一定也对它有了一个非常全面的掌握,那么赶快到实战项目中用起来吧👍。

到此这篇关于SwiftUI中@ViewBuilder的文章就介绍到这了,更多相关SwiftUI中@ViewBuilder知识点内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • SwiftUI中@ViewBuilder的相关知识点解密

    前言 在SwiftUI框架中使用很多的注解,虽然使语法看上去非常简洁,但是增加了初学者的理解难度,这篇文章我们来看一下@ViewBuilder的相关知识.主要包括以下内容: resultBuilder/functionBuilder是什么以及用法 ViewBuilder结构体 @ViewBuilder修饰符的用法 使用@ViewBuilder完成一个自定义视图 @resultBuilder注解 @resultBuilder是在Swift5.4添加的,之前是叫@_functionBuilder,在

  • jQuery中ajax的相关知识点汇总

    前言 学习JavaScript的同学都知道, AJAX (async javascript and xml)翻译叫做异步的JavaScript和XML , 在原生js中使用发送网络请求也是一件麻烦事,每次都是那几个步骤. 我们先来回顾一下在原生js中如何发送一个 ajax 网络请求 经典4步曲 1.原生js的ajax网络请求 // IE9及以上 // const xhr = new XMLHttpRequest() // IE9以下 // const xhr = new ActiveXObjec

  • C++中引用的相关知识点小结

    目录 引用的概念 引用特性 常引用 使用场景 引用和指针的区别 总结 引用的概念 引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间. 比如:李逵,在家称为"铁牛",江湖上人称"黑旋风".那么这里的“铁牛”.“黑旋风”就称李逵的引用. 在程序中呢,引用的用法如下: 类型& 引用变量名(对象名) = 引用实体: 举个例子: void TestRef() { int a = 10; int&

  • 详解Lua中的变量相关知识点

    变量不过是存储到区域项目可以操作的名称.它可以容纳不同类型的值,包括函数和表格. 变量名可以由字母,数字和下划线.它必须以字母或下划线.大写和小写字母是不同的,因为Lua是区分大小写的.有八种基本类型值在Lua中: 在Lua,尽管我们没有变量的数据类型,我们基于该变量范围的三种类型. 全局变量:所有的变量默是全局除非显式地声明为局部. 局部变量:当类型被指定为局部的一个变量,它的范围是有限的在自己的范围内使用. 表字段:这是一种特殊类型的变量,可以除了nil,包括功能不放任何东西. 在Lua变量

  • JS中BOM相关知识点总结(必看篇)

    window对象 ECMAScript是JavaScript的核心,但是如果要在web中使用javascript,那么BOM(浏览器对象模型)才是真正的核心.BOM提供了很多对象,用于访问浏览器的功能,这些功能与任何网页内容无关. window对象:BOM的核心对象是window,它表示浏览器的一个实例.在浏览器中,window对象有双重角色,它既是通过javascript访问浏览器窗口的一个接口,又是ECMAScript规定的Global对象. 因此,所有全局作用域中声明的变量.函数都会变成w

  • mysql中null(IFNULL,COALESCE和NULLIF)相关知识点总结

    本文实例讲述了mysql中null(IFNULL,COALESCE和NULLIF)相关知识点.分享给大家供大家参考,具体如下: 在MySQL中,NULL值表示一个未知值,它不同于0或空字符串'',并且不等于它自身. 我们如果将NULL值与另一个NULL值或任何其他值进行比较,则结果为NULL,因为一个不知道是什么的值(NULL值)与另一个不知道是什么的值(NULL值)比较,其值当然也是一个不知道是什么的值(NULL值). 然而我们通常,使用NULL值来表示数据丢失,未知或不适用的情况. 例如,潜

  • R语言中因子相关知识点详解

    因子是用于对数据进行分类并将其存储为级别的数据对象. 它们可以存储字符串和整数. 它们在具有有限数量的唯一值的列中很有用. 像"男性","女性"和True,False等.它们在统计建模的数据分析中很有用. 使用factor()函数通过将向量作为输入创建因子. 例 # Create a vector as input. data <- c("East","West","East","North

  • python文件操作相关知识点总结整理

    本文汇总了python文件操作相关知识点.分享给大家供大家参考,具体如下: 总是记不住API.昨晚写的时候用到了这些,但是没记住,于是就索性整理一下吧: python中对文件.文件夹(文件操作函数)的操作需要涉及到os模块和shutil模块. 得到当前工作目录,即当前Python脚本工作的目录路径: os.getcwd() 返回指定目录下的所有文件和目录名:os.listdir() 函数用来删除一个文件:os.remove() 删除多个目录:os.removedirs(r"c:\python&q

  • JS运动相关知识点小结(附弹性运动示例)

    本文总结了JS运动相关知识点.分享给大家供大家参考,具体如下: 1.多物体运动框架所有东西都不能共用 2.document.title输出频率不能太高 3.在写JS时尽量避免写小数,因为计算机内部都是模拟的,而不是实际存储的 如:0.07*100 在JS运算里不是为7 var a=3; var b=3.00000000000000000001; alert(a=b); 输出的结果却是true 4.写程序思考时先思考一般,再思考特殊,写程序是,先排除特殊,然后写一般 if(特殊1) {} else

  • PHP类相关知识点实例总结

    本文实例总结了PHP类相关知识点.分享给大家供大家参考,具体如下: 最终类与最终方法 如果父类中的方法被声明为 final,则子类无法覆盖该方法.如果一个类被声明为 final,则不能被继承. final class a{} class a{ final public function A(){} } 抽象类与抽象方法 abstract class a { public abstract function func(); } class A extends a{ public function

随机推荐