我正在尝试创建一个UIScrollView
,其中包含无限多个水平滚动页面。我计划使用几个可重复使用的缓存ViewController的实例来填充页面。为了实现这一点,我试图通过在用户滚动时使用beforeViewController
,currentViewController
和afterViewController
来填充这三个位置,来创建与UIPageViewController类似的效果,因此总会有一个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
}
}
}
}