You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中使用UIPageViewController实现双页翻书界面问题求助

解决UIPageViewController双页翻页跳转异常问题

问题根源分析

你的代码存在三个核心问题导致翻页直接跳转到最后一页:

  • 视图控制器初始化错误:第四到第六个VC的背景色被错误赋值给thirdViewController,导致后续VC的引用和属性混乱,索引判断失效。
  • DataSource方法滥用:viewControllerBefore/viewControllerAfter中手动调用setViewControllers违背了UIPageViewController的工作机制,系统会自动根据返回的VC处理翻页,手动设置会打断正常流程。
  • 索引逻辑错误:双页模式下的翻页索引计算逻辑有误,无法正确定位下一组双页的位置。

修正后的完整代码

import SwiftUI
import UIKit

class CustomPageViewController: UIPageViewController, UIPageViewControllerDelegate, UIPageViewControllerDataSource {

    // MARK: - DataSource Methods
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        guard let currentIndex = viewControllersList.firstIndex(of: viewController), currentIndex >= 2 else {
            return nil
        }
        // 返回上一组双页的第一个VC,系统会自动组合双页
        return viewControllersList[currentIndex - 2]
    }

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        guard let currentIndex = viewControllersList.firstIndex(of: viewController), currentIndex < viewControllersList.count - 2 else {
            return nil
        }
        // 返回下一组双页的第一个VC,系统会自动组合双页
        return viewControllersList[currentIndex + 2]
    }

    lazy var viewControllersList: [UIViewController] = []

    override func viewDidLoad() {
        super.viewDidLoad()
        self.dataSource = self
        self.delegate = self
        self.isDoubleSided = true

        // 修正:每个VC独立设置背景色
        let firstVC = UIViewController()
        firstVC.view.backgroundColor = .red

        let secondVC = UIViewController()
        secondVC.view.backgroundColor = .green

        let thirdVC = UIViewController()
        thirdVC.view.backgroundColor = .blue
        
        let fourthVC = UIViewController()
        fourthVC.view.backgroundColor = .yellow // 修正:给第四VC自己设置颜色
        
        let fifthVC = UIViewController()
        fifthVC.view.backgroundColor = .black // 修正:给第五VC自己设置颜色
        
        let sixthVC = UIViewController()
        sixthVC.view.backgroundColor = .magenta // 修正:给第六VC自己设置颜色

        viewControllersList = [firstVC, secondVC, thirdVC, fourthVC, fifthVC, sixthVC]

        // 初始化显示第一组双页
        setViewControllers([viewControllersList[0], viewControllersList[1]], direction: .forward, animated: true) { finished in
            print("初始双页设置完成")
        }
    }

    // MARK: - Spine Location Configuration
    func pageViewController(_ pageViewController: UIPageViewController, spineLocationFor interfaceOrientation: UIInterfaceOrientation) -> UIPageViewController.SpineLocation {
        if interfaceOrientation.isLandscape {
            // 确保当前显示的是双页
            if let currentVC = viewControllers?.first, let index = viewControllersList.firstIndex(of: currentVC) {
                let nextIndex = index + 1
                if nextIndex < viewControllersList.count {
                    setViewControllers([currentVC, viewControllersList[nextIndex]], direction: .forward, animated: false)
                }
            }
            return .mid
        } else {
            // 竖屏显示单页
            if let currentVC = viewControllers?.first {
                setViewControllers([currentVC], direction: .forward, animated: false)
            }
            return .min
        }
    }
}

// SwiftUI包装器
struct MyViewControllerRepresentable: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> CustomPageViewController {
        CustomPageViewController(transitionStyle: .pageCurl, navigationOrientation: .horizontal)
    }

    func updateUIViewController(_ uiViewController: CustomPageViewController, context: Context) {}
}

struct TestView : View {
    var body: some View{
        VStack{
            MyViewControllerRepresentable()
                .edgesIgnoringSafeArea(.all) // 让页面充满屏幕
        }
    }
}

关键修改说明

  1. 修复VC初始化错误:给每个VC独立设置背景色,避免属性覆盖导致的索引和显示混乱。
  2. 修正DataSource逻辑:移除setViewControllers的手动调用,改为返回对应索引的VC,让UIPageViewController自动处理双页组合和翻页过渡。
  3. 完善翻页索引计算:双页模式下每次翻页移动2个索引,确保从0-1到2-3再到4-5的正确跳转。
  4. 优化书脊位置逻辑:横屏时强制保持双页显示,竖屏时切换为单页,同时使用animated: false避免不必要的动画干扰。

内容的提问来源于stack exchange,提问作者shangod

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 15:04:53