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

iMessage扩展开发:用UIPageViewController实现双页面滚动切换

嘿,我来帮你把这个iMessage扩展里的UIPageViewController页面切换功能给补全并梳理清楚~你的基础代码已经搭好了视图控制器数组的架子,接下来只需要完成UIPageViewController的配置、数据源和代理逻辑就能实现左右滚动切换了。

完整实现步骤与代码

1. 定义UIPageViewController属性

首先在你的当前ViewController里添加UIPageViewController的实例属性:

private var pageViewController: UIPageViewController!

2. 补全视图控制器初始化方法

先把你没写完的newMessageViewController方法补全,假设你在Storyboard里给页面VC设置了标识符MessagePageVC,并且有自定义的MessagePageViewController用来接收页面标识:

private(set) lazy var orderedViewControllers: [UIViewController] = {
    return [self.newMessageViewController(pageNum: "Page1"), self.newMessageViewController(pageNum: "Page2")]
}()

private func newMessageViewController(pageNum: String) -> UIViewController {
    // 从Storyboard初始化自定义页面VC
    let vc = UIStoryboard(name: "MainInterface", bundle: nil)
        .instantiateViewController(withIdentifier: "MessagePageVC") as! MessagePageViewController
    // 给页面传递标识,用来区分内容
    vc.pageNumber = pageNum
    return vc
}

3. 初始化并配置UIPageViewController

在viewDidLoad里完成UIPageViewController的初始化、代理设置,并添加到当前视图:

override func viewDidLoad() {
    super.viewDidLoad()
    
    // 初始化UIPageViewController,指定滚动切换风格
    pageViewController = UIPageViewController(
        transitionStyle: .scroll,
        navigationOrientation: .horizontal,
        options: nil
    )
    // 设置数据源和代理,用来处理页面切换逻辑
    pageViewController.dataSource = self
    pageViewController.delegate = self
    
    // 设置初始显示的页面
    if let firstVC = orderedViewControllers.first {
        pageViewController.setViewControllers(
            [firstVC],
            direction: .forward,
            animated: true,
            completion: nil
        )
    }
    
    // 将pageVC添加到当前视图层级,适配Auto Layout避免尺寸问题
    addChild(pageViewController)
    view.addSubview(pageViewController.view)
    pageViewController.view.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
        pageViewController.view.topAnchor.constraint(equalTo: view.topAnchor),
        pageViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
        pageViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
        pageViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)
    ])
    pageViewController.didMove(toParent: self)
}

4. 实现数据源与代理协议

扩展当前ViewController,遵守UIPageViewControllerDataSource和UIPageViewControllerDelegate,处理页面切换的前后逻辑,还可以添加页面指示器:

extension YourCurrentViewController: UIPageViewControllerDataSource, UIPageViewControllerDelegate {
    // 返回当前页面的前一个页面
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        guard let currentIndex = orderedViewControllers.firstIndex(of: viewController) else { return nil }
        // 如果是第一个页面,返回nil则不能往左滚动;如果想循环切换,就返回orderedViewControllers.last
        return currentIndex == 0 ? nil : orderedViewControllers[currentIndex - 1]
    }
    
    // 返回当前页面的后一个页面
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        guard let currentIndex = orderedViewControllers.firstIndex(of: viewController) else { return nil }
        // 如果是最后一个页面,返回nil则不能往右滚动;循环切换的话返回orderedViewControllers.first
        return currentIndex == orderedViewControllers.count - 1 ? nil : orderedViewControllers[currentIndex + 1]
    }
    
    // 可选:显示页面指示器的总数量
    func presentationCount(for pageViewController: UIPageViewController) -> Int {
        return orderedViewControllers.count
    }
    
    // 可选:设置当前页面指示器的选中位置
    func presentationIndex(for pageViewController: UIPageViewController) -> Int {
        guard let currentVC = pageViewController.viewControllers?.first,
              let index = orderedViewControllers.firstIndex(of: currentVC) else { return 0 }
        return index
    }
}

5. 自定义页面ViewController示例

你的MessagePageViewController需要有接收页面标识的属性,用来区分不同页面的内容:

class MessagePageViewController: UIViewController {
    var pageNumber: String?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 根据pageNumber设置页面内容,比如标题、UI元素
        if let num = pageNumber {
            title = "页面\(num)"
            // 这里可以添加不同页面的专属UI逻辑
        }
    }
}

关键适配提示

  • iMessage界面适配:用Auto Layout约束而不是固定frame,确保在不同设备和iMessage的横竖屏状态下都能正常显示。
  • 循环切换开关:如果希望两个页面可以无限左右滚动,只需要把数据源方法里返回nil的地方改成对应首尾的视图控制器即可。
  • 性能优化:如果后续要扩展更多页面,可以考虑懒加载视图控制器,避免一次性初始化所有VC占用内存。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:59:03