0

I'm developing an iOS app using SwiftUI with UIKit's UIPageViewController with UIViewControllerRepresentable and I'm not good with UIKit. I have array of three view controllers which are UIHostingControllers to which I pass my SwiftUI view which is not very simple. When the app launches the second view controller is shown, but UIPageViewController does not prepare or pre-render the neighboring view controllers until I start swiping. At the moment when I start swiping the next view controller is getting updated (before swipe is finished). This causes a slight glitch on the first swipe that I'd like to avoid. After the first swipe, if I again swipe to that view controller the view update does not happen and further swipes are smooth without any glitches. So how can I prepare the neighbouring views when the app launches, maybe somehow manually render them, idk ...

struct ContentView: UIViewControllerRepresentable {

    @ObservedObject var viewModel: ViewModel

    var count: Int {
        viewModel.dayControllers.count
    }

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

        pageViewController.setViewControllers([viewModel.dayControllers[(count-1)/2]], direction: .forward, animated: false, completion: nil)

        return pageViewController
    }

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

class Coordinator: NSObject, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
    // Implementation of ordinary coordinator methods
}

here is view model

class ViewModel: ObservableObject {
    @Published var dayControllers: [UIViewController]
//...
    init() {
        // Initialize dayControllers with view controllers
        self.dayControllers = dayVMs.map { dayVM in
            UIHostingController(rootView: SomeView(dayVM: dayVM)
                .equatable()
            )
        }
    }
}

I tried somehow manually prepare them in makeUIViewController(context: Context) -> UIPageViewController function like

pageViewController.setViewControllers([viewModel.dayControllers[(count-1)/2]], direction: .forward, animated: true, completion: {_ in
    
    viewModel.dayControllers[(count-1)/2-1].loadViewIfNeeded()

    viewModel.dayControllers[(count-1)/2+1].loadViewIfNeeded()
})

Or call before and after methods in the same function

//        let _ = context.coordinator.pageViewController(uiViewController, viewControllerBefore: viewModel.dayControllers[(count-1)/2-1])
//        let _ = context.coordinator.pageViewController(uiViewController, viewControllerAfter: viewModel.dayControllers[(count-1)/2+1])

But it didn't work.

Maybe there is some straightforward solution, would be happy if someone could help

  • I can recommend you to use https://github.com/rechsteiner/Parchment. Also it has swiftUI support. This library does have ability as loading before scrolling. – EsatGozcu Aug 17 '23 at 20:21

0 Answers0