美文网首页Hacking with iOS: SwiftUI Edition
在SwiftUI视图中包装UIViewController

在SwiftUI视图中包装UIViewController

作者: 韦弦Zhy | 来源:发表于2020-06-19 20:00 被阅读0次

    \color{red}{\Large \mathbf{Hacking \quad with \quad iOS: SwiftUI \quad Edition}}

    {\Large \mathbf{Instafilter}}

    SwiftUI是构建应用程序的绝佳框架,但目前还远远不够完善——它有很多事情做不到,因此,如果您想添加更多高级功能,则需要学习与UIKit交流。有时,这是为了整合您为UIKit编写的现有代码(例如,如果您为拥有现有UIKit应用程序的公司工作),但有时是因为UIKit和Apple的其他框架向我们提供了我们想要展示在SwiftUI布局中的有用代码。

    在此项目中,我们将要求用户从其照片库中导入图片。UIKit随附了专用的代码来执行此操作,但尚未移植到SwiftUI,因此我们需要自己编写桥接。

    在编写代码之前,您需要了解三件事,所有这些都有点像UIKit 101,但是如果您仅使用SwiftUI,它们对您来说则是全新的东西。

    首先,UIKit有一个名为UIView的类,它是布局中所有视图的父类。因此,标签,按钮,文本字段,滑块等等——都是视图。

    其次,UIKit有一个名为UIViewController的类,该类旨在保存所有代码以使视图栩栩如生。就像UIView一样,UIViewController具有许多子类,它们可以完成各种工作。

    第三,UIKit使用一种称为委托的设计模式来确定工作在哪里进行。因此,在决定我们的代码如何响应文本字段的值更改时,我们将使用我们的功能创建一个自定义类,并让我们成为文本字段的委托。

    SwiftUI使我们的代码结构非常不同,不仅如此,我们主要将结构体用于视图而非类。但是,SwiftUI将UIViewUIViewController混合到单个View协议中,这使我们的代码更加简单。

    无论如何,所有这些都很重要,因为UIKit要求用户从其图库中选择照片的系统使用名为UIImagePickerController的视图控制器以及名为UINavigationControllerDelegateUIImagePickerControllerDelegate的委托协议。SwiftUI无法直接使用这两个,因此我们需要对其进行包装。

    我们将从简单开始,逐步发展。包装UIKit视图控制器要求我们创建一个符合UIViewControllerRepresentable协议的结构体。这是基于View的,这意味着我们定义的结构可以在SwiftUI视图层次结构体内使用,但是我们没有提供body属性,因为视图的主体是视图控制器本身——它仅显示UIKit传回的内容。

    符合UIViewControllerRepresentable确实需要我们实现两种方法:一种名为makeUIViewController(),用于创建初始视图控制器,另一种名为updateUIViewController(),其设计用于在某些SwiftUI状态更改时让我们更新视图控制器。

    按Cmd + N新建一个文件,选择“Swift File”,并将其命名为ImagePicker.swift。将import SwiftUI添加到新文件的顶部,然后为其提供以下代码:

    struct ImagePicker: UIViewControllerRepresentable {
        typealias UIViewControllerType = UIImagePickerController
    }
    

    这还不足以正确编译代码,但是当Xcode显示错误消息“Type ImagePicker does not conform to protocol UIViewControllerRepresentable”时,请点击错误左侧的红色和白色圆圈,然后选择“fix”。这将使Xcode编写我们实际需要的两个方法,实际上,这些方法实际上足以让Swift找出视图控制器的类型,因此您可以删除typealias行。

    您应该具有以下结构体:

    struct ImagePicker: UIViewControllerRepresentable {
        func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
            code
        }
    
        func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {
            code
        }
    }
    

    我们将不会使用updateUIViewController(),因此您只需删除代码(“code”)行,以使该方法为空,然后在第一个方法编写如下内容:

    let picker = UIImagePickerController()
    return picker
    

    不久我们将向其中添加更多代码,但这实际上是包装基本视图控制器所需的全部。

    我们的ImagePicker结构体是有效的SwiftUI视图,这意味着我们现在可以像其他任何SwiftUI视图一样在工作表中显示它。这个特定的结构体旨在显示图像,因此我们需要一个可选的Image视图来保存所选图像,以及确定该表是否在显示的某种状态。

    将此替换为当前的ContentView结构体:

    struct ContentView: View {
        @State private var image: Image?
        @State private var showingImagePicker = false
    
        var body: some View {
            VStack {
                image?
                    .resizable()
                    .scaledToFit()
    
                Button("Select Image") {
                   self.showingImagePicker = true
                }
            }
            .sheet(isPresented: $showingImagePicker) {
                ImagePicker()
            }
        }
    }
    

    继续并在模拟器或真实设备上运行它。当您点击按钮时,默认的UIKit图像选择器应向上滑动,以浏览所有照片,而当您选择其中一张时,它将消失。

    但是,尽管我们刚刚选择了一张图像,但在我们的视图中不会出现任何图像。您会看到,即使我们在视图中放置了SwiftUI图像,也没有将UIImagePickerController中的选择分配给它的任何地方。

    为了实现这一目标,需要一个全新的概念:coordinators。

    Wrapping a UIViewController in a SwiftUI view

    相关文章

      网友评论

        本文标题:在SwiftUI视图中包装UIViewController

        本文链接:https://www.haomeiwen.com/subject/wvubxktx.html