简体   繁体   中英

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.

But I get the following error, which I think is from constraints:

在此处输入图片说明

This block is repeated 100 times.

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:

在此处输入图片说明

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:

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. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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