ios - 如何优化 UIPageViewController 使其具有类似于 tableView.dequeueReusableCell(withIdentifier :for:)?

标签 ios uitableview uipageviewcontroller

到目前为止,我遇到的大多数 UIPageViewController 教程都会在滑动到所需页面时动态创建 UIViewController

UIPageViewController 示例,未经优化

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var contentView: UIView!

    let dataSource = ["View Controller One", "View Controller Two", "View Controller Three", "View Controller Four"]

    var currentViewControllerIndex = 0

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        configurePageViewController()
    }

    func configurePageViewController() {

        guard let pageViewController = storyboard?.instantiateViewController(withIdentifier: String(describing: CustomPageViewController.self)) as? CustomPageViewController else {
            return
        }

        pageViewController.delegate = self
        pageViewController.dataSource = self

        addChild(pageViewController)
        pageViewController.didMove(toParent: self)

        pageViewController.view.translatesAutoresizingMaskIntoConstraints = false

        contentView.addSubview(pageViewController.view)

        let views: [String: Any] = ["pageView": pageViewController.view]

        contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[pageView]-0-|", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: views))

        contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[pageView]-0-|", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: views))

        guard let startingViewController = detailViewControllerAt(index: currentViewControllerIndex) else {
            return
        }

        pageViewController.setViewControllers([startingViewController], direction: .forward, animated: true)
    }

    func detailViewControllerAt(index: Int) -> DataViewController? {

        if index >= dataSource.count || dataSource.count == 0 {
            return nil
        }

        guard let detailViewController = storyboard?.instantiateViewController(withIdentifier: String(describing: DataViewController.self)) as? DataViewController else {
            return nil
        }

        detailViewController.index = index
        detailViewController.displayText = dataSource[index]

        return detailViewController
    }
}

extension ViewController: UIPageViewControllerDelegate, UIPageViewControllerDataSource {

    func presentationIndex(for pageViewController: UIPageViewController) -> Int {

        print ("presentationIndex \(currentViewControllerIndex)")

        return currentViewControllerIndex
    }

    func presentationCount(for pageViewController: UIPageViewController) -> Int {

        print ("presentationCount \(dataSource.count)")

        return dataSource.count
    }

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        let dataViewController = viewController as? DataViewController

        guard var currentIndex = dataViewController?.index else {
            return nil
        }

        print ("viewControllerBefore \(currentIndex)")

        if (currentIndex == 0) {
            return nil
        }

        currentIndex -= 1

        currentViewControllerIndex = currentIndex

        return detailViewControllerAt(index: currentIndex)
    }

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        let dataViewController = viewController as? DataViewController

        guard var currentIndex = dataViewController?.index else {
            return nil
        }

        print ("viewControllerBefore \(currentIndex)")

        if currentIndex == dataSource.count-1 {
            return nil
        }

        currentIndex += 1

        currentViewControllerIndex = currentIndex

        return detailViewControllerAt(index: currentIndex)
    }
}

但是,我几乎没有看到任何关于如何优化 UIPageViewController 来处理大量页面的示例。

为每个页面重新创建新的 UIViewController 似乎不是最佳解决方案,因为它会很慢。它还会占用不必要的内存空间,因为大部分屏幕外的 UIViewController 是不可见的。

我们怎样才能拥有类似于 tableView.dequeueReusableCell(withIdentifier:for:) 的东西?

我们可以重用那些之前创建的、当前不可见的UIViewController吗?

非常感谢任何有关如何正确实现这一点的代码示例或教程资源。谢谢。

最佳答案

动态创建 Controller 可能会导致一些故障,因此我通常有一些像 var viewControllers: [UIViewController] 这样的数组来存储我的页面 并实现UIPageViewControllerDataSource

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        guard let index = viewControllers.firstIndex(of: viewController), index > 0 else {
            return nil
        }

        currentViewControllerIndex = index - 1
        return viewControllers[currentViewControllerIndex]
    }

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        guard let index = viewControllers.firstIndex(of: viewController), index < viewControllers.count - 1 else {
            return nil
        }

        currentViewControllerIndex = index + 1
        return viewControllers[currentViewControllerIndex]
    }

为了减少内存使用,您可以在页面更改时释放 View Controller 的 View :

    var currentViewControllerIndex = 0 {
        didSet {
            let range = currentViewControllerIndex - 1...currentViewControllerIndex + 1

            for (offset, element) in viewControllers.enumerated() {
                if range ~= offset {
                    element.loadViewIfNeeded()
                } else {
                    element.view = nil
                }
            }
        }
    }

关于ios - 如何优化 UIPageViewController 使其具有类似于 tableView.dequeueReusableCell(withIdentifier :for:)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57175319/

相关文章:

objective-c - 我的 UINavBar 不响应触摸,并随 tableview 滚动

ios - Swift - 如何在 UIAlertController 中放置页面 View ?

ios - 如何从 PageController 应用程序禁用 page curl shadown?

ios - scrollToRowAtIndexPath 在 iOS 8 中不起作用

ios - 使用 xcode 4.6 从 ios 模拟到 ios 设备

c++ - __next_prime 符号未定义

objective-c - Xcode 4.2 与 Storyboard : Program received signal: “EXC_BAD_ACCESS”

ios - 如何在tableViewCell中获取准确的星星

ios - 在委托(delegate)回调中包装手动 UItableViewCell 取消选择

ios - UIPageViewController滑动时黑色背景多