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