I have a paging UIScrollView
, each page being populated with a different view controller. Above the scrollview is a UICollectionView
that acts as a menu bar. As you scroll through the scrollview pages, the menu bar moves just a little bit. You can see from the gif on the left.
Setting their delegates to different classes keeps everything working correctly as seen in the gif on the left. BUT, setting them to the same class messes up the UICollectionView
s behavior.
How do I set their delegates to the same class?
import UIKit
class MenuView: UIView, UICollectionViewDataSource {
let collcetionView: UICollectionView = {
let view = UICollectionView()
// Setup...
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupCollectionView()
collcetionView.dataSource = self
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
fileprivate func setupCollectionView() {
// Autolayout code...
}
// Datasource methods to populate collection view cells
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// Populate cell code...
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// Populate cell code...
}
}
class MainView: UIView {
// Contains paging scroll view and menu bar
var menu: MenuView!
let scrollView: UIScrollView = {
let view = UIScrollView()
// Setup...
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupMenu()
setupScrollView()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
fileprivate func setupScrollView() {
// Autolayout code...
}
fileprivate func setupMenu() {
menu = MenuView()
// Autolayout code...
}
}
class MainController: UIViewController, UIScrollViewDelegate, UICollectionViewDelegate {
var mainView: MainView!
override func loadView() {
super.loadView()
mainView = MainView()
view = mainView
}
override func viewDidLoad() {
super.viewDidLoad()
mainView.scrollView.delegate = self
mainView.menu.collcetionView.delegate = self // <<--- THIS IS WHAT BREAKS EVERYTHING
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
// Moving menu bar with page scroll
mainView.menu.collectionView.contentOffset = CGPoint(x: scrollView.contentOffset.x/SCROLL_FACTOR - (firstIndexPosition/SCROLL_FACTOR - difference/2), y: 0)
// Fade in and out highlighted state of menu bar cell
let exactPage = (scrollView.contentOffset.x / SCREEN_WIDTH)
let currentPage = (scrollView.contentOffset.x / SCREEN_WIDTH).rounded()
let unitExact = currentPage - exactPage
//print(String(format: "exact: %.2f, ", exactPage) + "current: \(currentPage), " + String(format: "unit: %.2f, ", unitExact))
if exactPage > currentPage {
// exact > current
// fade out/in left icon
// select current
let unit = 0 - unitExact // from 0 - 0.5
let cell = mainView.menu.collectionView.cellForItem(at: IndexPath(item: Int(currentPage), section: 0)) as! MenuBarCell
let mapped = unit.map(from: 0.0...0.5, to: 0...149.0)
print(cell)
setCellColor(cell: cell, value: mapped)
} else if exactPage < currentPage {
// exact < current
// fade out/in right icon
// select current
let unit = unitExact // from 0 - 0.5
let cell = mainView.menu.collectionView.cellForItem(at: IndexPath(item: Int(currentPage), section: 0)) as! MenuBarCell
let mapped = unit.map(from: 0.0...0.5, to: 0...149.0)
setCellColor(cell: cell, value: mapped)
} else if exactPage == currentPage {
// exact = current
// darken that icon
// select current
}
}
}
UICollectionView
and UITableView
inherit from UIScrollView
,
The scrollViewDidScroll
delegate method will be called for both your collection view and your scrollview if you set the delegate
for both objects to the same class.
You need to check why scrollViewDidScroll
is being called and act accordingly.
The simplest approach is a guard
statement that returns if the delegate method isn't called for the scroll view you are interested in.
If you needed to execute different code depending on the scroll view involved you could use a series of if
statements or a switch
statement.
func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard scrollView == self.scrollView else {
return
}
// Moving menu bar with page scroll
mainView.menu.collectionView.contentOffset = CGPoint(x: scrollView.contentOffset.x/SCROLL_FACTOR - (firstIndexPosition/SCROLL_FACTOR - difference/2), y: 0)
// Fade in and out highlighted state of menu bar cell
let exactPage = (scrollView.contentOffset.x / SCREEN_WIDTH)
let currentPage = (scrollView.contentOffset.x / SCREEN_WIDTH).rounded()
let unitExact = currentPage - exactPage
//print(String(format: "exact: %.2f, ", exactPage) + "current: \(currentPage), " + String(format: "unit: %.2f, ", unitExact))
if exactPage > currentPage {
// exact > current
// fade out/in left icon
// select current
let unit = 0 - unitExact // from 0 - 0.5
let cell = mainView.menu.collectionView.cellForItem(at: IndexPath(item: Int(currentPage), section: 0)) as! MenuBarCell
let mapped = unit.map(from: 0.0...0.5, to: 0...149.0)
print(cell)
setCellColor(cell: cell, value: mapped)
} else if exactPage < currentPage {
// exact < current
// fade out/in right icon
// select current
let unit = unitExact // from 0 - 0.5
let cell = mainView.menu.collectionView.cellForItem(at: IndexPath(item: Int(currentPage), section: 0)) as! MenuBarCell
let mapped = unit.map(from: 0.0...0.5, to: 0...149.0)
setCellColor(cell: cell, value: mapped)
} else if exactPage == currentPage {
// exact = current
// darken that icon
// select current
}
}