简体   繁体   English

Swift4 - 我无法第一次显示 CollectionView “无法同时满足约束”

[英]Swift4 - I can not show the CollectionView the first time "Unable to simultaneously satisfy constraints"

I am creating an app with Swift 4, where I make a request to the API and I want to return a result on a CollectionView.我正在使用 Swift 4 创建一个应用程序,在那里我向 API 发出请求,并且我想在 CollectionView 上返回结果。

But I get the following error, which I think is from constraints:但是我收到以下错误,我认为这是来自约束:

在此处输入图片说明

This block is repeated 100 times.此块重复 100 次。

And the result is that he does not paint any cells.结果是他没有画任何细胞。 Showing an image like this:显示这样的图像:

在此处输入图片说明

Unless I press the top button "CHANGE AUTOLAYOUT" twice.除非我按两次顶部按钮“更改自动布局”。 Which is when you paint the cells of the two display modes you have, and it looks like this:这是当您绘制您拥有的两种显示模式的单元格时,它看起来像这样:

在此处输入图片说明

And this:和这个:

在此处输入图片说明

But the problem is, initially nothing is shown and should be shown.但问题是,最初没有显示任何内容,应该显示。 And the error that I show you in the beginning appears.我在开始时向您展示的错误出现了。

To help you a little, because I would say that the problem derives from the constrainst applied, I attach some images with the different constrainsts applied.为了帮助您,因为我会说问题源于应用的约束,所以我附上了一些应用了不同约束的图像。

The initial xib, where the collectionView is, are: collectionView 所在的初始 xib 是:

在此处输入图片说明

The cell that is initially loaded is:最初加载的单元格是:

在此处输入图片说明

The cell once we have changed the layout is this:我们更改布局后的单元格是这样的:

在此处输入图片说明

I attached the code of the main class, the ViewVontroller that controls the CollectionView:我附上了主类的代码,即控制 CollectionView 的 ViewVontroller:

import UIKit
import RxSwift
import RxCocoa

final class SpeedRunListViewController: UIViewController {

@IBOutlet private var collectionView: UICollectionView!
@IBOutlet private var buttonChangeLayout: UIButton!

private let disposeBag = DisposeBag()
private var viewModelList: SpeedRunListViewModel?
private var numElementsByCol: CGFloat = 3

override func viewDidLoad() {
    super.viewDidLoad()
    navigationController?.isNavigationBarHidden = true
    setupCollectionView()
    viewModelList = SpeedRunListViewModel(interactor: InteractorSpeedRunSearch())
    setupRx(viewModel: viewModelList!)
    viewModelList?.fetch()
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    navigationController?.isNavigationBarHidden = true
}


private func setupCollectionView() {
    registerCollectionCells()
    if #available(iOS 10.0, *) {
        collectionView.isPrefetchingEnabled = false
    } else {
        // Fallback on earlier versions
    }
    calculateLayoutCollectionItem()
}


private func registerCollectionCells() {
    collectionView.register(UINib(nibName: SpeedRunRowCollectionViewCell.nibName, bundle: nil),
                            forCellWithReuseIdentifier: SpeedRunRowCollectionViewCell.reuseCellId)

    collectionView.register(UINib(nibName: SpeedRunCollectionViewCell.nibName, bundle: nil),
                            forCellWithReuseIdentifier: SpeedRunCollectionViewCell.reuseCellId)

}

private func calculateLayoutCollectionItem() {
    if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
        layout.estimatedItemSize = CGSize.init(width: 2, height: 2)
    }
}

private func setupRx(viewModel: SpeedRunListViewModel) {
    viewModel.numElements.asObservable().subscribe(onNext: { e in
        self.collectionView.reloadData()
    }, onError: { error in

    }, onCompleted: {

    }, onDisposed: {

    }).disposed(by: disposeBag)


    buttonChangeLayout.rx.tap.subscribe(onNext: { void in
        guard let value = self.viewModelList?.layoutRow else {
            return
        }
        self.viewModelList?.layoutRow = !value
        self.collectionView.collectionViewLayout.invalidateLayout()
        self.collectionView.reloadData()
    }, onError: { error in

    }, onCompleted: {

    }, onDisposed: {

    }).disposed(by: disposeBag)

}

fileprivate func getCellId() -> String {
    if let layoutRow = self.viewModelList?.layoutRow, layoutRow == true {
        return SpeedRunRowCollectionViewCell.reuseCellId
    }
    return SpeedRunCollectionViewCell.reuseCellId
}

}

//MARK: - UICollectionViewDelegate, UICollectionViewDataSource
extension SpeedRunListViewController: UICollectionViewDelegate, 
UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    guard let numElements = viewModelList?.numElements else {
        return 0
    }
    return numElements.value
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: getCellId(), for: indexPath) as! SpeedRunCollectionViewCellBase
    if let cellViewModel = viewModelList?.getCellViewModel(index: indexPath.row) {
        cell.setupCell(viewModel: cellViewModel)
    }

    return cell
}


func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    guard let speedRun = viewModelList?.getSpeedRun(index: indexPath.row) else {
        return
    }

    let interactorDetail: InteractorSpeedRunDetail = InteractorSpeedRunDetail(speedRun: speedRun)
    let viewControllerDetail: SpeedRunDetailViewController = SpeedRunDetailViewController(interactor: interactorDetail)
    viewControllerDetail.URISpeedRunDetail = (speedRun.links![1].uri)!

    navigationController?.pushViewController(viewControllerDetail, animated: true)
}


}

And the truth is that I do not know why that conflict of layouts occurs.事实是,我不知道为什么会发生布局冲突。 But it's driving me crazy ... I can not understand how the cells are not shown initially (because data is being received).但它让我发疯......我无法理解最初如何不显示单元格(因为正在接收数据)。 What could it be?会是什么呢?

Thank you very much, any question you attach it to me.非常感谢,有什么问题可以发给我。

[CODE UPDATED] [代码更新]

These is the code solution:这些是代码解决方案:

//MARK: - UICollectionViewDelegateFlowLayout
extension SpeedRunListViewController: UICollectionViewDelegateFlowLayout {

func collectionView(_ collectionView: UICollectionView,
                    layout collectionViewLayout: UICollectionViewLayout,
                    sizeForItemAt indexPath: IndexPath) -> CGSize{


    if let value = self.viewModelList?.layoutRow {
        if value {
            return CGSize(width: 320, height: 144)
        }
        else{
            return CGSize(width: 96, height: 162)
        }
    }

    return CGSize(width: 320, height: 144)

}
}

You are not setting the UICollectionViewDelegateFlowLayout in the viewController.您没有在 viewController 中设置 UICollectionViewDelegateFlowLayout。 You need to set it and then use您需要设置它然后使用

func collectionView(_ collectionView: UICollectionView, 
                  layout collectionViewLayout: UICollectionViewLayout, 
           sizeForItemAt indexPath: IndexPath) -> CGSize

To set the sizes of your cells.设置单元格的大小。

You are having the error because when you load the cells the very first time you are basically telling them that they have a size of 0 0.您遇到错误是因为当您第一次加载单元格时,您基本上是在告诉他们它们的大小为 0 0。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM