I would like to create a UIScrollView
that cycles between 3 paging views infinitely while I change the subviews to hold different reusable view controllers giving the illusion of infinitely many screen while only allocating the resources for 3 screens at a time similar to a UICollectionView
.
Below is an attempt I've made at implementing such a view based on this answer Infinite UIScrollView however my project has not been working as expected.
Ive been trying to use 3 views as the basis for infinite scrolling and many labels as the subviews to be added and removed as the user scrolls.
import UIKit
class ViewController: UIViewController, UIScrollViewDelegate {
var scrollView:UIScrollView = {
let scrollView:UIScrollView = UIScrollView()
scrollView.backgroundColor = UIColor.orange
scrollView.translatesAutoresizingMaskIntoConstraints = false
return scrollView
}()
var labels:[CustomLabel] = [CustomLabel]()
var pages:[Page] = [Page]()
var visiblePages:Set<Page>!{
didSet{
print("visible pages count: \(recycledPages.count)")
}
}
var recycledPages:Set<Page>!{
didSet{
print("recycled pages count: \(recycledPages.count)")
}
}
var visibleLabels:Set<CustomLabel>!
var recycledLabels:Set<CustomLabel>!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
recycledPages = Set<Page>()
visiblePages = Set<Page>()
recycledLabels = Set<CustomLabel>()
visibleLabels = Set<CustomLabel>()
scrollView.contentSize = CGSize(width: view.bounds.width * 3, height: view.bounds.height)
scrollView.delegate = self
scrollView.isPagingEnabled = true
scrollView.indicatorStyle = .white
view.addSubview(scrollView)
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: view.topAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
])
configureLabels()
setUpPages()
for i in 0..<pages.count{
scrollView.addSubview(pages[i])
}
}
func setUpPages(){
let page1 = Page(),page2 = Page(),page3 = Page()
page1.backgroundColor = .red
page2.backgroundColor = .green
page3.backgroundColor = .blue
page1.index = 0
page2.index = 1
page3.index = 2
pages = [page1,page2,page3]
visiblePages = [page1,page2,page3]
setContentViewFrames()
}
func configureLabels(){
let label1 = CustomLabel(), label2 = CustomLabel(), label3 = CustomLabel()
label1.text = "label1"
label2.text = "label2"
label3.text = "label3"
label1.backgroundColor = .red
label2.backgroundColor = .green
label3.backgroundColor = .blue
labels = [label1,label2,label3]
setContentViewFrames()
}
// func dequeueRecycledPage()->CustomLabel?{
// let page = recycledPages.first
// if let page = page{
// recycledPages.remove(page)
// return page
// }
// return nil
// }
var currentIndex = 0
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if (scrollView.contentOffset.x < 0) {
let newOffset = CGPoint(x: scrollView.bounds.width + scrollView.contentOffset.x, y: 0)
scrollView.contentOffset.x = newOffset.x
rotateViewsRight()
}else if(scrollView.contentOffset.x > scrollView.bounds.size.width*2){
let newOffset = CGPoint(x: scrollView.contentOffset.x - scrollView.bounds.width, y: 0)
scrollView.contentOffset.x = newOffset.x
rotateViewsLeft()
}
print("current index: \(currentIndex)")
}
lazy var previousOffset:CGPoint = CGPoint()
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
print("currentIndex called")
if previousOffset.x < scrollView.contentOffset.x{
currentIndex += 1
}else if previousOffset.x > scrollView.contentOffset.x{
currentIndex -= 1
}
previousOffset = scrollView.contentOffset
}
func rotateViewsRight(){
let endView = pages.removeLast()
pages.insert(endView, at: 0)
setContentViewFrames()
}
func rotateViewsLeft(){
let endView = pages.removeFirst()
pages.append(endView)
setContentViewFrames()
}
func setContentViewFrames(){
for i in 0..<pages.count{
// let adjustedIndex = i % pages.count
// let view = pages[i]
// view.frame = CGRect(origin: CGPoint(x: view.bounds.width * CGFloat(i), y: 0), size: view.bounds.size)
pages[i].frame = CGRect(x: CGFloat(i)*view.bounds.width, y: 0, width: view.bounds.width, height: view.bounds.height)
let label = labels[currentIndex%labels.count]
label.text = "current label: \(currentIndex)"
label.frame = pages[i].frame
pages[i].addSubview(label)
}
}
func configurePage(forIndex index:Int){
}
func dequeueRecycledPage()->Page?{
let page = recycledPages.first
if let page = page{
recycledPages.remove(page)
return page
}
return nil
}
}