如何处理表视图单元格中的全部打开/全部关闭,每个单元格在 iOS Swift 中具有查看更多/查看更少选项

Posted

技术标签:

【中文标题】如何处理表视图单元格中的全部打开/全部关闭,每个单元格在 iOS Swift 中具有查看更多/查看更少选项【英文标题】:How to handle open all/close all in tableview cell with each cell has View More/View less options in iOS Swift 【发布时间】:2021-05-30 21:15:40 【问题描述】:

我正在做 Swift 项目,每个单元格都有 查看更多/查看更少 选项。我已经用下面的代码做到了。它用于查看更多/查看更少选项。

//视图控制器类

var expanded:[IndexPath] = []

//Custom protocol

    func viewMoreTapped(cell: tableviewcell) 
        
        let indexpath = EntriesTableView.indexPath(for: cell)
        let indexPath = IndexPath(item: indexpath!.row, section: indexpath!.section)
        if(expanded.contains(indexPath)) 
            expanded.removeAll  (checkPath) -> Bool in
                return checkPath == indexPath
            
         else 
            expanded.append(indexPath)
        
        entriesTableView.beginUpdates()
        entriesTableView.reloadRows(at: [indexPath], with: .none)
        entriesTableView.endUpdates()
    

@IBAction func expandAllBtnAction(_ sender: Any) 
    
    isExpandedAll = !isExpandedAll
    expandAllButton.titlelabel.text = isExpandedAll ? "Open All" : "Close All"
    self.entriesTableView.reloadData()



        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
                 let cell = tableView.dequeueReusableCell(withIdentifier:"cellIdentifier", for:
         indexPath) as! MyTableViewCell
        let checkPath = IndexPath(row:indexPath.row, section: indexPath.section)
        if expanded.contains(checkPath) 
            cell.cellConfigure(index: indexPath.row, isexpanded: true, info: Info, expandedAll: isExpandedAll)
         else 
            cell.cellConfigure(index: indexPath.row, isexpanded: false, info: Info, expandedAll: isExpandedAll)
        

    return cell



//Tableview cell class

    var isExpanded: Bool = false

    func cellConfigure(index: Int, isexpanded : Bool, info: Info, expandedAll: Bool) 

//For open all/close all handling
      if expandedAll && isExpanded == false 
            isExpanded = true
            viewMoreBtn.titleLabel?.text = "View Less"
         else  
            viewMoreBtn.titleLabel?.text = isExpanded ? "View Less" : "View More"
        
  //view more/view less handling               cellHeight.constant = isExpanded ? 40 : 120



    @IBAction func viewMoreBtnAction(_ sender: Any) 
        
        isExpanded = !isExpanded
        delegate?.viewMoreTapped(cell: self) // this is custom protocol
    

每个单元格都可以正常工作查看更多/查看更少,但是在用户点击全部打开后,如果用户有,它应该打开所有单元格和每个单元格点击少看,它应该只关闭选定的单元格。但是,那个时候不行。

要求是

    如果用户点击查看更多,它应该是打开选定的单元格。如果用户点击view less,它应该是关闭选定的单元格。 此外,如果用户点击全部打开,所有单元格都应展开,同时如果用户点击特定单元格的视图更少,则此时只有选定的单元格应关闭。 如果用户点击全部关闭,所有单元格都应该关闭,如果用户在关闭所有显示时点击视图较少,则只有选定的单元格应该关闭。

有什么建议吗?

【问题讨论】:

我不会使用IndexPath 的数组,而是使用Set<IndexPath>。然后添加从集合中删除给定索引路径的方法既高效又简单,就像检查给定索引路径的存在一样。 我的问题是,如何处理全部展开/全部折叠 收起一切都很简单;只需从集合中删除所有元素并重新加载表格视图。 Expand all 大致相同,只是您需要一个循环将所有索引路径插入集合中,然后重新加载 tableview。我建议您不要直接在单元格中切换isExpanded。让视图控制器设置它并在属性上添加didSet 以更改单元格外观。 如果可能的话,你能不能把你的答案贴出来,我在这里有点困惑,谢谢 【参考方案1】:

