如何滚动到给定的 indexPath.item?
Posted
技术标签:
【中文标题】如何滚动到给定的 indexPath.item?【英文标题】:How to scroll to a given indexPath.item? 【发布时间】:2021-04-17 17:59:25 【问题描述】:我有 2 个并行的集合视图。其中一个是菜单,另一个是包含垂直表视图的大菜单,其中填充了 API 查询数据。
当用户向右滚动时,Order History 会突出显示,并且底部大集合视图中的下一个单元格会占据屏幕的其余部分,并显示自己的 tableview 数据。就像implementation here。
除了我在附图所示状态下点击订单历史记录时,一切正常,底部的集合视图不会滚动到大集合视图中的第二个单元格。如果我点击当前订单单元格,它会滚动到大集合视图中的第一个单元格。在过去的 48 小时内,我不知道是什么导致了这个问题。
这是菜单栏:
class MenuBar: UIView, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout
lazy var menuCollection: UICollectionView =
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
let collectionview = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionview.translatesAutoresizingMaskIntoConstraints = false
collectionview.backgroundColor = .white
collectionview.delegate = self
collectionview.dataSource = self
collectionview.register(InvoiceCell.self, forCellWithReuseIdentifier: InvoiceCell.identifier)
return collectionview
()
var leftIndicatorConstraint: NSLayoutConstraint?
private let menuOptions = ["Current Orders", "Order History"]
var containerViewController: ContainerViewController? // I use an instance of the parent VC to pass on the value
override init(frame: CGRect)
super.init(frame: frame)
addSubview(menuCollection)
menuCollection.topAnchor.constraint(equalTo: self.topAnchor, constant: 0).isActive = true
menuCollection.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0).isActive = true
menuCollection.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 0).isActive = true
menuCollection.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: 0).isActive = true
menuCollection.selectItem(at: IndexPath(row: 0, section: 0), animated: true, scrollPosition: .left)
setupIndicator()
required init?(coder: NSCoder)
fatalError("init(coder:) has not been implemented")
func setupIndicator()
let indicatorBar = UIView()
indicatorBar.backgroundColor = UIColor(hex: Constants.Colors.primary)
addSubview(indicatorBar)
indicatorBar.translatesAutoresizingMaskIntoConstraints = false
leftIndicatorConstraint = indicatorBar.leadingAnchor.constraint(equalTo: self.leadingAnchor)
leftIndicatorConstraint?.isActive = true
indicatorBar.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
indicatorBar.heightAnchor.constraint(equalToConstant: 5).isActive = true
indicatorBar.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.5).isActive = true
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
containerViewController?.scrollToMenu(menuIndex: indexPath.item) // Here I pass on the value of the menu item that's tapped
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
return menuOptions.count
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: InvoiceCell.identifier, for: indexPath) as? InvoiceCell else return UICollectionViewCell()
cell.thisOption = menuOptions[indexPath.row]
return cell
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
return CGSize(width: menuCollection.frame.size.width / CGFloat(menuOptions.count), height: menuCollection.frame.size.height)
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat
return 0
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat
return 0
这是包含菜单集合视图以及大基础集合视图的父 UIView 控制器
class ContainerViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout
lazy var menuBar: MenuBar =
let menuBar = MenuBar()
menuBar.containerViewController = self
menuBar.translatesAutoresizingMaskIntoConstraints = false
return menuBar
()
lazy var baseCollectionView: UICollectionView =
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.register(PastCell.self, forCellWithReuseIdentifier: PastCell.pastCellId)
collectionView.register(CurrentCell.self, forCellWithReuseIdentifier: CurrentCell.currentCellId)
collectionView.isPagingEnabled = true
collectionView.delegate = self
collectionView.dataSource = self
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.showsHorizontalScrollIndicator = false
collectionView.backgroundColor = .white
return collectionView
()
var orderViewModel = OrderViewModel(order: Order(addressOne: "", addressTwo: "", city: "", postalCode: "", mpName: "", planType: 0, restaurantAddress: "", restaurantId: "", restaurantName: "", timeOfCreation: nil, currentTotal: 0.00, orderMenu: [], status: 0, itemshtml: ""))
override func viewDidLoad()
super.viewDidLoad()
view.backgroundColor = .white
setupView()
override func viewDidDisappear(_ animated: Bool)
super.viewDidDisappear(animated)
orderViewModel.removeListener()
private func setupView()
view.addSubview(menuBar)
menuBar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true
menuBar.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 0).isActive = true
menuBar.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: 0).isActive = true
menuBar.heightAnchor.constraint(equalToConstant: 40).isActive = true
view.addSubview(baseCollectionView)
baseCollectionView.topAnchor.constraint(equalTo: menuBar.bottomAnchor, constant: 0).isActive = true
baseCollectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0).isActive = true
baseCollectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0).isActive = true
baseCollectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true
func scrollToMenu(menuIndex: Int)
// Here I am using the passed on menu index to scroll to the appropriate cell in the big collection view.
let indexPath = IndexPath(item: menuIndex, section: 0)
baseCollectionView.scrollToItem(at: indexPath, at: .left, animated: true) // For some reason it ALWAYS SCROLL TO THE FIRST CELL
func scrollViewDidScroll(_ scrollView: UIScrollView)
menuBar.leftIndicatorConstraint?.constant = scrollView.contentOffset.x / 2
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>)
let index = Int(targetContentOffset.pointee.x / view.frame.width)
menuBar.menuCollection.selectItem(at: IndexPath(item: index, section: 0), animated: true, scrollPosition: .left)
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
return 2
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
switch indexPath.row
case 0:
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CurrentCell.currentCellId, for: indexPath) as? CurrentCell
if let tabBarHeight = self.tabBarController?.tabBar.frame.size.height
cell.adjustSize(top: menuBar.frame.height * 1.2, bottom: tabBarHeight * 0.5)
return cell
case 1:
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PastCell.pastCellId, for: indexPath) as? PastCell
cell.backgroundColor = .systemOrange
return cell
default:
return UICollectionViewCell()
return UICollectionViewCell()
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
return CGSize(width: view.frame.size.width, height: view.frame.size.height)
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat
return 0
【问题讨论】:
【参考方案1】:原来有一个big bug with scrollToItem Apple 没有修复。在我的情况下,它是由 isPagingEnabled 引起的。所以the best solution I found was here 在滚动到项目之前禁用分页,然后再次启用它。
【讨论】:
以上是关于如何滚动到给定的 indexPath.item?的主要内容,如果未能解决你的问题,请参考以下文章
UICollectionVIew indexPath.item/row 返回不正确的值
在 indexpath.item 以编程方式呈现 UIViewController(嵌入在 UITabBarController 中)