yout_ishida
@yout_ishida (悠斗 石田)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

SwiftUIからUIPageViewControllerを使用した際に生じる不具合について

SwiftUIでUIPageViewControllerを使用した際に、一度ページをめくると、その後、他のページに移動することができなくなる現象が生じて困っております。
解決方法をご教授いただけると幸いです。

エラーの発生を確認した環境は、Xcode 14.2 iOS15及びiOS16です。
参考にしたサイト→https://www.yururiwork.net/archives/750

問題を再現するコード

import SwiftUI

struct ContentView: View {
    @State var page = 1
    var body: some View {
        VStack{
            Text(page.description)
                .font(.title)
                .bold()
            PageView([Text("oo"),Text("kkkk"),Text("jjj")], currentPage: $page)
        }
    }
}

struct PageView<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 {
        VStack {
            PageViewController(controllers: viewControllers, currentPage: $currentPage)
        }
    }
}

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.dataSource = context.coordinator
        pageViewController.delegate = context.coordinator

        return pageViewController
    }

    func updateUIViewController(_ pageViewController: UIPageViewController, context: Context) {
        pageViewController.setViewControllers(
            [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?
        {
            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
            }
        }
    }

}

0

2Answer

iOS14から、UIPageViewControllerを使わなくても、TabViewと.tabViewStyleにPageTabViewStyleを組み合わせると、ページめくりが簡単に実装できるみたいです。

下記コードで10ページの左右ページめくりができました。

struct ContentView: View {
    @State private var selection = 0
    var body: some View {
        TabView(selection: $selection) {
            ForEach(0 ..< 10) { index in
                let page = index + 1
                HStack{
                    Text("\(page)")
                }
                .tag(index)
            }
            .font(.largeTitle)
        }
        .tabViewStyle(.page(indexDisplayMode: .automatic))
    }
}
0Like

Comments

  1. @yout_ishida

    Questioner

    ご教示ありがとうございます。
    私のアプリではTabViewを使うとカクついてしまうという別の問題が生じるため、pageViewControllerを使用しております。そのため、TabViewを使わずに解決したいと考えております。
  2. 直接の原因は`pageViewController:viewControllerBefore`と`pageViewController:viewControllerAfter`にある`guard文`により`nil`を返すことだと思います。引数でもらう`viewController`の値が怪しい?

下記の3行を削除すればちゃんと動きますね。理由は不明です。

//Text(page.description)
//    .font(.title)
//    .bold()
0Like

Your answer might help someone💌