Многоразовые ViewControllers в ScrollView Передача по ссылке - PullRequest
1 голос
/ 10 апреля 2019

Я пытаюсь создать UIScrollView с бесконечным количеством горизонтально прокручиваемых страниц.Я планирую использовать экземпляры нескольких повторно используемых кэшированных ViewController для заполнения страниц.Чтобы добиться этого, я пытаюсь создать эффект, аналогичный UIPageViewController, используя beforeViewController a currentViewController и afterViewController, чтобы заполнить три позиции, когда пользователь прокручивает, так что всегда есть один viewController до и после текущегопользователь смотрит, чтобы перейти к.

Я бы хотел сохранить эти экземпляры равными изменяющимся viewControllers из моего кэша, но когда я прокручиваю взад-вперед, в конце концов у меня остается пустой ViewController.Я полагаю, что это вызвано передачей ссылочной природы ViewController и установкой одного равным другому.

Ниже код, который я создал, есть ли способ улучшить функциональность.Заранее благодарю за помощь.

import UIKit

class ViewController: UIViewController,UIScrollViewDelegate {

    var previousOffset:CGFloat = 0

    var viewControllers:[UIViewController] = [UIViewController](){
        didSet{
            print("viewControllers.count: \(viewControllers.count)")
        }
    }

    var beforeViewController:UIViewController?
    var currentViewController:UIViewController?
    var nextViewController:UIViewController?

    var scrollView:UIScrollView = {
        let scrollView = UIScrollView()
        scrollView.isPagingEnabled = true
        scrollView.backgroundColor = UIColor.lightGray
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        return scrollView
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        scrollView.delegate = self
        //3 Pages 
        scrollView.contentSize = CGSize(width: 3 * self.view.bounds.width, height: self.view.bounds.height)

        self.view.addSubview(scrollView)

        NSLayoutConstraint.activate([
            scrollView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0),
            scrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0),
            scrollView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0),
            scrollView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 0)
            ])

        currentViewController = getViewController()
        addViewController(viewController: currentViewController!, index: 0) { (view) in
            view.backgroundColor = UIColor.green
        }

        nextViewController = getViewController()
        addViewController(viewController: nextViewController!, index: 1) { (view) in
            view.backgroundColor = UIColor.purple
        }

    }

    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        let currentPage = scrollView.contentOffset.x/scrollView.bounds.width
        print("current page: \(currentPage)")
        if scrollView.contentOffset.x > previousOffset{
            print("User scrolled Forward")
            scrolledForwards(currentPage: Int(currentPage))
        }else if scrollView.contentOffset.x < previousOffset{
            print("User scrolled backwards")
            scrolledBackwards(currentPage: Int(currentPage))
        }
        previousOffset = scrollView.contentOffset.x
    }

    func getViewController()->UIViewController{
        let unusedViewControllers:[UIViewController] = self.viewControllers.filter({return $0.parent == nil})
        if let unusedViewController = unusedViewControllers.first{
            print("reusing viewController: \(viewControllers.count)")
            print("reusing viewController: \(unusedViewController.description)")
            return unusedViewController
        }else{
            let newViewController = UIViewController()
            self.viewControllers.append(newViewController)
            print("creating new viewController")
            return newViewController
        }
    }

    func addViewController(viewController:UIViewController,index:Int, completion: ((UIView)->Void)? = nil){
        self.willMove(toParent: viewController)
        self.addChild(viewController)
        guard let view = viewController.view else{
            removeViewController(viewController: viewController)
            fatalError("view controller sent without a view")
        }
        self.scrollView.addSubview(view)
        viewController.didMove(toParent: self)

        let offset = self.view.bounds.width * CGFloat(index)

        view.translatesAutoresizingMaskIntoConstraints = false

        NSLayoutConstraint.activate([
            view.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 0),
            view.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: offset),
            view.heightAnchor.constraint(equalTo: scrollView.heightAnchor, constant: 0),
            view.widthAnchor.constraint(equalTo: scrollView.widthAnchor, constant: 0)
            ])

        if let completion = completion{
         completion(view)
        }

    }

    func removeViewController(viewController:UIViewController?, completion: ((UIView)->Void)? = nil){
        viewController?.willMove(toParent: nil)
        viewController?.view.removeFromSuperview()
        viewController?.removeFromParent()


        if let completion = completion{
            completion(view)
        }

    }


    func scrolledForwards(currentPage:Int = 0){
        removeViewController(viewController: beforeViewController)
        let index = currentPage + 1
        self.beforeViewController = self.currentViewController
        self.currentViewController = self.nextViewController
        print("index: \(index)")
        if index > 2{
            print("There is no more forwards")
            return
        }
        self.nextViewController = getViewController()

                if nextViewController?.parent == nil{
                    let index = currentPage + 1
                    self.addViewController(viewController: nextViewController!, index: index) { (view) in
                        view.backgroundColor = .magenta
                    }
                }


    }

    func scrolledBackwards(currentPage:Int = 0){

        let index = currentPage - 1

        removeViewController(viewController: nextViewController)
        nextViewController = currentViewController
        currentViewController = beforeViewController
        print("index: \(index)")
        if index < 0{
            print("There is no more backwards")
            return
        }
        beforeViewController = getViewController()

        currentViewController?.view.backgroundColor = UIColor.brown

        if beforeViewController?.parent == nil{
            self.addViewController(viewController: beforeViewController!, index: index) { (view) in
                view.backgroundColor = .cyan
            }
        }

    }



}
...