У меня есть пейджинг UIScrollView
, каждая страница заполняется другим контроллером представления. Над прокруткой находится UICollectionView
, который действует как строка меню. Когда вы прокручиваете страницы прокрутки, строка меню немного перемещается. Вы можете видеть на гифке слева.
Установка их делегатов в разные классы обеспечивает правильную работу, как показано на рисунке слева. НО, установка их в один и тот же класс портит поведение UICollectionView
s.
Как установить их делегатов в один и тот же класс?
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
}
}
}
Я никогда даже не думал, что это будет применяться как к CollectionViewCell, так и к scrollview! Есть ли способ исправить это? И я обновлю свой вопрос с кодом scrollViewDidScroll
В scrollViewDidScroll выполните: guard scrollView != myCollectionView else { return }
; guard scrollView == myScrollViewAndNotMyCollection else { return }
и т. д. Как сказал Paulw11, это потому, что UICollectionView
наследуется от UIScrollView
.
Спасибо! Это сработало отлично. Но есть ли стандартное решение этой проблемы. Например, если бы у меня было 2 UIScrollView
в одном представлении? Или использование оператора guard
является нормой?
UICollectionView
и UITableView
наследуются от UIScrollView
,
Метод делегата scrollViewDidScroll
будет вызываться как для представления коллекции, так и для представления прокрутки, если вы установите delegate
для обоих объектов в один и тот же класс.
Вам нужно проверить, почему вызывается scrollViewDidScroll
, и действовать соответственно.
Самый простой подход — это оператор guard
, который возвращает значение, если метод делегата не вызывается для интересующего вас представления прокрутки.
Если вам нужно выполнить другой код в зависимости от задействованного представления прокрутки, вы можете использовать серию операторов if
или оператор switch
.
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
}
}
Можете показать код для
scrollViewDidScroll
? Вы проверяете прокрутку который прокрутки? Представления коллекции — это представления прокрутки, и для них также будет вызываться этот метод делегата.