bze12
bze12

Reputation: 783

SwiftUI + UIPageViewController, multiple view types

I want to use a UIPageViewController in my SwiftUI app, as demonstrated in this tutorial. However, the tutorial passes in identical view types as pages, and I want to pass in any type of view.

struct PageViewController<Page: View>: UIViewControllerRepresentable {
    var pages: [Page]
    @Binding var currentPage: Int
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

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

    func updateUIViewController(_ pageViewController: UIPageViewController, context: Context) {
        pageViewController.setViewControllers(
            [context.coordinator.controllers[currentPage]], direction: .forward, animated: true)
    }
    
    class Coordinator: NSObject, UIPageViewControllerDelegate {
        var parent: PageViewController
        var controllers = [UIViewController]()
        
        init(_ pageViewController: PageViewController) {
            parent = pageViewController
            controllers = parent.pages.map { UIHostingController(rootView: $0) }
        }
        
        func pageViewController(
            _ pageViewController: UIPageViewController,
            didFinishAnimating finished: Bool,
            previousViewControllers: [UIViewController],
            transitionCompleted completed: Bool) {
            if completed,
               let visibleViewController = pageViewController.viewControllers?.first,
               let index = controllers.firstIndex(of: visibleViewController) {
                parent.currentPage = index
            }
        }
    }
}


struct PageView<Page: View>: View {
    var pages: [Page]
    @State var currentPage = 0

    var body: some View {
        ZStack {
            PageViewController(pages: pages, currentPage: $currentPage)
        }
    }
}

struct PageView_Previews: PreviewProvider {
    static var previews: some View {
        PageView(pages: [
            Color.red,
            Color.blue 
            // I want to add other view types here
        ])
    }
}

If I change the array of pages in the PageView_Previews to something like [Color.red, Text("abc")], I get an error because they're not the same type. How do I get SwiftUI to allow heterogeneous View types here?

I can't use TabView with PageTabViewStyle (lots of bugs), so that's why I need to use this UIKit method.

Upvotes: 0

Views: 2112

Answers (1)

jnpdx
jnpdx

Reputation: 52312

You can wrap your pages in AnyView:

PageView(pages: [
            AnyView(Color.red),
            AnyView(Color.blue),
            AnyView(Text("Hi"))
])

Upvotes: 2

Related Questions