gpt4 book ai didi

uiviewcontroller - 更新 @EnvironmentObject var 以将数据传递给 SwiftUI 中的 PageViewController 会导致 ViewController 之间的滑动丢失

转载 作者:行者123 更新时间:2023-12-03 15:27:50 27 4
gpt4 key购买 nike

在我的 SwiftUI 应用程序中,我目前有一个使用 UIKit 实现的 PageViewController。它遵循 Apple 的 SwiftUI UIKit 集成中概述的传统 SwiftUI - UIKit 实现 tutorials .

我有填充 UIViewController 的数据,在传递给 PageViewController 的 Controller 数组中,由 @Environment 提供。多变的。在应用程序的不同屏幕中,您可以发出一个导致 Environment 对象更新的操作,触发位于 PageViewController 中的 ViewController 的重新渲染。

然而,这种重新渲染会导致问题,因为 ViewController 是用新标识符重新制作的,因此在 parent.controller 中找不到 viewController 的索引。类协调器 pageViewController 函数中的数组。这会导致索引默认为 nil 并禁用更新的 viewController 上的任何滑动。我仍然可以使用页面控制点在 viewController 之间导航,但我想确定如何更新 parent.controller 数组以包含新的 ViewController 并丢弃旧的。

经过数小时的搜索、调试和修补,我一直无法找到一种方法来重置父 Controller 数组,用新的 ViewController 替换已丢弃的旧 View 。下面是 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 填充数据的环境状态后,导致重新渲染,协调器类可以打印 Controller 数组,其中包括旧 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]
}

...
}


任何有关此问题的帮助或指导将不胜感激!

最佳答案

遇到同样的问题,最后几个小时,我找到了解决方法。

似乎这是一个错误。如果您查看 UIViewControllerRepresentable 循环,它应该从 Init > Coordinator > makeUIViewController > updateUIViewController 开始。

但是如果 PageViewController 中的页面得到更新(我们的案例)。页面由 SwiftUI 重新创建,很棒,但是 PageViewController 会从 Init > updateUIViewController 获得一个内部错误的创建周期。没有 makeUIViewController 既没有协调器。以某种方式创建了一个新的 UIPageViewController(如何?)导致您注意到的差异。

要解决该问题并强制重新创建 PageViewController,请在页面 View 代码中添加 .id(UUID),例如:

struct SGPageView<Page: View>: View {
var viewControllers: [UIHostingController<Page>]
@Binding var currentPage:Int

init(_ views: [Page], currentPage:Binding<Int>) {
self.viewControllers = views.map { UIHostingController(rootView: $0) }
self._currentPage = currentPage
}

var body: some View {
PageViewController(controllers: viewControllers, currentPage: $currentPage).id(UUID())
}
}

它会起作用,但您会注意到页面的滚动位置被重置。另一个错误;)

关于uiviewcontroller - 更新 @EnvironmentObject var 以将数据传递给 SwiftUI 中的 PageViewController 会导致 ViewController 之间的滑动丢失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59813507/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com