UIPageViewController 中的 SwiftUI scrollViewDidScroll 无法正常工作 [英] SwiftUI scrollViewDidScroll in UIPageViewController not work properly

查看:98
本文介绍了UIPageViewController 中的 SwiftUI scrollViewDidScroll 无法正常工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我关注了 Apple 的关于 interifying-with-uikit 的 SwiftUI 教程,我想得到 UIScrollViewcontentOffset ,所以我在 PageViewController 中定义了@Binding var progress: CGFloat,但在 scrollViewDidScroll 中,PageViewController 在我设置时将无法正常工作self.parent.progress = progress .

I followed Apple's SwiftUI tutorial about interfacing-with-uikit,I want to get the contentOffset of UIScrollView ,so I then defined@Binding var progress: CGFloat in PageViewController ,but in the scrollViewDidScroll,PageViewController will not work correctly when I set self.parent.progress = progress .

行为是当我滑动PageViewController时,它会自动返回.

The behavior is when I slide the PageViewController, it will automatically go back.

当我将 @Binding var progress: CGFloat 更改为 @State var progress: CGFloat 时,PageViewController 将起作用,但我需要的是@Binding 而不是 @State

When I change @Binding var progress: CGFloat to @State var progress: CGFloat, PageViewController will work ,but what I need is @Binding rather than @State

这是完整的代码

import SwiftUI
import UIKit

struct ContentView: View {
    var body: some View {
        PageView([Color.red,Color.green,Color.yellow])
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}



struct PageViewController: UIViewControllerRepresentable {
    var controllers: [UIViewController]
    @Binding var currentPage: Int
    @Binding var progress : CGFloat

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    func makeUIViewController(context: Context) -> UIPageViewController {
        let pageViewController = UIPageViewController(
            transitionStyle: .scroll,
            navigationOrientation: .horizontal)
        pageViewController.dataSource = context.coordinator

        for view in pageViewController.view.subviews {
            if view is UIScrollView {
                (view as! UIScrollView).delegate = context.coordinator
            }
        }

        return pageViewController
    }

    func updateUIViewController(_ pageViewController: UIPageViewController, context: Context) {
        pageViewController.setViewControllers(
            [controllers[currentPage]], direction: .forward, animated: true)
    }

    class Coordinator: NSObject, UIPageViewControllerDataSource, UIPageViewControllerDelegate ,UIScrollViewDelegate {
        var parent: PageViewController

        init(_ pageViewController: PageViewController) {
            self.parent = pageViewController
        }

        func pageViewController(
            _ pageViewController: UIPageViewController,
            viewControllerBefore viewController: UIViewController) -> UIViewController?
        {
            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
            }
        }

        func scrollViewDidScroll(_ scrollView: UIScrollView) {
            let width = scrollView.frame.size.width
            let offsetX = scrollView.contentOffset.x
            let progress = (offsetX - width) / width
            self.parent.progress = progress
        }

    }
}




struct PageView<Page: View>: View {
    var viewControllers: [UIHostingController<Page>]
    @State var currentPage = 0
    @State var progress : CGFloat = 0

    init(_ views: [Page]) {
        self.viewControllers = views.map { UIHostingController(rootView: $0) }
    }

    var body: some View {
        VStack {
            PageViewController(controllers: viewControllers, currentPage: $currentPage,progress: $progress)
        }
    }
}

struct PageView_Previews: PreviewProvider {
    static var previews: some View {
        PageView([Color.red])
    }
}

推荐答案

移动 setViewControllers 到创建位置,如下图

Move setViewControllers to place of creation, like below

    ...
    pageViewController.setViewControllers( // << here !!
        [controllers[currentPage]], direction: .forward, animated: true)
    return pageViewController
}

func updateUIViewController(_ pageViewController: UIPageViewController, context: Context) {
}

经过测试适用于 Xcode 11.2/iOS 13.2

Tested & works with Xcode 11.2 / iOS 13.2

这篇关于UIPageViewController 中的 SwiftUI scrollViewDidScroll 无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