swiftui-hosting-transitions

SwiftUI 允许使用 matchedGeometryEffect 视图修饰符在视图之间执行流畅的转场动画,但是当视图被包含在 UIHostingControllers 中时会发生什么呢?

当将 UIKit 项目迁移到 SwiftUI 时,许多开发者最初会将他们的视图包装在 UIHostingController 中,同时仍然使用 UIKit 进行导航。然而,这种方法限制了在 SwiftUI 视图之间实现自定义转场动画的能力。这个库旨在解决这个问题,提供了一个直接的方案,专门为 UIHostingController 设计,用于执行自定义的匹配几何转场动画。

在开发这个代码仓库的过程中,受到了关于 SwiftUI 中视图控制器转场动画的一篇文章的启发。

SwiftUI 中的 Hero 视图控制器转场动画

安装

如果您想在 SPM 项目中使用 Matched Transitions,只需将其添加到 Package.swift 文件中的 dependencies 中即可

dependencies: [
  .package(url: https://github.com/pbalduz/swiftui-hosting-transitions, from: "0.1.0")
]

然后,您可以将其作为依赖项包含在任何目标中

targets: [
  .target(
    name: "MyTarget",
    dependencies: [
      .product(name: "MatchedTransitions", package, "swiftui-hosting-transitions")
    ]
]

您也可以通过将其作为包依赖项添加到 Xcode 项目中。

用法

执行自定义转场动画的 API 非常简单,只需要两个步骤:识别应该动画的 SwiftUI 视图(源视图和目标视图),并将这些视图包装在 MatchedHostingController 中。

以下是如何识别要动画的视图的方法

struct FirstView: View {
  var body: some View {
    Color.red
      .frame(width: 100, height: 100)
      .matchedGeometry(id: "id", isSource: true)
  }
}

struct FirstView: View {
  var body: some View {
    Color.red
      .frame(maxWidth: .infinity)
      .frame(height: 100)
      .matchedGeometry(id: "id", isSource: false)
  }
}

然后我们只需要将视图包装在 MatchedHostingController 中,而不是 UIHostingController

class FirstViewController: MatchedHostingController<FirstView> {
  let state = MatchedGeometryState()
  
  init() {
    super.init(
      rootView: FirstView(),
      state: state
    )
  }
}

class SecondViewController: MatchedHostingController<SecondView> {
  init(state: MatchedGeometryState) {
    super.init(
      rootView: SecondView(),
      state: state
    )
  }
}

MatchedHostingController 继承自 UIHostingController,并保留了类似的初始化 API,但增加了一个 state 属性,该属性对于正确执行转场动画至关重要。 必须保留此属性的实例,因为它必须传递给目标视图控制器,以启用共享有关匹配视图的信息。

最后,为了在视图控制器之间进行导航,可以使用常规的导航控制器 API

// from FirstViewController
let vc = SecondViewController(state: state)
navigationController?.pushViewController(vc, animated: true)

演示

matched-transition-demo

下一步