可靠地使用 UICollectionView indexPath 访问字典键?

Posted

技术标签:

【中文标题】可靠地使用 UICollectionView indexPath 访问字典键?【英文标题】:Reliably using UICollectionView indexPath to access dictionary keys? 【发布时间】:2019-01-07 17:56:00 【问题描述】:

我正在尝试使用当前 CollectionViewcell 的 IndexPath 来访问字典中的数据。字典的键是 Int 类型。 此 CollectionView 具有“整页”单元格,这意味着每个单元格都占据了我使用水平滚动(启用分页)在单元格之间导航的完整视图区域。

字典是:

var dataFromServer: [Int: [VillageFestival]]?

每个 CollectionViewCell 里面都有一个 TableView,我计划在其中有可变数量的行,具体取决于 [VillageFestival] 中有多少项目

但是,在CollectionView cellForItemAt indexPath 中,该方法的行为引起了一些麻烦,因为打印 indexPath.item 或将其设置为我的 navigationController 的标题,返回奇怪但“可以理解”的结果,因为我认为 dequeueReusableCell 是如何工作的?...

示例:当前索引为 0。当我向右滚动时,当前索引为 2。如果我导航到第 6 页然后返回一页,当前索引指示为 3。

为了简化逻辑,我已将字典键从 Date 更改为 String,现在更改为 Int。但问题仍然存在。 我正在使用全局 pageIndex: Int,它正在 CollectionView cellForItemAt 内部更新

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 

    pageIndex = indexPath.item

    self.navigationController?.navigationBar.topItem?.title = String(pageIndex)

    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionViewCell", for: indexPath) as! CollectionViewCell

    // CollectionViewCell resize to CollectionView Bounds
    cell.tableViewCellOffsets = (UIApplication.shared.statusBarFrame.size.height + (self.navigationController?.navigationBar.frame.height ?? 0.0) , self.tabBarController?.tabBar.frame.height ?? 0)
    return cell


在 Tableview numberOfRowsInSection 中,我使用 pageIndex 来访问字典值。

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 

    guard let festivals = dataFromServer?[pageIndex]  else return 0

    return festivals.count


使用我当前的代码,该应用程序为某些页面显示 0 行,为其他页面显示 1 行。我的猜测是 collectionView 的 cellForItemAt 在 tableView 的方法之前(也可能在之后?)被调用,这使得使用全局 pageIndex 不可靠......

谢谢!

【问题讨论】:

cellForItemAt 也用于尚未出现在屏幕上的单元格,这就是为什么您的 pageIndex 不能准确反映您所看到的内容。我不知道您在这里如何处理嵌套的 tableView,但一种方法可能是每次将 collectionViewCell 出列并调用 reloadData 时传递 festivals 数组。 我认为您在影响索引路径的 dequeable 单元格的正确轨道上。我认为您应该根据手势识别器或按下特定页面来增加 pageIndex。 (所以如果向右滑动,+= 1。按第 6 页,pageIndex = 5 等。) 如何设置navigationController的标题?您应该使用 cellForItem(at: indexPath) 来获取单元格的内容。 【参考方案1】:

试试这个游乐场,它可能对你有帮助:

import UIKit
import PlaygroundSupport

class Cell: UICollectionViewCell, UITableViewDataSource 

    var data: [Int]! = [] 
        didSet 
            tableView.reloadData()
        
    
    private let tableView: UITableView

    override init(frame: CGRect) 
        tableView = UITableView(frame: .zero, style: .plain)
        super.init(frame: frame)
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
        tableView.dataSource = self
        tableView.translatesAutoresizingMaskIntoConstraints = false
        contentView.addSubview(tableView)
        NSLayoutConstraint.activate([
            tableView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
            tableView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
            tableView.topAnchor.constraint(equalTo: contentView.topAnchor),
            tableView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
        ])
    

    required init?(coder aDecoder: NSCoder) 
        fatalError()
    

    func numberOfSections(in tableView: UITableView) -> Int 
        return 1
    

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return data.count
    

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
        cell.textLabel?.text = String(data[indexPath.item])
        return cell
    


class VC: UICollectionViewController 

    let data = [
        0: [1, 2, 3, 4, 5],
        1: [6, 4],
        2: [5, 5, 5, 5, 6],
        3: [9, 9, 8, 4, 5, 5, 5]
    ]

    override init(collectionViewLayout layout: UICollectionViewLayout) 
        super.init(collectionViewLayout: layout)
        collectionView.isPagingEnabled = true
        collectionView.register(Cell.self, forCellWithReuseIdentifier: "Cell")
    

    required init?(coder aDecoder: NSCoder) 
        fatalError()
    

    override func numberOfSections(in collectionView: UICollectionView) -> Int 
        return 1
    

    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
        return data.count
    

    override func viewDidLayoutSubviews() 
        (collectionViewLayout as? UICollectionViewFlowLayout)?.itemSize = collectionView.bounds.size
    

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! Cell
        cell.data = data[indexPath.item]
        return cell
    



let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
PlaygroundPage.current.liveView = VC(collectionViewLayout: layout)

【讨论】:

这正是我所需要的。谢谢!

以上是关于可靠地使用 UICollectionView indexPath 访问字典键?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过关闭连接可靠地确定主体长度(RFC 2616 4.4.5)

UICollectionView 神秘地延迟触摸直到滚动

Python 电子邮件包:如何可靠地将多部分消息转换/解码为 str

UICollectionView - 下载图像并有效地重新加载数据,例如 Instagram

UICollectionView.scrollToItemAtIndexPath 动画与虚拟键盘奇怪地配合

UICollectionView 在帧更改后错误地显示单元格