SwiftUI 和 UIKit 是两个强大的结构,使您能够为 iOS 应用程序创立美观且响应灵敏的用户界面。 SwiftUI 是一个现代的声明式结构,可让您运用简略简练的代码构建 UI。 UIKit 是一个经典的指令式结构,可让您彻底操控和灵活地操控 UI 的各个方面。
虽然 SwiftUI 是 iOS 开发的未来,但 UIKit 仍然遭到 Apple 和开发者社区的广泛运用和支持。您或许期望在项目中一起运用这两个结构的原因有很多
-
SwiftUI 不兼容的现有 UIKit 组件和库
-
逐渐增量地将旧版 UIKit 项目迁移到 SwiftUI
-
试验 SwiftUI 的特性和功能,而无需从头开始重写整个应用程序
-
创立结合了一举两得的混合界面
但是,将 SwiftUI 和 UIKit 结合起来并不总是简略或容易的。您需求了解并战胜一些挑战和陷阱。例如:
-
了解怎么 SwiftUI 和 UIKit 不同典范和架构之间的差距
-
了解怎么在 SwiftUI 视图中包装 UIKit 视图和视图操控器,反之亦然
-
了解怎么在 SwiftUI 和 UIKit 视图之间双向传递数据和通讯
-
跨两个结构办理 UI 的生命周期和状况
我将指导您了解 SwiftUI 和 UIKit 互操作性的基础知识和高级技能。我将向您展现怎么运用 UIViewRepresentable
和 UIViewControllerRepresentable
协议将 UIKit 组件与 SwiftUI 集成。我还将向您展现怎么运用 Coordinator
模式来处理杂乱的场景,例如导航、委托、回调等。最终,我将向您展现怎么运用 UIHostingController
和 SwiftUIHostingView
类将 SwiftUI 视图嵌入 UIKit 视图操控器和视图中
互操作性的重要性
SwiftUI 和 UIKit 是 iOS 应用程序开发中运用的两个盛行结构。 SwiftUI 是 Apple 最新的 UI 结构,专注于声明式方法,使创立用户界面变得更容易、更高效。另一方面,旧结构 UIKit 是根据指令式典范构建的,需求更多的手动工作和样板代码。
虽然 SwiftUI 兴起,UIKit 仍然是许多现有应用程序和库的重要组成部分。因此,了解怎么结合 SwiftUI 和 UIKit 关于想要运用这两个结构的优势一起保持与现有代码库的兼容性的开发人员至关重要
SwiftUI 和 UIKit 概述
SwiftUI 是 Apple 于 2019 年推出的根据 Swift 的现代 UI 结构。它运用声明性语法简化了创立用户界面的进程,使开发人员能够更简练地表达 UI 组件及其关系。另一方面,UIKit 是一个根据 Objective-C 的结构,自该平台诞生以来一直是 iOS 开发人员的首选。它提供了一组丰富的 UI 组件和东西,但依赖于或许愈加杂乱和冗长的指令式编程风格。
SwiftUI 和 UIKit 互操作性入门
先决条件 要遵循本攻略
-
Xcode (version 11 or later)
-
对 Swift 和 iOS 应用程序开发有基本了解
创立新项目 要创立新项目
-
发动 Xcode 并挑选新的 Xcode 项目
-
挑选“单视图应用程序”模板,然后单击“下一步
-
输入项目名称,挑选“Swift”作为言语,然后挑选“SwiftUI”作为用户界面。点击下一步。”
-
为您的项目挑选一个方位,然后单击“创立”。
将 UIKit 集成到 SwiftUI 中
我们将探索将 UIKit 组件集成到 SwiftUI 中的两种方法:UIViewRepresentable 和 UIViewControllerRepresentable。
运用 UIViewRepresentable
UIViewRepresentable 是一个协议,允许您创立包装 UIKit 视图的 SwiftUI 视图。要运用 UIViewRepresentable,请按照下列过程操作:
-
创立一个新的 Swift 文件并导入 SwiftUI 和 UIKit
-
定义一个契合 UIViewRepresentable 协议的结构体。
-
完成所需的方法:makeUIView(context:) 和 updateUIView (_:context:)
-
下面是在 SwiftUI 视图中包装 UIKit UILabel 的示例
import SwiftUI
import UIKitstruct UILabelWrapper: UIViewRepresentable {
var text: Stringfunc makeUIView(context: Context) -> UILabel { let label = UILabel() label.textAlignment = .center return label } func updateUIView(_ uiView: UILabel, context: Context) { uiView.text = text }
}
现在能够在 SwiftUI 视图中运用 UILabelWrapper
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
Text("SwiftUI Text")
UILabelWrapper(text: "UIKit UILabel")
}
}
}
完成 UIViewControllerRepresentable
UIViewControllerRepresentable 与 UIViewRepresentable 相似,但用于包装 UIKit 视图操控器而不是视图。要运用 UIViewControllerRepresentable,请按照下列过程操作:
-
创立一个新的 Swift 文件并导入 SwiftUI 和 UIKit
-
定义一个契合 UIViewControllerRepresentable 协议的结构体
-
完成所需的方法:makeUIViewController(context:) 和 updateUIViewController(_:context:)。
-
下面是在 SwiftUI 视图中包装 UIImagePickerController 的示例
import SwiftUI
import UIKitstruct ImagePicker: UIViewControllerRepresentable {
@Binding var image: UIImage?
@Environment(.presentationMode) var presentationModefunc makeUIViewController(context: Context) -> UIImagePickerController { let picker = UIImagePickerController() picker.delegate = context.coordinator return picker } func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {} func makeCoordinator() -> Coordinator { Coordinator(self) } class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate { let parent: ImagePicker init(_ parent: ImagePicker) { self.parent = parent } func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) { if let image = info[.originalImage] as? UIImage { parent.image = image } parent.presentationMode.wrappedValue.dismiss() } }
}
现在能够在 SwiftUI 视图中运用 ImagePicker,如下所示
import SwiftUI
struct ContentView: View {
@State private var image: UIImage?
@State private var showingImagePicker = false
var body: some View {
VStack {
if let image = image {
Image(uiImage: image)
.resizable()
.scaledToFit()
} else {
Text("Select an image")
}
Button("Pick Image") {
showingImagePicker = true
}
}
.sheet(isPresented: $showingImagePicker) {
ImagePicker(image: $image)
}
}
}
将 SwiftUI 集成到 UIKit 中
我们将演示怎么运用 UIHostingController 将 SwiftUI 视图集成到 UIKit 中,并将 SwiftUI 视图直接添加到 UIKit 组件中
运用 UIHostingController
UIHostingController 是一个 UIViewController 子类,能够保管 SwiftUI 视图。要运用 UIHostingController,请按照下列过程操作:
-
创立一个新的 SwiftUI 视图文件
-
在 UIKit 视图操控器中,导入 SwiftUI
-
运用 SwiftUI 视图作为其根视图实例化 UIHostingController。
-
将保管操控器添加为子视图操控器并 addSubview 其视图
下面是将 SwiftUI 视图添加到 UIKit 视图操控器的示例:
import UIKit
import SwiftUI
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let swiftUIView = SampleSwiftUIView()
let hostingController = UIHostingController(rootView: swiftUIView)
addChild(hostingController)
hostingController.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(hostingController.view)
NSLayoutConstraint.activate([
hostingController.view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
hostingController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
hostingController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
hostingController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
hostingController.didMove(toParent: self)
}
}
在此示例中,SampleSwiftUIView 是您要添加到 UIKit 视图操控器中的 SwiftUI 视图
将 SwiftUI 视图添加到 UIKit
您还能够运用 UIView 的 addSubview() 方法将 SwiftUI 视图直接添加到 UIKit 组件。为此,请按照下列过程操作:
-
在 UIKit 视图或视图操控器中,导入 SwiftUI。
-
创立一个 UIHostingController 实例,并将 SwiftUI 视图作为其根视图
-
将保管操控器的视图添加为 UIKit 视图的子视图
下面是将 SwiftUI 视图添加到 UIKit UIView 的示例
import UIKit
import SwiftUI
class CustomView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
let swiftUIView = SampleSwiftUIView()
let hostingController = UIHostingController(rootView: swiftUIView)
hostingController.view.translatesAutoresizingMaskIntoConstraints = false
addSubview(hostingController.view)
NSLayoutConstraint.activate([
hostingController.view.topAnchor.constraint(equalTo: topAnchor),
hostingController.view.leadingAnchor.constraint(equalTo: leadingAnchor),
hostingController.view.trailingAnchor.constraint(equalTo: trailingAnchor),
hostingController.view.bottomAnchor.constraint(equalTo: bottomAnchor)
])
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}