无限 UICollectionview 与 UIPageControl
Infinite UICollectionview with UIPageControl
在下面给出的代码中,我可以简单地无限滚动单元格。页面控件似乎至少在向前滚动(屏幕右侧)时也能正常工作。但坦率地说,当我向左滚动时,我看到 3 个项目的奇怪索引路径跳转(顺便说一句,我的数据源有 3 个项目用于测试目的)。在屏幕上,我没有发现任何问题。但是页面控制似乎冻结了片刻,然后又开始工作,但是有一个转变,并且显示单元格的错误点。有任何想法吗?感谢您的帮助...
import UIKit
class HomeHeaderCell: CategoryCell {
private let cellId = "cellId"
private var timer: Timer?
private let infiniteSize = 1000
private var onlyOnce = true
// ...
let pageControl: UIPageControl = {
let rect = CGRect(origin: .zero, size: CGSize(width: 200, height: 50))
let pc = UIPageControl(frame: rect)
pc.currentPage = 0
pc.numberOfPages = 3
pc.pageIndicatorTintColor = .gray
pc.currentPageIndicatorTintColor = .red
pc.isUserInteractionEnabled = false
return pc
}()
override func setupViews() {
addSubview(baseCollectionView)
addSubview(pageControl)
baseCollectionView.delegate = self
baseCollectionView.dataSource = self
baseCollectionView.register(HeaderCell.self, forCellWithReuseIdentifier: cellId)
baseCollectionView.backgroundColor = .white
baseCollectionView.isPagingEnabled = true
baseCollectionView.isScrollEnabled = true
baseCollectionView.showsHorizontalScrollIndicator = false
baseCollectionView.anchor(top: topAnchor, leading: leadingAnchor, bottom: bottomAnchor, trailing: trailingAnchor)
pageControl.anchor(top: nil, leading: leadingAnchor, bottom: bottomAnchor, trailing: nil, padding: UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 0))
}
@objc func autoScroll() {
guard let currentItemNumber = baseCollectionView.indexPathsForVisibleItems.first?.item else { return }
let nextItemNumber = currentItemNumber + 1
let nextIndexPath = IndexPath(item: nextItemNumber, section: 0)
baseCollectionView.scrollToItem(at: nextIndexPath, at: .left, animated: true)
}
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
stopTimer()
}
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
startTimer()
}
func startTimer() {
timer = Timer.scheduledTimer(timeInterval: 4.0, target: self, selector: #selector(autoScroll), userInfo: nil, repeats: true)
}
func stopTimer() {
timer?.invalidate()
timer = nil
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return infiniteSize
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! HeaderCell
// Maybe can be done more elegantly...
if let foods = foodCategory?.foods {
let numberOfFood = indexPath.item % foods.count
cell.food = foods[numberOfFood]
pageControl.currentPage = numberOfFood
print(numberOfFood)
}
return cell
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if onlyOnce {
let middleIndex = IndexPath(item: Int (infiniteSize / 2), section: 0)
baseCollectionView.scrollToItem(at: middleIndex, at: .centeredHorizontally, animated: false)
startTimer()
onlyOnce = false
}
}
override func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: frame.width, height: frame.height)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
private class HeaderCell: ItemCell {
override func setupViews() {
addSubview(imageView)
imageView.layer.cornerRadius = 0
imageView.layer.borderColor = UIColor(white: 0.5, alpha: 0.5).cgColor
imageView.layer.borderWidth = 0.5
imageView.anchor(top: topAnchor, leading: leadingAnchor, bottom: bottomAnchor, trailing: trailingAnchor)
}
}
}
我解决了我自己的问题。这是您应该应用的代码。前两个方法是 UICollectionView 附带的 UIScrollView 方法,顺便说一句,它是 UIScrollView 的子类。 updatePageControl 方法是我为保持代码简洁而编写的方法。希望这有助于...
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
updatePageControl(scrollView: scrollView)
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
updatePageControl(scrollView: scrollView)
}
func updatePageControl(scrollView: UIScrollView) {
let pageNumber = round(scrollView.contentOffset.x / scrollView.bounds.size.width)
guard let count = foodCategory?.foods?.count else {return}
let currentPageNumber = Int(pageNumber) % count
pageControl.currentPage = currentPageNumber
}
在下面给出的代码中,我可以简单地无限滚动单元格。页面控件似乎至少在向前滚动(屏幕右侧)时也能正常工作。但坦率地说,当我向左滚动时,我看到 3 个项目的奇怪索引路径跳转(顺便说一句,我的数据源有 3 个项目用于测试目的)。在屏幕上,我没有发现任何问题。但是页面控制似乎冻结了片刻,然后又开始工作,但是有一个转变,并且显示单元格的错误点。有任何想法吗?感谢您的帮助...
import UIKit
class HomeHeaderCell: CategoryCell {
private let cellId = "cellId"
private var timer: Timer?
private let infiniteSize = 1000
private var onlyOnce = true
// ...
let pageControl: UIPageControl = {
let rect = CGRect(origin: .zero, size: CGSize(width: 200, height: 50))
let pc = UIPageControl(frame: rect)
pc.currentPage = 0
pc.numberOfPages = 3
pc.pageIndicatorTintColor = .gray
pc.currentPageIndicatorTintColor = .red
pc.isUserInteractionEnabled = false
return pc
}()
override func setupViews() {
addSubview(baseCollectionView)
addSubview(pageControl)
baseCollectionView.delegate = self
baseCollectionView.dataSource = self
baseCollectionView.register(HeaderCell.self, forCellWithReuseIdentifier: cellId)
baseCollectionView.backgroundColor = .white
baseCollectionView.isPagingEnabled = true
baseCollectionView.isScrollEnabled = true
baseCollectionView.showsHorizontalScrollIndicator = false
baseCollectionView.anchor(top: topAnchor, leading: leadingAnchor, bottom: bottomAnchor, trailing: trailingAnchor)
pageControl.anchor(top: nil, leading: leadingAnchor, bottom: bottomAnchor, trailing: nil, padding: UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 0))
}
@objc func autoScroll() {
guard let currentItemNumber = baseCollectionView.indexPathsForVisibleItems.first?.item else { return }
let nextItemNumber = currentItemNumber + 1
let nextIndexPath = IndexPath(item: nextItemNumber, section: 0)
baseCollectionView.scrollToItem(at: nextIndexPath, at: .left, animated: true)
}
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
stopTimer()
}
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
startTimer()
}
func startTimer() {
timer = Timer.scheduledTimer(timeInterval: 4.0, target: self, selector: #selector(autoScroll), userInfo: nil, repeats: true)
}
func stopTimer() {
timer?.invalidate()
timer = nil
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return infiniteSize
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! HeaderCell
// Maybe can be done more elegantly...
if let foods = foodCategory?.foods {
let numberOfFood = indexPath.item % foods.count
cell.food = foods[numberOfFood]
pageControl.currentPage = numberOfFood
print(numberOfFood)
}
return cell
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if onlyOnce {
let middleIndex = IndexPath(item: Int (infiniteSize / 2), section: 0)
baseCollectionView.scrollToItem(at: middleIndex, at: .centeredHorizontally, animated: false)
startTimer()
onlyOnce = false
}
}
override func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: frame.width, height: frame.height)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
private class HeaderCell: ItemCell {
override func setupViews() {
addSubview(imageView)
imageView.layer.cornerRadius = 0
imageView.layer.borderColor = UIColor(white: 0.5, alpha: 0.5).cgColor
imageView.layer.borderWidth = 0.5
imageView.anchor(top: topAnchor, leading: leadingAnchor, bottom: bottomAnchor, trailing: trailingAnchor)
}
}
}
我解决了我自己的问题。这是您应该应用的代码。前两个方法是 UICollectionView 附带的 UIScrollView 方法,顺便说一句,它是 UIScrollView 的子类。 updatePageControl 方法是我为保持代码简洁而编写的方法。希望这有助于...
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
updatePageControl(scrollView: scrollView)
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
updatePageControl(scrollView: scrollView)
}
func updatePageControl(scrollView: UIScrollView) {
let pageNumber = round(scrollView.contentOffset.x / scrollView.bounds.size.width)
guard let count = foodCategory?.foods?.count else {return}
let currentPageNumber = Int(pageNumber) % count
pageControl.currentPage = currentPageNumber
}