大师学SwiftUI第16章 - UIKit框架集成
其它相关内容请见虚拟现实(VR)/增强现实(AR)&visionOS开发学习笔记
SwiftUI是一套新框架,因此并没有包含我们构建专业应用所需的所有工具。这意味着我们会需要求助于UIKit(移动设备)和AppKit(Mac电脑)等原生框架所提供的工具。
我们已介绍过UIKit。它是一套SwiftUI在后台实现用于创建大部分视图和控件的框架。有些UIKit类用于运行应用(UIApplication)、加载图片(UIImage)、管理设备(UIDevice)及窗口(UIWindow),而另一些定义用于设置应用和场景(UiApplicationDelegate和UIWindowSceneDelegate)的代理。当然,该框架提供了我们创建界面所需的所有工具,包括两个创建和管理视图的基本类,称为UIView和UIViewController。
最后面这两个类,UIView和UIViewController,是在我们需要对SwiftUI界面添加UIKit特性时需要实现的类。UIView的子类用于在屏幕上显示信息,比如标签和图像,以及创建控件,比如按钮、滑块和开关。而UIViewController类的子类用于展示视图及包含处理它们的值和与用户交互的必要功能。为了将这些工具集成到SwiftUI界面中,SwiftUI框架定义了两个协议:UIViewRepresentable和UIViewControllerRepresentable。
Representable视图
UIViewRepresentable协议定义了一结构体,作为UIView类或其子类所创建对象的一层封装(wrapper)。实现这一协议的结构体可表示SwiftUI界面中的一个UIKit视图。创建及管理UIKit视图,结构体必须要实现如下的方法。
-
makeUIView(context: Context):该方法创建一个UIKit视图并返回。context参数是对提供视图状态信息的UIViewRepresentableContext类型结构体的引用。 -
updateUIView(UIViewType, context: Context):该方法通过一个绑定属性使用SwiftUI界面所提供的信息更新UIKit视图。第一个参数是对UIKit视图的引用,context参数是对提供视图状态信息的UIViewRepresentableContext类型结构体的引用。 -
dismantleUIView(UIViewType, coordinator: Coordinator):该类型方法为释放视图做准备工作。第一个参数是UIKit视图的指针,coordinator参数是将值发回SwiftUI界面的对象。 -
makeCoordinator():该方法创建的对将UIKit视图的信息传回给SwiftUI界面。
要在SwiftUI接口中包含一个UIView对象(或其子类所创建对象),我们需要定义一个实现UIViewRepresentable协议的结构体,并实现上述的方法。makeUIView()和updateUIView()方法是必选的。在makeUIView()方法中,我们必须创建并返回一个UIKit视图实例,updateUIView()法用于使用SwiftUI界面中所获取的值来更新视图。
下例中创建了一个蓝色背景的UIKit视图,并在SwiftUI视图中包含它。只需要用makeUIView()方法创建UIKit视图,但同时也要实现updateUIView()方法,因为协议有相应要求。
示例16-1:准备一个供SwiftUI使用的UIKit视图
struct MyCustomView: UIViewRepresentable {func makeUIView(context: Context) -> some UIView {let view = UIView()view.backgroundColor = UIColor(.blue)return view}func updateUIView(_ uiView: UIViewType, context: Context) {}
}
在每次创建新的MyCustomView结构体实例时调用makeUIView()方法。在该方法中,我们创建一个UIView视图,将背景色设置为蓝色并返回。因此,每次我们创建MyCustomView结构体实例的时候,会创建一个UIView并添加到SwiftUI实例之中,如下例所示。
示例16-2:在SwiftUI视图中显示UIKit视图
struct ContentView: View {var body: some View {VStack {MyCustomView().frame(width: 200, height: 150).padding()Spacer()}}
}
representable视图默认为弹性大小,但可以通过SwiftUI修饰符进行修改。本例中,我们使用frame()修饰符赋了固定的宽和高。