我会使用IndexSet 来跟踪展开的行;使用集合更容易插入、删除和检查是否存在索引路径。

要折叠所有行,您只需从集合中删除所有元素。要展开所有,您将所有索引路径插入到集合中。

您尚未提供有关如何存储表数据的详细信息。就我的回答而言,我将使用一个名为 data 的数组数组 - 外部数组是部分,每个内部数组是该部分中的行。即numberOfSectionsdata.count,一个section的行数是data[indexPath.section].count

视图控制器


var expanded = [IndexSet]()

//Custom protocol


func loadData() 
    // After data is fetched
    self.expanded = Array(repeating: IndexSet(),count:data.count)
    self.tableView.reloadData()


func viewMoreTapped(cell: tableviewcell) 
        
   guard let indexPath = entriesTableView.indexPath(for: cell) else 
       return
   

   let row = indexPath.row
   let section = indexPath.section

   if self.expanded[section].contains(row) 
       self.expanded[section].remove(row) 
    else 
       self.expanded[section].insert(row)
   

   self.entriesTableView.beginUpdates()
   self.entriesTableView.reloadRows(at: [indexPath], with: .none)
   self.entriesTableView.endUpdates()


@IBAction func expandAllBtnAction(_ sender: Any) 
    
    isExpandedAll.toggle()
    expandAllButton.titlelabel.text = isExpandedAll ? "Open All" : "Close All"
    
    if isExpandedAll 
        self.expanded = data.map  return IndexSet(integersIn: 0..<$0.count)
     else 
        self.expanded = Array(repeating: IndexSet(),count:data.count)
    
    self.entriesTableView.reloadData()

      
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    let cell = tableView.dequeueReusableCell(withIdentifier:"cellIdentifier", for:
         indexPath) as! MyTableViewCell
    cell.cellConfigure(isExpanded: self.expanded[indexPath.section].contains(indexPath.row), info: info) // A cell should never need to know its index path

    return cell

单元格

var isExpanded: Bool = false

func cellConfigure(isExpanded : Bool, info: Info) 

    viewMoreBtn.titleLabel?.text = isExpanded ? "View less":"View more"
    cellHeight.constant = isExpanded ? 40 : 120



@IBAction func viewMoreBtnAction(_ sender: Any) 
    delegate?.viewMoreTapped(cell: self) // this is custom protocol

一般注意事项、变量和函数应以小写字母开头。类和结构名称应以大写字母开头。

【讨论】:

非常感谢@Paulw11 的宝贵建议,但是我有多个tableview 部分,每个部分都有多行,我如何在此处检查此数组计数 self.expanded.insert(integersIn:0. . 可能最简单的方法是使用IndexSet的数组;每个部分一个。然后,您可以调整我的代码以使用正确的索引集,并在您全选/取消全选时使用for 循环清除或插入每个集的索引。 那么,假设如果我的表中有 100 个部分,那么我需要使用 100 个 IndexSet 吗?这是好习惯吗? Paulw11 为什么不呢?如果您有 100 个部分,那么您需要跟踪这 100 个部分中行的展开状态。 但是,我试过这个逻辑,好像没有效果,我的意思是它没有扩展或崩溃。似乎它应该存储同时包含 Section 和 Row 的 Indexpath。

以上是关于如何处理表视图单元格中的全部打开/全部关闭,每个单元格在 iOS Swift 中具有查看更多/查看更少选项的主要内容,如果未能解决你的问题,请参考以下文章

sql PostgreSQL:如何处理表和视图依赖项

如何让excel单元格中的内容全部显示出来

集群中多线程如何处理表中的数据的问题

iOS - 如何处理自定义表格单元格中的方向变化

表格视图单元格中的 ImageView 切断标签(自动布局)[关闭]

如何为自定义表格视图单元格中的按钮单击获取不同的视图控制器