首页 > 解决方案 > 用不同的单元格重新加载 CollectionView

问题描述

我是 swift 的初学者,想创建我的第一个应用程序。在应用程序中,我使用 collectionViews,因为我遵循 Lets build that App on Youtube 的建议。
在我的应用程序中,我想要一个垂直的 collectionView。在这个 collectionView 中,我想要另一个包含 2 个不同单元格的 collectionView:1x TitleCell 和 ?x ContentCell。
对于这些单元格,发送一个 API 请求来设置它们的值。API调用完成后,我重新加载collectionView:

  self.collectionView.reloadData()  

不幸的是,当我重新加载数据时,我的 TitleCell 被 ContentCell 覆盖。正如我在有关 reloadData() 的 swift 文档中所读到的:当它被调用时,它会擦除​​每个单元格并将其替换为最后一个调用的单元格:在我的情况下是 ContentCell。

因此我的问题是,有没有办法以不被覆盖的方式重新加载 TitleCell 和 ContentCell ?
还有:用 2 个不同的单元格制作 collectionView 是不是一种不好的做法?

这是我的代码:

接口:

class ApiService: NSObject {
 static let sharedInstance = ApiService()

 var contentBaseUrl = "netAddress"

  func fetchContent(from url: String, completion: @escaping ([ContentModel]) -> ()) {
    fetchFeedForUrlString(urlString: "\(contentBaseUrl)/"folder"/\(url)", completion: completion)
 }

 func fetchFeedForUrlString<T: Decodable>(urlString: String, completion: @escaping (T) -> ()) {
    let url = URL(string: urlString)
    let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in

        guard let data = data else {
            return
        }

        do {
            let json = try JSONDecoder().decode(T.self, from: data)

            DispatchQueue.main.async {
                completion(json)
            }

        } catch let jsonError {
            print(jsonError)
        }

    }

    task.resume()
 }
}

调用 api 的 CollectionView:

class VHomeCell: BaseCell, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

var firstCell = true
var content: [ContentModel]?

override func setupViews() {
    super.setupViews()

    fetchVideos()
    collectionView.register(HomeContentCell.self, forCellWithReuseIdentifier: "ContentCellID")
    collectionView.register(LeagueCell.self, forCellWithReuseIdentifier: "TitleCellID")
}

//Method that causes the "error"
func fetchMatches() {

    ApiService.sharedInstance.fetchData(from: "ApiNetworkAddress", completion: { (content: [ContentModel]) in
        self.content = content
        self.collectionView.reloadData()
    })
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return content?.count ?? 0
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    if firstCell {
        firstCell = false
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TitleCellID", for: indexPath) as! TitleCell
        return cell
    } else {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ContentCellID", for: indexPath) as! ContentCell
        cell.match = matches?[indexPath.item]
        return cell
    }
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    return CGSize(width: frame.width, height: 50)
}

ContentCell 和 TitleCell 只是 2 个 UICollectionView 单元,其中包含不同的内容:

 class TitleCell: BaseCell {
   var content: ContentModel? {
      didSet {
        title.text = content.titleText
     }
  }
 }

 class ContentCell: BaseCell {
   var content: ContentModel? {
      didSet {
         content.Text = content.text
     }
  }
 }

这是使用的 BaseCell:

class BaseCell: UICollectionViewCell {
  override init(frame: CGRect) {
    super.init(frame: frame)
    setupViews()
  }

func setupViews() {

}

required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}
}

我知道我的代码需要大量的清理工作。因此,如果有人也能指出我可以如何清理我的代码或使其更有效率,我会很高兴。

标签: swiftapiuicollectionview

解决方案


您不应该使用此firstCell属性来确定在您的cellForItemAt方法中配置哪个单元格。相反,您应该使用indexPath传递给方法的参数来确定是否正在为第一个单元格调用该方法。您可以通过检查indexPath's来做到这一点item(您可以忽略indexPath's section,因为您的收藏视图中似乎只有一个部分)。

因此,完全删除该firstCell属性。然后只需替换此if条件:

if firstCell {

和:

if indexPath.item == 0 {

要回答您的另一个问题:不,每个集合视图有多个单元格类型并不是一个坏习惯。


推荐阅读