在每个单元格都包含表格视图的表格视图中选择新单元格时,无法取消选择先前选择的单元格

Posted

技术标签:

【中文标题】在每个单元格都包含表格视图的表格视图中选择新单元格时,无法取消选择先前选择的单元格【英文标题】:Can’t deselect previously selected cell when a new one is selected in a tableview where each cell contains tableview 【发布时间】:2019-10-30 09:02:05 【问题描述】:

我有一个表格视图,其中每个单元格都是一个自定义表格视图单元格。该自定义表格视图单元格包含一个表格视图和一个标签。 可以说,外部 tableview 称为 MainTableView。 MainTableView 的每个单元格都包含另一个 tableview。问题是,当我选择 内部 tableview 单元格一个接一个先前选择的单元格没有被取消选择。在第一张图像中,我选择的单元格包含文本“Two”。然后在第二张图片中,我选择的单元格包含文本“五”,但之前选择的单元格“二”仍处于选择模式。我想在选择新单元格时取消选择上一个单元格。

我试过了

tableView.deselectRow(at: IndexPath, animated: Bool)

自定义 tableviewcell 类中的 didSelectRowAt 中的此方法,但它没有起到作用,因为之前的 indexPath 来自单独的 tableview。那么,如何取消选择上一个呢?

【问题讨论】:

首先获取第一个 tableview 索引路径,然后获取 InsideTableview 并在所选索引路径处取消选择该行 【参考方案1】:

获取正确的内部tableView,

首先,你应该记录外部tableView的cell indexPath,内部tableView在哪个cell。

所以你应该记录两个 indexPathes

var selectionRowInfo: (lastOutsideIP: IndexPath?, lastInnerIP: IndexPath?)

其次,您可以通过 outsideTableView 获得正确的 tableView。

如果内表可见,你应该立即处理它。通过outTableView.indexPathsForVisibleRows

else条件,不用处理。 tableView 重用机制会刷新它的状态。

    // pseudo code.


    if let lastOut = lastOutsideIP, let visibleRows = outTableView.indexPathsForVisibleRows, visibleRows.contains(lastOut)
        let cell = tableView.cellForRow(at: lastOut) as! YourCell
        // get the correct inner tableView via the cell
    

因为内部的 tableViews 彼此不相关。选择表一的单元格,不会影响表二的单元格的选择。

所以你应该手动建立连接。

使用属性存储状态var lastIndexPath: IndexPath?

然后每次选择一个indexPath,

  // pseudo code.
  if let last = lastIndexPath
        tableView.deselectRow(at: last, animated: true) 
  

请注意,您应该找到正确的内部 tableView,它具有 lastIndexPath

【讨论】:

获得正确的内部 tableView 的最佳方法是什么? 更新。 Via the cell ,单元格应该有一些方法来处理它的内部 tableView 。 我已经解决了问题并在此处添加了答案,但不确定这是最好的方法 它消耗内存,单元重用机制不好用。【参考方案2】:

前面的答案是正确的,但有一个缺陷 - 它无法区分 tableViews,这是最重要的部分。此外,如果 tableView 的行数不同,则可能会尝试访问不存在的行并导致崩溃。

要在两个 tableViews (tv1 & tv2) 中跟踪所选行,您需要在每个表中保留所选行:

var tv1, tv2: UITableView!
var lastRowForTV1, lastRowForTV2: IndexPath?

然后通过识别正在使用的 tableView 并调整另一个来响应选择(这假设两个 tableView 使用相同的数据源/委托)

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
      if tableView === tv1 
         lastRowForTV1 = indexPath
         if let last = lastRowForTV2 
            tv2.deselectRow(at: last, animated: true)
            lastRowForTV2 = nil
         
       else if tableView === tv2 
         lastRowForTV2 = indexPath
         if let last = lastRowForTV1 
            tv1.deselectRow(at: last, animated: true)
            lastRowForTV1 = nil
         
      
   

【讨论】:

内部tableview的数量并不像你回答的那样固定,它可以是10或20或20左右的任何数字 @Asif 这就是我的观点 - 您需要一个可以处理可变行数的解决方案。上面的解决方案是哪个,为什么前面的解决方案会有崩溃的风险。 是的,可能cell中的table view不存在,因为cell复用机制,可以outTableView.indexPathsForVisibleRows解决 你是说你的外部表格可以有大约 20 个单元格,每个单元格都包含自己的 tableView?如果是这样(a)您可以调整上述答案以使用数组来保存数据,使用元组或简单结构来保存对每个 tableView 的引用及其最后一个索引和(b)我会说你应该重新考虑你的 UI因为这听起来像高度处理器密集型,使代码混乱,甚至更难以排除故障。为什么不将外部数组与部分而不是子数组一起使用? 并且使用可见行是行不通的,因为您需要跟踪所有屏幕外的行,以便在它们回滚时更新它们。【参考方案3】:

我已经通过使用 dengApro 给出的第一个答案的想法解决了这个问题。这个想法是找到包含先前选择的单元格的正确内表。 我有两个文件,一个是 ViewController.swift,其中包含外部 tableview MainTableView。另一种是带有 CustomTableViewCell.xib 的 CustomTableViewCell.swift,其中包含带有 tableview 的自定义单元格。

fileprivate var lastSelectedInnerTableView : Int = -1
fileprivate var lastSelectedRow: Int = -1
fileprivate var tableViewList :[UITableView] = []

我在 CustomTableViewCell 类之外的 CustomTableViewCell.swift 文件中添加了这 3 个变量。 lastSelectedSection , lastSelectedRow 这两个变量用于保持 跟踪最后选择的内部 tableview (lastSelectedInnerTableView) 和该内部 tableView (lastSelectedRow) 的最后选择的单元格。 tableViewList 变量用于保存 内表视图。在 awakeFromNib() 中,我附加了创建的内部表格视图。

override func awakeFromNib() 
    super.awakeFromNib()
    self.tableView.delegate = self
    self.tableView.dataSource = self
    self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
    tableViewList.append(self.tableView) // append the created inner tableviews

然后在 didSelectRowAt 里面我取消了前一个:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
    if lastSelectedInnerTableView != -1 && lastSelectedRow != -1
        self.oldIndexPath.section = 0
        self.oldIndexPath.row = lastSelectedRow
        tableViewList[lastSelectedInnerTableView].deselectRow(at: self.oldIndexPath, animated: true)
    

    lastSelectedInnerTableView = self.innerTableId
    lastSelectedRow = indexPath.row

在 ViewController.swift 中,我在 cellForRowAt 中设置了 innerTableId

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    let customCell: CustomTableViewCell = self.tableView.dequeueReusableCell(withIdentifier: "customCell") as! CustomTableViewCell
    customCell.innerTableId = indexPath.row
    customCell.customCellActionDelegate = self

    return customCell

【讨论】:

以上是关于在每个单元格都包含表格视图的表格视图中选择新单元格时,无法取消选择先前选择的单元格的主要内容,如果未能解决你的问题,请参考以下文章

在表格视图中的所有单元格都已加载后,重新加载表格视图单元格内的集合视图

Swift 表格视图,在表格视图单元格中播放视频,内存泄漏

按表格视图单元格

自动布局 - 在表格单元格中对齐视图

如何在不选择任何行的情况下从 iphone 的表格视图单元格中读取值

自定义表格视图单元格中特定元素的手势