图16-1:SwiftUI界面中的UIKit视图
UIView对象创建一个空视图,但我们也可以实现接收其它用户输入的视图,如文本框、开关等。我们使用updateUIView()方法将SwiftUI视图中的值传递给UIKit视图。但如果想将UIKit视图中的值传递给SwiftUI界面,则需要实现makeCoordinator()方法。在这个方法中,我们必须创建一个coordinator对象实例并返回。coordinator是一个可将UIKit视图中的信息回发给Swift界面的对象,通常通过修改绑定属性实现。如何处理这些值取决于我们操作的UIkit视图的类型。例如,UITexView视图创建一个用户可输入多行文本的输入框,和SwiftUI中的TextEditor视图一样。这个视图通过调用代理方法上报改变。因此,要获取用户在UITexView中插入的文本并在SwiftUI中进行处理,我们需要创建一个实现UITextViewDelegate协议的coordinator类,并实现其方法。下例演示了如何创建一个UIViewRepresentable结构体来操作这个类。
示例16-3:对SwiftUI视图发送和接收值
import SwiftUIstruct TextView: UIViewRepresentable {@Binding var input: Stringfunc makeUIView(context: Context) -> UITextView {let view = UITextView()view.backgroundColor = UIColor.yellowview.font = UIFont.systemFont(ofSize: 17)view.delegate = context.coordinatorreturn view}func updateUIView(_ uiView: UITextView, context: Context) {uiView.text = input}func makeCoordinator() -> CoordinatorTextView {return CoordinatorTextView(input: $input)}
}class CoordinatorTextView: NSObject, UITextViewDelegate {@Binding var inputCoordinator: Stringinit(input: Binding<String>) {self._inputCoordinator = input}func textViewDidChange(_ textView: UITextView) {inputCoordinator = textView.text}
}
本示例创建了一个名为TexView的UIViewRepresentable结构体。结构体中有一个名为input的@Binding属性,接收值并传递给SwiftUI视图。在TexView结构体定义的下面,我们定义了一类名为CoordinatorTextView的类。这是我们视图的coordinator,任务是将值发回给SwiftUI视图。为此,我们通过一个关联TexView结构体中定义的input属性的@Binding属性对其初始化,然后实现一个代理方法,在用户插入或删了字符时执行。该方法获取输入框中的当前文本,因此我们将其赋值给那个@Binding属性,发回到SwiftUI视图。UIViewRepresentable结构体初始化时。CoordinatorTextView对象通过makeCoordinator()方法创建,因而该结构体在一开始就可接收和发送值了。
SwiftUI界面中的视图实现和之前相同。只需对存储添加一个@State属性,将值传递给input属性。
示例16-4:对UIKit视图接收和发送值
struct ContentView: View {@State private var inputText: String = "Initial text"var body: some View {VStack {HStack {Text(inputText)Spacer()Button("Clear") {inputText = ""}}TextView(input: $inputText)}.padding()}
}
以上视图定义了一个名为inputText的@State属性、一个显示其值的Text视图、一个用空字符串替换当前值的按钮以及自定义TextInput视图的一个实例。该视图获取到inputText属性的指针,与representable视图中的输入属性相关联,这样便可以来回传递值 。
用户在编辑器中输入或删除字符时,representable视图调用coordinator中的textViewDidChange()方法,该方法将文本视图中的当前值赋给inputCoordinator属性,也就赋给了input属性。这意味着值在@State属性中可用 ,并且Text视图可将其显示到屏幕上。而在用户点击Clear按钮时,我们将空字符串赋值给@State属性,系统执行representable视图中的updateUIView()方法,关联@State属性的@Binding属性的值被赋给了视图,文本视图被清除。

