在 UITableView 中存储 UICollectionView 的选定 indexPath

Posted

技术标签:

【中文标题】在 UITableView 中存储 UICollectionView 的选定 indexPath【英文标题】:Stored selected indexPath of UICollectionView inside UITableView 【发布时间】:2020-01-09 13:54:03 【问题描述】:

我目前正在制作一个具有UITableView 的屏幕,其中许多部分的单元格内容为UICollectionView。现在我将集合的选定 indexPath 保存到一个数组中,然后保存到 UserDefaults (因为要求显示在重新打开视图控制器之前所有单元格都已选择)。

但我遇到的问题是,当我重新打开视图控制器时,所有部分中具有相同选定 indexPath 的所有项目都显示相同的状态。

我知道它会发生,因为我只保存了所选项目的唯一 indexPath,而没有 UITableviewsection 持有集合视图。但我不知道如何检查这些部分。有人可以帮我解决这个问题吗?提前致谢。

我正在关注这个解决方案How do I got Multiple Selections in UICollection View using Swift 4

这是我在代码中所做的:

var usrDefault = UserDefaults.standard
    var encodedData: Data?

override func awakeFromNib() 
    super.awakeFromNib()
    // Initialization code

    if let act = usrDefault.data(forKey: "selected") 
        let outData = NSKeyedUnarchiver.unarchiveObject(with: act)
        arrSelectedIndex = outData as! [IndexPath]
    else 
        arrSelectedData = []
    


func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
        let optionItemCell = collectionView.dequeueReusableCell(withReuseIdentifier: "optionCell", for: indexPath) as! SDFilterCollectionCell
        let title = itemFilter[indexPath.section].value[indexPath.item].option_name

    if arrSelectedIndex.contains(indexPath) 
        optionItemCell.filterSelectionComponent?.bind(title: title!, style: .select)
        optionItemCell.backgroundColor = UIColor(hexaString: SDDSColor.color_red_50.rawValue)
        optionItemCell.layer.borderColor = UIColor(hexaString: SDDSColor.color_red_300.rawValue).cgColor
    else 
        optionItemCell.backgroundColor = UIColor(hexaString: SDDSColor.color_white.rawValue)
        optionItemCell.layer.borderColor = UIColor(hexaString: SDDSColor.color_grey_100.rawValue).cgColor
        optionItemCell.filterSelectionComponent?.bind(title: title!, style: .unselect)
    

    optionItemCell.layoutSubviews()

    return optionItemCell

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) 
        let strData = itemFilter[indexPath.section].value[indexPath.item]
        let cell = collectionView.cellForItem(at: indexPath) as? SDFilterCollectionCell

    cell?.filterSelectionComponent?.bind(title: strData.option_name!, style: .select)
    cell?.backgroundColor = UIColor(hexaString: SDDSColor.color_red_50.rawValue)
    cell?.layer.borderColor = UIColor(hexaString: SDDSColor.color_red_300.rawValue).cgColor

    if arrSelectedIndex.contains(indexPath) 
        arrSelectedIndex = arrSelectedIndex.filter($0 != indexPath)
        arrSelectedData = arrSelectedData.filter($0 != strData)
    else 
        arrSelectedIndex.append(indexPath)
        arrSelectedData.append(strData)

        encodedData = NSKeyedArchiver.archivedData(withRootObject: arrSelectedIndex)
        usrDefault.set(encodedData, forKey: "selected")
    

    if let delegate = delegate 
        if itemFilter[indexPath.section].search_key.count > 0 
            if (strData.option_id != "") 
                input.add(strData.option_id!)
                let output = input.componentsJoined(by: ",")
                data["search_key"] = itemFilter[indexPath.section].search_key.count > 0 ?  itemFilter[indexPath.section].search_key : strData.search_key;
                data["option_id"] = output
            
        else 
            data["search_key"] = itemFilter[indexPath.section].search_key.count > 0 ?  itemFilter[indexPath.section].search_key : strData.search_key;
            data["option_id"] = strData.option_id
        

        delegate.filterTableCellDidSelectItem(item: data, indexPath: indexPath)
    

【问题讨论】:

每个表格单元格中的集合视图本身有多个部分还是只有一个?此外,您的表格视图是仅使用部分还是仅使用行来显示集合视图,还是有多个部分,每个部分包含多行? 我的表格视图有 5 个部分,每个部分只包含一个单元格,我在其中显示集合。集合视图只有一个部分 知道了,那么我发布的答案应该适用于您的实施。 【参考方案1】:

这仅在您的父表视图和子集合视图都没有使用具有多行的多个部分并且您只需要为每个部分存储一个值来表示项目在各自中的位置的假设基础上才有效看法。

如果我的理解正确,您对每个表格视图单元格都有一个集合视图。您正在存储每个集合视图的选择,但您还需要知道集合视图在父表中的位置?一种方法是向您的UICollectionView 类添加一个属性,或者使用tag 属性并将其设置为它位于父表中的相应部分。然后当您保存选定的IndexPath 时,您可以将section 设置为您创建的集合视图的属性(或示例中的tag),以便每个选定的indexPath.section 代表表视图section,并且indexPath.row 代表集合视图的行。

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    //...
    let collectionView = UICollectionView()
    collectionView.tag = indexPath.section
    //...


func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) 
    indexPath.section = collectionView.tag
    let strData = itemFilter[indexPath.section].value[indexPath.item]
    //...

基本上,您保存的每个选定的索引路径将对应于以下内容:

indexPath.section = 表视图部分indexPath.row = 集合视图行

IndexPath(row: 5, section: 9) 将关联到: --IndexPath(row: 0, section: 9) 处的表格视图单元格。 ----IndexPath(row: 5, section: 0)的集合视图单元格

编辑:这是您可以在当前代码中使用保存的索引路径的方式

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
    //...
    let tempIndexPath = IndexPath(row: indexPath.row, section: collectionView.tag)
    if arrSelectedIndex.contains(tempIndexPath) 
        //...
     else 
        //...
    
    //...

【讨论】:

indexPath.section = collectionView.tag 这会出错:Cannot assign to property: 'indexPath' is a 'let' constant。使用您的解决方案,我是否需要像我所做的那样添加唯一的 indexPath,然后它才能工作?【参考方案2】:

您在cellForItemAt 方法中的声明arrSelectedIndex.contains(indexPath) 不正确。

每次加载 UITableView 部分中的 UICollectionView 时,这将为所有单元格调用 cellForItemAt

这是错误:

在您的 GIF 示例中,第一个单元格在第一个 collectionView 中被选中,您将 (0, 0) 存储在数组中。

但是当第二个 collectionView 加载它的单元格时,它会检查 indexPath (0, 0) 是否包含在您的数组中。就是这样,所以会选择 backgroundColor。

此错误将在存储在 tableView 部分中的每个 collectionView 上重现。

您可能还应该将 UITableView 的 sectionIndex 存储到您的 IndexPath 数组中。

【讨论】:

你能做一些清晰的代码吗?我知道我错在哪里,但我不知道如何存储部分索引,然后将其与集合视图的选定索引进行比较。抱歉,我是 ios 新手

以上是关于在 UITableView 中存储 UICollectionView 的选定 indexPath的主要内容,如果未能解决你的问题,请参考以下文章

如何在 UITableview 中存储 UIButton 图像

从 uitableview 将数据存储在 nsdictionary 中

在 UITableView 中存储 UICollectionView 的选定 indexPath

如何在获取 api 响应并存储在 coredata 中然后在 UItableview 中显示后消除重复数据

从 UITableView 中删除行会更改存储在其他行中的信息

在 Swift 中存储和引用绘图数据以在 UITableView 中使用的最佳方式