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類中做的那樣:)。 –