图16-2:SwiftUI界面中的UITexView视图
✍️跟我一起做:创建一个多平台项目。根据示例16-3中的代码创建一个名为TextView.swift的文件。根据示例16-4中的代码更新ContextView视图。插入一段文本。应该会看到顶部的文本发生了变化。点击Clear按钮。会看到文本视图及顶部的视图中的文本被删除。
注意:UIViewRepresentable结构体可表示任意UIKit视图。实现会取决于想使用的视图。我们会在后续的章节中看到更多的示例。要学习UIKit及UiKit视图,可参阅UIKit for MasterMinds等书。
Representable视图控制器
UIViewControllerRepresentable协议定义一个结构体,作为对UIViewController类及子类所创建对象的封装。该类展示一个可包含其它视图的视图,为窗口或整个屏幕定义界面,类似SwiftUI文件中所定义的视图。实现UIViewControllerRepresentable协议的结构体可在一个SwiftUI界面中展示这些视图控制器。创建及管理这个视图控制器,结构体必须实现如下方法。
-
makeUIViewController(context: Context):该方法创建一个UIKit视图控制器并返回。context参数是UIViewControllerRepresentableContext类型结构体的一个指针,提供视图控制器状态的相关信息。 -
updateUIViewController(UIViewControllerType, context: Context):该方法使用SwiftUI界面所提供的信息更新UIKit视图控制器。第一个参数是UIKit视图控制器的指针,context参数是UIViewControllerRepresentableContext类型结构体的一个指针,提供视图控制器状态的相关信息。 -
dismantleUiViewController(UIViewControllerType, coordinator: Coordinator):该类型方法为释放视图控制器做准备。第一个参数是UIKit视图控制器的指针,coordinator参数是是将值发回SwiftUI界面的对象。 -
makeCoordinator():该方法创建将UIKit视图控制器信息传回SwiftUI界面的对象。
UIKit视图控制器由UIViewController的子类创建。文件通过File菜单创建 ,但选取UIKit子类的选项称为Cocoa Touch Class。选择该选项后,Xcode会显示一个可输入文件名称的窗口,并可选择所创建子类相应的父类。本例中我们创建了一个继承UIViewController类的DetailViewController类。
示例16-5:创建一个UIKit视图控制器
import UIKitclass DetailViewController: UIViewController {override func viewDidLoad() {super.viewDidLoad()let label = UILabel()label.frame = CGRect(x: 20, y: 16, width: 250, height: 30)label.font = UIFont.systemFont(ofSize: 30)label.text = "Hello World!"view.addSubview(label)}
}
在初始化视图控制器类时,它创建一个表示界面的视图,将其赋值给view属性,并调用viewDidLoad()方法来告诉我们的代码视图已就绪。在这个方法中,我们可以执行所有必要的任务来初始化视图。在本例中,我们创建一个UILabel对象来在屏幕上显示文本。该对象类似SwiftUI的Text视图,但需要做一些配置。在我们的例子中,通过将CGRect值赋给frame属性来为其设置位置和大小,字体大小定义为30像素,赋值给要显示的文本,通过addSubview()方法将其添加给视图控制器的视图。
现在有了视图控制器,我们需要创建一个representable视图将其转为SwiftUI视图,如下例所示:
示例16-6:为UIKit视图控制器创建representable视图
import SwiftUIstruct MyViewController: UIViewControllerRepresentable {func makeUIViewController(context: Context) -> DetailViewController {let controller = DetailViewController()return controller}func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {}
}
UIViewControllerRepresentable协议类似UIViewRepresentable。我们必须定义一个实现此协议的结构体,然后添加创建和更新视图所需的方法。在本例中,我们仅定义了makeUIViewController(),因为只需要创建视图控制器的实例,来在屏幕上进行显示。以下的SwiftUI视图在用户点击按钮时在NavigationStack视图中加载该视图控制器。
图16-7:通过SwiftUI视图加载一个UIKit视图控制器
struct ContentView: View {var body: some View {NavigationStack {VStack {NavigationLink("Open UIKit View", destination: {MyViewController()}).buttonStyle(.borderedProminent)Spacer()}.padding()}}
}
以上视图包含一个加载MyViewController结构体实例的NavigationLink视图,因而可以从初始视图导航至结构体所创建的视图控制器,和常规SwiftUI视图的操作一样。

