大师学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视图

图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 SwiftUI

struct TextView: UIViewRepresentable {
    @Binding var input: String
    
    func makeUIView(context: Context) -> UITextView {
        let view = UITextView()
        view.backgroundColor = UIColor.yellow
        view.font = UIFont.systemFont(ofSize: 17)
        view.delegate = context.coordinator
        return view
    }
    func updateUIView(_ uiView: UITextView, context: Context) {
        uiView.text = input
    }
    func makeCoordinator() -> CoordinatorTextView {
        return CoordinatorTextView(input: $input)
    }
}

class CoordinatorTextView: NSObject, UITextViewDelegate {
    @Binding var inputCoordinator: String
    
    init(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界面中的UITextView视图

图16-2:SwiftUI界面中的​​UITexView​​视图

✍️跟我一起做:创建一个多平台项目。根据示例16-3中的代码创建一个名为​​TextView.swift​​​的文件。根据示例16-4中的代码更新​​ContextView​​​视图。插入一段文本。应该会看到顶部的文本发生了变化。点击​​Clear​​按钮。会看到文本视图及顶部的视图中的文本被删除。

注意:​​UIViewRepresentable​​结构体可表示任意UIKit视图。实现会取决于想使用的视图。我们会在后续的章节中看到更多的示例。要学习UIKitUiKit视图,可参阅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 UIKit

class 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 SwiftUI

struct 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视图控制器

图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仓库​​

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/162638.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

optee4.0.0 qemu_v8的环境搭建篇(ubuntu20.10)

快速链接: . 👉👉👉 个人博客笔记导读目录(全部) 👈👈👈 付费专栏-付费课程 【购买须知】:【精选】ARMv8/ARMv9架构入门到精通-[目录] 👈👈👈文章目录 前提条件1、拉取代码2、下载工具链3、编译4、运行

Unity在Windows选项下没有Auto Streaming

Unity在Windows选项下没有Auto Streaming Unity Auto Streaming插件按网上说的不太好使最终解决方案 Unity Auto Streaming插件 我用的版本是个人版免费版&#xff0c;版本号是&#xff1a;2021.2.5f1c1&#xff0c;我的里边Windows下看不到Auto Streaming选项,就像下边这张图…

一起Talk Android吧(第五百五十三回:解析Retrofit返回的数据)

文章目录 1. 知识回顾2. 解析方法2.1 解析有效数据2.2 解析错误数据3. 示例代码4. 经验与总结4.1 经验分享4.2 内容总结各位看官们大家好,上一回中咱们说的例子是"Retrofit的基本用法",本章回中介绍的例子是" 如何解析Retrofit返回的数据"。闲话休提,言…

【南京】最新ChatGPT/GPT4科研技术应用与AI绘图及论文高效写作

2023年我们进入了AI2.0时代。微软创始人比尔盖茨称ChatGPT的出现有着重大历史意义&#xff0c;不亚于互联网和个人电脑的问世。360创始人周鸿祎认为未来各行各业如果不能搭上这班车&#xff0c;就有可能被淘汰在这个数字化时代&#xff0c;如何能高效地处理文本、文献查阅、PPT…

深入了解Java 8 新特性:lambda表达式基础

阅读建议 嗨&#xff0c;伙计&#xff01;刷到这篇文章咱们就是有缘人&#xff0c;在阅读这篇文章前我有一些建议&#xff1a; 本篇文章大概000多字&#xff0c;预计阅读时间长需要5分钟。本篇文章的实战性、理论性较强&#xff0c;是一篇质量分数较高的技术干货文章&#xf…

数据库选型与优化:策略与技巧的探讨

大家好&#xff0c;我是一名狂热的数据库程序员&#xff0c;最近鼓起勇气开始吐槽一下数据库&#xff0c;如有雷同&#xff0c;请对号入座。 名不副实的数据库类型 先说说最近的事&#xff0c;我们业务有很多图片要管理&#xff0c;老板说让我选个专业的图数据库&#xff0c;…

【LeetCode刷题-双指针】--360.有序转化数组

360.有序转化数组 方法&#xff1a;双指针 从两头计算&#xff0c;保存两端较小的值&#xff0c;高中抛物线知识&#xff0c;a>0&#xff0c;向上的抛物线&#xff0c;两端大中间小&#xff0c;从后往前存储计算结果&#xff1b;a<0&#xff0c;向下的抛物线&#xff0c…

[MySQL] MySQL表的约束

在前面的文章中提到了约束&#xff0c;是通过数据类型对字段产生的约束。但是数据类型约束很单一&#xff0c;需要有一些额外的约束&#xff0c;更好的保证数据的合法性&#xff0c;从业务逻辑角度保证数据的正确性。于是就引入了表的约束。 表的约束很多&#xff0c;这里主要介…

​软考-高级-系统架构设计师教程(清华第2版)【第17章 通信系统架构设计理论与实践(P614~646)-思维导图】​

软考-高级-系统架构设计师教程&#xff08;清华第2版&#xff09;【第17章 通信系统架构设计理论与实践&#xff08;P614~646&#xff09;-思维导图】 课本里章节里所有蓝色字体的思维导图

Vue3 函数式弹窗

运行环境 vue3vitetselement-plus 开发与测试 1. 使用h、render函数创建Dialog 建议可在plugins目录下创建dialog文件夹&#xff0c;创建index.ts文件&#xff0c;代码如下 import { h, render } from "vue";/*** 函数式弹窗* param component 组件* param opti…

强化学习在文生图中的应用:Training Diffusion Models with Reinforcement Learning

论文链接:Training Diffusion Models with Reinforcement Learning项目地址:Training Diffusion Models with Reinforcement Learning官方代码:https://github.com/kvablack/ddpo-pytorch/tree/maintrl实现:https://huggingface.co/docs/trl/ddpo_trainer🤗关注公众号 fu…

口袋参谋:一键下载任意买家秀图片、视频,是怎么做到的!

​对于淘宝商家来说&#xff0c;淘宝买家秀是非常的重要的。买家秀特别好看的话&#xff0c;对于提升商品的销量来说&#xff0c;会有一定的帮助&#xff0c;如何下载别人的买家秀图片&#xff0c;然后用到自己的店铺中呢&#xff1f; 这里我可以教叫你们一个办法&#xff01;那…

pdf如何让多张图片在一页

pdf保存为一页六张图片的方法是&#xff1a; 1、打开pdf查看器,打开文档。 2、点击【打印】图标进入打印程序&#xff0c;选择打印范围。 3、在【打印处理】选项,选择【每张张上放置多页】。 4、自定义每页放置的图片张数为六张&#xff0c;并对打印排版预览设置。 5、设置打印…

Halcon (2):Halcon基础知识

文章目录 文章专栏视频资源前言Halcon文档案例学习结论 文章专栏 Halcon开发 视频资源 机器视觉之C#联合Halcon 前言 本章我们主要讲解Halcon的基础语法 Halcon文档 按下F1&#xff0c;就可以看到Halcon的文档&#xff0c;不过都是纯英文的 如果不清楚参数如何使用&#x…

土地利用强度(LUI)综合指数

土地利用强度的概念可以解释为某一时间特定区域内人类活动对土地利用强度的干扰程度[1]&#xff0c;其不仅反映不同土地利用类型本身的自然属性&#xff0c;也体现了人类利用土地的深度和广度&#xff0c;进而揭示在人类社会系统干扰下土地资源自然综合体自然平衡的保持状态[2]…

解决/usr/lib/libstdc++.so.6: version `GLIBCXX_3.x.x‘ not found问题

目录 1、查找缺少库版本2、动态库版本与gcc版本对应关系3、查找 libstdc.so.6.0.x 库文件4、如果libstdc.so.6.0.21库文件已存在&#xff0c;则按照下面的步骤创建软链接即可4.1 拷贝、软连接4.2验证新的 libstdc.so.6.0.21 库文件是否生效 5、如果libstdc.so.6.0.21库文件不存…

Codeforces Round 909 (Div. 3)(A~G)(启发式合并 , DSU ON TREE)

1899A - Game with Integers 题意&#xff1a;给定一个数 , 两个人玩游戏&#xff0c;每人能够执行 操作&#xff0c;若操作完是3的倍数则获胜&#xff0c;问先手的人能否获胜&#xff08;若无限循环则先手的人输&#xff09;。 思路&#xff1a;假如一个数模3余1或者2&#…

计算机msvcr120.dll丢失的解决方法,分享多种亲测可靠的方法

在使用计算机的过程中&#xff0c;我们有时可能会遇到一些技术问题&#xff0c;其中之一就是提示丢失msvcr120.dll文件。当计算机提示丢失msvcr120.dll文件时&#xff0c;可能是由于某些程序无法找到这个文件&#xff0c;从而导致程序无法正常运行。那么我们需要如何解决修复好…

微服务下整合knife4j接口文档

前言:本文旨在解决微服务下通过网关访问所用服务的knife4j文档&#xff0c;无需再通过其他服务单独访问 功能模块配置&#xff1a; 1.配置类&#xff1a; 在这个文件中注意下basePackage的扫描路径&#xff0c;修改为对应controller下的路径。 Configuration EnableSwagger…

教你轻松解决win系统ucrtbased.dll丢失的问题,亲测有效!

ucrtbased.dll是一个动态链接库文件&#xff08;DLL&#xff09;&#xff0c;它是Windows操作系统中的一部分&#xff0c;主要负责提供操作系统和应用程序所需的函数和接口。这个文件包含了操作系统和应用程序共同使用的通用代码&#xff0c;以确保不同程序之间的兼容性和稳定性…