ios - UIPageViewController 在 SwiftUI 中滑动 1 次后停止工作
问题描述
我正在关注 SwiftUI 的 Apple 教程,并在“与 UIKit 交互”( https://developer.apple.com/tutorials/swiftui/interfacing-with-uikit ) 下制作了一个 UIPageController。
在教程中,他们使用 State 属性来currentPage
更新PageView
. 我想进行一些实验,并决定将其嵌入到PageView
不同的视图中,并currentPage
在该父视图中进行属性更新。因此,很自然地,我将@State
属性更改为@Binding
属性PageView
,以便在父级中进行更新currentPage
。
但是,当我这样做时, UIPageController 停止工作并继续nil
从pageViewController(_:viewControllerBefore:) -> UIViewController?
第二次滑动返回。
这是代码,我将添加注释以使其不那么繁琐:
struct ContentView: View {
@State var currentPage = 0 // This is the new @State variable which should get updated.
var body: some View {
VStack {
PageView([Text("First page"), Text("Second Page"), Text("Third Page")],
currentPage: self.$currentPage) // Passed a binding to the State variable since I want that to be updated when the page changes.
Text("Page number: \(currentPage)") // Removing this fixes the problem, but I need it here.
}
}
}
struct PageView<Page: View>: View {
var viewControllers: [UIHostingController<Page>]
@Binding var currentPage: Int // This used to be an @State property, but I changed it to a binding since the currentPage variable is now being updated elsewhere (In the view above).
init(_ views: [Page], currentPage: Binding<Int>) {
self.viewControllers = views.map { UIHostingController(rootView: $0) } // Simply wrapping all the views inside ViewControllers for UIPageViewController to use.
self._currentPage = currentPage // Assigning the binding.
}
var body: some View {
PageViewController(controllers: self.viewControllers, currentPage: self.$currentPage)
}
}
struct PageViewController: UIViewControllerRepresentable {
var controllers: [UIViewController]
@Binding var currentPage: Int
func makeCoordinator() -> Coordinator { // Makes the coordinator, irrelevant to the problem
Coordinator(self)
}
func makeUIViewController(context: Context) -> UIPageViewController {
// I don't think the problem lies here.
let pageViewController = UIPageViewController(
transitionStyle: .scroll,
navigationOrientation: .horizontal)
pageViewController.dataSource = context.coordinator
pageViewController.delegate = context.coordinator
return pageViewController
}
func updateUIViewController(_ pageViewController: UIPageViewController, context: Context) {
// I don't think the problem lies here.
pageViewController.setViewControllers(
[self.controllers[currentPage]], direction: .forward, animated: true)
}
class Coordinator: NSObject, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
var parent: PageViewController
init(_ pageViewController: PageViewController) {
self.parent = pageViewController
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
// This is where I think the problem lies. When the line below is evaluated, nil is returned on the second swipe when it shouldn't be. It works on the first swipe but on the second swipe nil is returned and therefore nothing is presented.
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 == parent.controllers.count - 1 {
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
}
}
}
}
此外,从解决问题中删除,但我需要它Text
ContentView
- 所以删除它不是一个选项。
如果有人可以解释如何解决我的问题,我将非常感激。如果您太懒惰,则无需提供代码示例,简单的解释也应该可以完成工作。
提前致谢!
解决方案
刷新时在PageView
更新期间重新创建。避免这种情况的解决方案是确认。body
Text
PageView
Equatable
最简单的修复演示如下(仅修改部分)。使用 Xcode 11.4 / iOS 13.4 测试
注意:使用相同的 PageView,因为没有提供 PageView2
// ...
var body: some View {
VStack {
PageView([Text("First page"), Text("Second Page"), Text("Third Page")],
currentPage: self.$currentPage)
.equatable() // << here !!
Text("Page number: \(currentPage)")
}
}
struct PageView<Page: View>: View, Equatable { // << confirm !!
static func == (lhs: PageView<Page>, rhs: PageView<Page>) -> Bool {
return true // just for demo, make it meaningful on some property
}
// .. other code goes here
推荐阅读
- django - 如何将此 SQL 查询“翻译”为 django 中的查询集
- python - 总结所有正值和所有负值 Pandas
- macos - 我应该把 Pyqt4 脚本生成的文件放在哪里?
- amazon-ec2 - 带有 HTTPS 侦听器的 AWS 弹性负载均衡器。最终用户浏览器认为网站是安全的?
- sqlite - 我们如何将日期插入 SQLite 数据库
- html - CSS边框半径不适用于UIwebview
- matlab - fmincon 在输入参数上抛出错误
- vb.net - 如何在 vb.net 中的 if else 条件循环中获得总计数?
- python - 动态创建嵌套的for循环
- kotlin-exposed - 如何在 Kotlin Exposed 的一对多关系中设置级联类型?