图16-3:SwiftUI界面中的UIKit视图控制器
✍️跟我一起做:选择屏幕顶部菜单中的File选项,新建一个文件。点击iOS版块中的Cocoa Touch Class图标,创建一个UIKit文件。在SubClass选项中选择UIViewController。插入名称DetailViewController并点击Next进行保存。使用示例16-5中的代码更新DetailViewController。用示例16-6中的代码创建一个名为MyViewController.swift的文件。使用示例16-7中的代码更新ContentView视图。运行应用,点击按钮打开UIKit视图控制器。
代码请见:GitHub仓库
相关文章:
大师学SwiftUI第16章 - UIKit框架集成
其它相关内容请见虚拟现实(VR)/增强现实(AR)&visionOS开发学习笔记 SwiftUI是一套新框架,因此并没有包含我们构建专业应用所需的所有工具。这意味着我们会需要求助于UIKit(移动设备)和AppKit(Mac电脑)等原…...
7.docker运行redis容器
1.准备redis的配置文件 从上一篇运行MySQL容器我们知道,需要给容器挂载数据卷,来持久化数据和配置,相应的redis也不例外。这里我们以redis6.0.8为例来实际说明下。 1.1 查找redis的配置文件redis.conf 下面这个网址有各种版本的配置文件供…...
unity教程
前言 伴随游戏行业的兴起,unity引擎的使用越来越普遍,本文章主要记录博主本人入门unity的相关记录大部分依赖siki学院进行整理。12 一、认识unity引擎? 1、Unity相关信息: Unity的诞生:https://www.jianshu.com/p/550…...
未定义与 ‘double‘ 类型的输入参数相对应的函数 ‘Link‘
报错 检查对函数"Link"得调用中是否缺失参数或参数数据类型不正确。 未定义与"double"类型的输入参数相对应的函数"Link"。 问题描述 网上搜了搜一般说是toolbox没有下载导致的,相当于调用的包本地没有。 但是我看看了 Robotics…...
为什么Transformer模型中使用Layer Normalization(Layer Norm)而不是Batch Normalization(BN)
❤️觉得内容不错的话,欢迎点赞收藏加关注😊😊😊,后续会继续输入更多优质内容❤️ 👉有问题欢迎大家加关注私戳或者评论(包括但不限于NLP算法相关,linux学习相关,读研读博…...
Vite - 配置 - 文件路径别名的配置
为什么要配置别名 别名的配置,主要作用是为了缩短代码中的导入路径。例如有如下的项目目录: project-name| -- src| -- a| --b| --c| --d| --e| -- abc.png| -- index.html| -- main.js如果想在 main.js 文件中使用 abc.png ,则使用的路径是 ࿱…...
phpStorm Xdebug调试 加FireFox浏览器
步骤1: [Xdebug] zend_extension“D:\phpstudy_pro\Extensions\php\php5.4.45nts\ext\php_xdebug.dll” xdebug.collect_params1 xdebug.collect_return1 xdebug.remote_enableOn xdebug.remote_hostlocalhost xdebug.remote_port9001 xdebug.remote_handlerdbgp ;…...
多维时序 | MATLAB实现PSO-BiGRU-Attention粒子群优化双向门控循环单元融合注意力机制的多变量时间序列预测
多维时序 | MATLAB实现PSO-BiGRU-Attention粒子群优化双向门控循环单元融合注意力机制的多变量时间序列预测 目录 多维时序 | MATLAB实现PSO-BiGRU-Attention粒子群优化双向门控循环单元融合注意力机制的多变量时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 …...
linux配置固定ip(两种方法)
首先刚下载的vm,刚创建的虚拟机,肯定是需要配置ip的 其次以前我的每次都是设置自动ip,这样每次登录都会自动获取ip地址,并且每次的ip都不相同。 ~方法: 开机登陆后 1)Cd /etc/sysconfig/network-scripts 2)Vi ifcf…...
什么是缓存雪崩、击穿、穿透?
背景 数据一般是存储于数据库中,数据库中的数据都是存在磁盘上的,磁盘读写的速度相较于内存或者CPU中的寄存器来说是非常慢的了。 如果用户的请求都直接访问数据库的话,请求数量一上来,数据库很容易就崩溃了,所以为了…...
可以通过电脑远程控制安卓设备的软件
有些时候,我们需要用电脑远程控制安卓设备,比如远程维护门店设备、安卓系统的户外广告牌等等。我们来探索和比较几款允许用户通过电脑远程控制安卓设备的软件。 1、Splashtop Business Splashtop 是一种多功能远程访问解决方案,以其高性能流…...
HP惠普暗影精灵9笔记本电脑OMEN by HP Transcend 16英寸游戏本16-u0000原厂Windows11系统
惠普暗影9恢复出厂开箱状态,原装出厂Win11-22H2系统ISO镜像 下载链接:https://pan.baidu.com/s/17ftbBHEMFSEOw22tnYvPog?pwd91p1 提取码:91p1 适用型号:16-u0006TX、16-u0007TX、16-u0008TX、16-u0009TX、16-u0017TX 原厂系…...
vue2+elementUI 仿照SPC开发CPK分析工具
源码地址请访问 Vue CPK分析工具页面设计源码(支持左右可拖拽和表格可编辑、复制粘贴)仿照SPC开发-CSDN博客...
云ES使用集群限流插件(aliyun-qos)
aliyun-qos插件是阿里云Elasticsearch团队自研的插件,能够提高集群的稳定性。该插件能够实现集群级别的读写限流,在关键时刻对指定索引降级,将流量控制在合适范围内。例如当上游业务无法进行流量控制时,尤其对于读请求业务,可根据aliyun-qos插件设置的规则,按照业务的优先…...
2023.11.17 hadoop之HDFS进阶
目录 HDFS的机制 元数据简介 元数据存储流程:namenode 生成了多个edits文件和一个fsimage文件 edits和fsimage文件 SecondaryNameNode辅助NameNode的方式: HDFS的存储原理 写入数据原理: 发送写入请求,获取主节点同意,开始写入,写入完成 读取数据原理:发送读取请求,获取…...
如何在el-tree懒加载并且包含下级的情况下进行数据回显-01
在项目中做需求,遇到一个比较棘手的问题,el-tree懒加载在包含下级的时候,需要做回显,将选中的数据再次勾选上,在处理这个需求的时候有两点是比较困难的: el-tree是懒加载的,包含下级需要一层一…...
系列六、JVM的内存结构【栈】
一、产生背景 由于跨平台性的设计,Java的指令都是根据栈来设计的,不同平台的CPU架构不同,所以不能设计为基于寄存器的。 二、概述 栈也叫栈内存,主管Java程序的运行,是在线程创建时创建,线程销毁时销毁&…...
技巧篇:在Pycharm中配置集成Git
一、在Pycharm中配置集成Git 我们使用git需要先安装git工具,这里给出下载地址,下载后一路直接安装即可: https://git-for-windows.github.io/ 0. git中的一些常用词释义 Repository name: 仓库名称 Description(可选):…...
Yolov5
Yolov5 Anchor 1.Anchor是啥? anchor字面意思是锚,是个把船固定的东东(上图),anchor在计算机视觉中有锚点或锚框,目标检测中常出现的anchor box是锚框,表示固定的参考框…...
36、Flink 的 Formats 之Parquet 和 Orc Format
Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…...
测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...
【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...
Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...
NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...
tauri项目,如何在rust端读取电脑环境变量
如果想在前端通过调用来获取环境变量的值,可以通过标准的依赖: std::env::var(name).ok() 想在前端通过调用来获取,可以写一个command函数: #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...
MFE(微前端) Module Federation:Webpack.config.js文件中每个属性的含义解释
以Module Federation 插件详为例,Webpack.config.js它可能的配置和含义如下: 前言 Module Federation 的Webpack.config.js核心配置包括: name filename(定义应用标识) remotes(引用远程模块࿰…...
spring Security对RBAC及其ABAC的支持使用
RBAC (基于角色的访问控制) RBAC (Role-Based Access Control) 是 Spring Security 中最常用的权限模型,它将权限分配给角色,再将角色分配给用户。 RBAC 核心实现 1. 数据库设计 users roles permissions ------- ------…...
WEB3全栈开发——面试专业技能点P7前端与链上集成
一、Next.js技术栈 ✅ 概念介绍 Next.js 是一个基于 React 的 服务端渲染(SSR)与静态网站生成(SSG) 框架,由 Vercel 开发。它简化了构建生产级 React 应用的过程,并内置了很多特性: ✅ 文件系…...
Qwen系列之Qwen3解读:最强开源模型的细节拆解
文章目录 1.1分钟快览2.模型架构2.1.Dense模型2.2.MoE模型 3.预训练阶段3.1.数据3.2.训练3.3.评估 4.后训练阶段S1: 长链思维冷启动S2: 推理强化学习S3: 思考模式融合S4: 通用强化学习 5.全家桶中的小模型训练评估评估数据集评估细节评估效果弱智评估和民间Arena 分析展望 如果…...
