0

我遇到了实现水平scrollToItem collectionView的问题。我有一个collectionView(menuBar),单击页面collectionView将水平滚动到适当的单元格。点击menuBar的collectionViewCell时,应用程序崩溃。不知道错误在哪里。提前致谢!scrollToItem水平滚动collectionView崩溃

//控制器类

class CurrentUserPlaceDetailsVC: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { 

    var titleText: String? 

    let cellId = "cellId" 

    // UI elements 
    lazy var contentCollectionView: UICollectionView = { 
     let cv = UICollectionView() 
     cv.backgroundColor = UIColor.red 
     cv.layer.zPosition = 0 
     cv.translatesAutoresizingMaskIntoConstraints = false 
     cv.layer.masksToBounds = true 
     return cv 
    }() 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     setupMenuBar() 
     setupCollectionView() 

    } 

    func scrollToMenuIndex(_ menuIndex: Int) { 
     let indexPath = IndexPath(item: menuIndex, section: 0) 
     contentCollectionView.scrollToItem(at: indexPath, at: UICollectionViewScrollPosition(), animated: true) 
    } 

    lazy var menuBar: MenuBar = { 
     let mb = MenuBar() 
     mb.currentUserPlaceDetailsVC = self 
     return mb 
    }() 

    private func setupMenuBar() { 
     view.addSubview(menuBar) 
     view.addConstraintsWithFormat("H:|[v0]|", views: menuBar) 
     view.addConstraintsWithFormat("V:|[v0(114)]", views: menuBar) 
    } 

    func setupCollectionView() { 

     let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout() 

     layout.scrollDirection = .horizontal 
     layout.minimumLineSpacing = 0 
//  layout.sectionInset = UIEdgeInsets(top: 0, left: 10, bottom: 10, right: 10) 
     layout.itemSize = CGSize(width: self.view.frame.width, height: self.view.frame.height) 

     let contentCollectionView:UICollectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout) 
     contentCollectionView.dataSource = self 
     contentCollectionView.delegate = self 

     // register cells 
     contentCollectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cellId") 
     contentCollectionView.backgroundColor = .white 
//  contentCollectionView.scrollIndicatorInsets = UIEdgeInsets(top:114, left: 10, bottom: 10, right: 10) 
     self.view.addSubview(contentCollectionView) 

     _ = contentCollectionView.anchor(view.topAnchor, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor, topConstant: 114, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 0) 
     view.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true 
     contentCollectionView.isPagingEnabled = true 
    } 

    func scrollViewDidScroll(_ scrollView: UIScrollView) { 
     print(scrollView.contentOffset.x) 
     menuBar.horizontalBarLeftAnchorConstraint?.constant = scrollView.contentOffset.x/4 
    } 

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 
     return 4 
    } 

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 
     let myCell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) 
     let colors: [UIColor] = [.blue, .red, .yellow, .green] 
     myCell.backgroundColor = colors[indexPath.item] 
     return myCell 
    } 

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 
     return CGSize(width: view.frame.width, height: view.frame.height) 
    } 

} 

//菜单栏类

class MenuBar: UIView, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout { 

    lazy var collectionView: UICollectionView = { 
     let layout = UICollectionViewFlowLayout() 
     layout.minimumLineSpacing = 0 
     layout.headerReferenceSize = .zero 
     layout.sectionInset = .zero 
     let cv = UICollectionView(frame: .zero, collectionViewLayout: layout) 
     cv.backgroundColor = .green 
     cv.dataSource = self 
     cv.delegate = self 
     return cv 
    }() 

    let cellId = "cellId" 

    var currentUserPlaceDetailsVC: CurrentUserPlaceDetailsVC? 

    override init(frame: CGRect) { 
     super.init(frame: frame) 

     collectionView.register(MenuCell.self, forCellWithReuseIdentifier: cellId) 

     addSubview(collectionView) 
     addConstraintsWithFormat("H:|[v0]|", views: collectionView) 
     addConstraintsWithFormat("V:|[v0]|", views: collectionView) 

     let selectedIndexPath = IndexPath(item: 0, section: 0) 
     collectionView.selectItem(at: selectedIndexPath, animated: false, scrollPosition: UICollectionViewScrollPosition()) 

     setupHorizontalBar() 
    } 

