【发布时间】:2020-01-19 19:14:49
【问题描述】:
在我的 SwiftUI 应用程序中,我目前有一个使用 UIKit 实现的 PageViewController。它遵循 Apple 的 SwiftUI UIKit 集成 tutorials 中概述的传统 SwiftUI - UIKit 实现。
我有填充 UIViewController 的数据,在传递给 PageViewController 的控制器数组中,由 @Environment 变量提供。在应用程序的另一个屏幕中,您可以发出导致 Environment 对象更新的操作,从而触发位于 PageViewController 中的 ViewController 的重新渲染。
但是,这种重新渲染会导致问题,因为 ViewController 是使用新标识符重新制作的,因此无法在 Class Coordinator pageViewController 函数的 parent.controller 数组中找到 viewController 的索引。这会导致索引默认为 nil 并禁用更新后的 viewController 上的任何滑动。我仍然可以使用页面控制点在 viewController 之间导航,但我想确定如何更新 parent.controller 数组以包含新的 ViewController 并丢弃旧的。
经过数小时的搜索、调试和修补,我无法找到一种方法来重置父控制器数组,用新的 ViewController 替换已丢弃的旧视图。下面是 PageViewController 的代码。
import SwiftUI
import UIKit
struct PageViewController: UIViewControllerRepresentable {
var controllers: [UIViewController]
@Binding var currentPage: Int
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIViewController(context: Context) -> UIPageViewController {
let pageViewController = UIPageViewController(
transitionStyle: .scroll,
navigationOrientation: .horizontal)
pageViewController.view.backgroundColor = UIColor.clear
pageViewController.dataSource = context.coordinator
pageViewController.delegate = context.coordinator
return pageViewController
}
func updateUIViewController(_ pageViewController: UIPageViewController, context: Context) {
pageViewController.setViewControllers(
[controllers[currentPage]], direction: .forward, animated: false)
}
class Coordinator: NSObject, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
var parent: PageViewController
init(_ pageViewController: PageViewController) {
self.parent = pageViewController
}
func pageViewController(
_ pageViewController: UIPageViewController,
viewControllerBefore viewController: UIViewController) -> UIViewController? {
print(parent.controllers)
print(viewController)
guard let index = parent.controllers.firstIndex(of: viewController) else {
return nil
}
if index == 0 {
return parent.controllers.last
}
return parent.controllers[index - 1]
}
func pageViewController(
_ pageViewController: UIPageViewController,
viewControllerAfter viewController: UIViewController) -> UIViewController? {
guard let index = parent.controllers.firstIndex(of: viewController) else {
return nil
}
if index + 1 == parent.controllers.count {
return parent.controllers.first
}
return parent.controllers[index + 1]
}
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
if completed,
let visibleViewController = pageViewController.viewControllers?.first,
let index = parent.controllers.firstIndex(of: visibleViewController) {
parent.currentPage = index
}
}
}
}
在更新填充给定 ViewController 数据的环境状态后,导致重新渲染,协调器类可以打印一个控制器数组,其中包括旧 ViewController 以及下面注释代码中的新 ViewController 但我有还没有找到一种可靠的方法来确保新的 ViewController 有效地替换旧的。
struct PageViewController: UIViewControllerRepresentable {
...
class Coordinator: NSObject, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
...
func pageViewController(
_ pageViewController: UIPageViewController,
viewControllerBefore viewController: UIViewController) -> UIViewController? {
print(parent.controllers)
// prints out array of ViewControllers including old ViewController that has now been
// discarded
// [<_TtGC7SwiftUI19UIHostingControllerVS_7AnyView_: 0x7fd595c93de0>,
// <_TtGC7SwiftUI19UIHostingControllerVS_7AnyView_: 0x7fd595c94be0>,
// <_TtGC7SwiftUI19UIHostingControllerVS_7AnyView_: 0x7fd595c96830>,
// <_TtGC7SwiftUI19UIHostingControllerVS_7AnyView_: 0x7fd595c976b0>]
print(viewController)
// prints out new ViewController that does not exist within the parent.controllers array
// and hence nil is returned from the guard
// <_TtGC7SwiftUI19UIHostingControllerVS_7AnyView_: 0x7fd593721710>
guard let index = parent.controllers.firstIndex(of: viewController) else {
return nil
}
if index == 0 {
return parent.controllers.last
}
return parent.controllers[index - 1]
}
...
}
任何有关此问题的帮助或指导将不胜感激!
【问题讨论】:
-
嘿,@DanielBarclay,你能分享你的代码,包括环境变量吗?在我的情况下,要么是页面没有在 PageViewController 中更新,要么是我在控制器中添加 ObservableObject 然后在页面中断之间滑动。 UUID hack 在我的情况下不起作用。
标签: uiviewcontroller swiftui uipageviewcontroller