【问题标题】:scrollToItem horizontal scrolling collectionView crashscrollToItem 水平滚动 collectionView 崩溃
【发布时间】:2017-10-13 11:37:19
【问题描述】:

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

// 控制器类

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")
    }

}

【问题讨论】:

  • 什么错误?另外,正如我所见,您也尝试滚动两个不同的集合视图,也许这就是重点?顺便说一句,在您的菜单栏中 var currentUserPlaceDetailsVC: CurrentUserPlaceDetailsVC? 应该是 weak
  • 嗨 - 我收到“以 NSException 类型的未捕获异常终止”错误。
  • 你能提供所有的错误信息吗?带有堆栈跟踪等。
  • 由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“必须使用非零布局参数初始化 UICollectionView”。我相信我的 func scrollToMenuInde​​x() 有问题...当我删除该 func 时,应用程序不会崩溃。

标签: swift uicollectionview uicollectionviewcell horizontal-scrolling scroll-paging


【解决方案1】:

在你的评论中你说:

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.

发生这种情况,因为您在 View Controller 中将 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
}()

附:正如我在对您的问题的评论中所写,您拥有reference cycleMenuBar 类应该持有对视图控制器的弱引用以防止这种情况发生。

【讨论】:

  • 谢谢...这确实有帮助,但我也发现我的 UICollectionViewFlowLayout 约束导致了一些问题。我必须将以下代码添加到我的 setupCollectionView() 方法中。如果让 flowLayout = contentCollectionView.collectionViewLayout 为? UICollectionViewFlowLayout { flowLayout.scrollDirection = .horizo​​ntal flowLayout.minimumLineSpacing = 0 }
  • 你可以直接在let layout = UICollectionViewFlowLayout()这一行之后设置它,就像你在MenuBar类中所做的那样:)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多