在 UIKit 中使用 Swift UI

3 年前
/ ,
1290
1
这篇文章上次修改于 3 年前,可能部分内容已经不适用,如有疑问可询问作者。

本文基于 Xcode 12.3 Swfit 5.3.2 iOS 14.3 macOS 11.2 构建

无意间发现好像不止可以在 Swift UI 中用上 UIKit,反过来亦然。

首先打开 Xcode 新建一个 Cocoa Touch 项目,interface 选择 Storyboard。

随后,新建一个 Swift UI File,命名为 ContentView.swift。文件会自动生成一个 ContentView 的 Swift UI View。

接下来需要把 Swift UI View 用在 UIKit 中,需要用到 Swift UI 中的 UIHostingController。这是可以把 Swift UI 包装成 UIView。

在 Main.stroyboard 中将 rootViewController 包装上一个 NavigtaionController,不用多说了。之后打开 ViewController.swift。在 viewDidLoad 中加上如下代码:

let uiButton = UIButton(type: .system)

uiButton.setTitle("Button", for: .normal)
uiButton.translatesAutoresizingMaskIntoConstraints = false
uiButton.addTarget(self, action: #selector(click), for: .touchUpInside)

view.addSubview(uiButton)

uiButton.snp.makeConstraints { make in
    make.center.equalTo(view)
}

方便起见,以上代码使用了 SnapKit,在运行之前请先下载安装 SnapKit

在再底下加个方法

@objc func click() {
    let vc = UIHostingController(rootView: ContentView())

    navigationController?.pushViewController(vc, animated: true)
}

OK, 现在可以 Run 了。点击中央的 Button 之后将会 Push 到一个由 Swift UI 构建的 View。

接下来,如果不用 PushViewController 的方式把 Swift UI View 直接挂载到 RootViewController。

将 ViewController 中 viewDidLoad 中代码替换成

super.viewDidLoad()
let hostVc = UIHostingController(rootView: ContentView())
view.backgroundColor = .systemBackground
let sview = hostVc.view as! UIView

view.addSubview(sview)
sview.snp.makeConstraints({ make in
    make.bottom.equalTo(view)
    make.top.equalTo(view)
    make.left.equalTo(view)
    make.right.equalTo(view)
    make.width.equalTo(view)
    make.height.equalTo(view)
})
1612689096600

1612689096600

然后我又发现了点好玩的东西。如何在 Swift UI 直接用上 UINavigationController 和 UITabBarController。

刺激。

NavigationController 外置的另一方式

如下写法能让 SwiftUI 内部识别到外层 UINavigationController,无需包裹 NavigationView 即可使用 NavigationLink,同时还能使用 UINavigationController 更完善的方法。

var hv = UIHostingController(rootView: TestView())
var myNavigationController = UINavigationController(rootViewController: hv)

struct TestView: View {
    var body: some View {
        Form {
            NavigationLink("Navigation", destination: EmptyView())
        }.navigationTitle("Test")
    }
}

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
    }
}
  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...