    var horizontalBarLeftAnchorConstraint: NSLayoutConstraint? 

    func setupHorizontalBar() { 
     let horizontalBarView = UIView() 
     horizontalBarView.backgroundColor = .white 
     horizontalBarView.translatesAutoresizingMaskIntoConstraints = false 
     addSubview(horizontalBarView) 

     horizontalBarLeftAnchorConstraint = horizontalBarView.leftAnchor.constraint(equalTo: self.leftAnchor) 
     horizontalBarLeftAnchorConstraint?.isActive = true 

     horizontalBarView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true 
     horizontalBarView.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 1/4).isActive = true 
     horizontalBarView.heightAnchor.constraint(equalToConstant: 4).isActive = true 

    } 

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { 
     print(indexPath.item) 
     let x = CGFloat(indexPath.item) * frame.width/4 
     horizontalBarLeftAnchorConstraint?.constant = x 

     UIView.animate(withDuration: 0.75, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: { 
      self.layoutIfNeeded() 
     }, completion: nil) 

     currentUserPlaceDetailsVC?.scrollToMenuIndex(indexPath.item) 

    } 

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 
     return 4 
    } 

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 
     let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! MenuCell 
     cell.imageView.image = UIImage(named: imageNames[indexPath.item])?.withRenderingMode(.alwaysTemplate) 
     cell.tintColor = UIColor.rgb(91, green: 14, blue: 13) 

     return cell 
    } 

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 
     return CGSize(width: frame.width/4, height: frame.height) 
    } 

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { 
     return 0 
    } 

    required init?(coder aDecoder: NSCoder) { 
     fatalError("init(coder:) has not been implemented") 
    } 

} 
+0

什么错误?另外,正如我可以看到你尝试过滚动两个不同的集合视图,也许这是重点?顺便说一句,在你的MenuBar'var currentUserPlaceDetailsVC:CurrentUserPlaceDetailsVC?'应该是'weak'。 –

+0

嗨 - 我得到“终止与类型NSException的未捕获异常”错误。 – user3708224

+0

你能提供所有的错误信息吗?堆栈跟踪等。 –

回答

0

在你的评论说:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'UICollectionView must be initialized with a non-nil layout parameter'. I believe there is something wrong in my func scrollToMenuIndex()... when I remove that func the app does not crash.

出现这种情况,是因为您在视图中控制器你的collectionView声明为懒惰,这意味着它会按需计算。 问题是在初始化您的CollectionView(reason: 'UICollectionView must be initialized with a non-nil layout parameter'

在视图控制器与此代码替换UICollectionView初始化:

lazy var contentCollectionView: UICollectionView = { 
    let layout = UICollectionViewFlowLayout() 
    let cv = UICollectionView(frame: .zero, collectionViewLayout: layout) 
    cv.backgroundColor = UIColor.red 
    cv.layer.zPosition = 0 
    cv.translatesAutoresizingMaskIntoConstraints = false 
    cv.layer.masksToBounds = true 
    return cv 
}() 

P.S.正如我在对您的问题发表评论时所写的,您有reference cycle。类MenuBar应该对您的视图控制器持有较弱的参考,以防止这种情况。

+0

谢谢......这确实有帮助,但我也发现我的UICollectionViewFlowLayout约束导致了一些问题。我不得不将以下代码添加到我的setupCollectionView()方法中。如果让flowLayout = contentCollectionView.collectionViewLayout as? UICollectionViewFlowLayout {flowLayout.scrollDirection = .horizo​​ntal flowLayout.minimumLineSpacing = 0 } – user3708224

+0

您可以在'let layout = UICollectionViewFlowLayout()'这一行之后直接设置它,就像您在MenuBar类中做的那样:)。 –