簡體   English   中英

Swift4 - 我無法第一次顯示 CollectionView “無法同時滿足約束”

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

我正在使用 Swift 4 創建一個應用程序,在那里我向 API 發出請求,並且我想在 CollectionView 上返回結果。

但是我收到以下錯誤,我認為這是來自約束:

在此處輸入圖片說明

此塊重復 100 次。

結果是他沒有畫任何細胞。 顯示這樣的圖像:

在此處輸入圖片說明

除非我按兩次頂部按鈕“更改自動布局”。 這是當您繪制您擁有的兩種顯示模式的單元格時,它看起來像這樣:

在此處輸入圖片說明

和這個:

在此處輸入圖片說明

但問題是,最初沒有顯示任何內容,應該顯示。 我在開始時向您展示的錯誤出現了。

為了幫助您,因為我會說問題源於應用的約束,所以我附上了一些應用了不同約束的圖像。

collectionView 所在的初始 xib 是:

在此處輸入圖片說明

最初加載的單元格是:

在此處輸入圖片說明

我們更改布局后的單元格是這樣的:

在此處輸入圖片說明

我附上了主類的代碼,即控制 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)
}


}

事實是,我不知道為什么會發生布局沖突。 但它讓我發瘋......我無法理解最初如何不顯示單元格(因為正在接收數據)。 會是什么呢?

非常感謝,有什么問題可以發給我。

[代碼更新]

這些是代碼解決方案:

//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)

}
}

您沒有在 viewController 中設置 UICollectionViewDelegateFlowLayout。 您需要設置它然后使用

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

設置單元格的大小。

您遇到錯誤是因為當您第一次加載單元格時,您基本上是在告訴他們它們的大小為 0 0。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM