静态和动态单元格的 UITableView 混合?

Posted

技术标签:

【中文标题】静态和动态单元格的 UITableView 混合?【英文标题】:UITableView Mix of Static and Dynamic Cells? 【发布时间】:2013-08-09 18:54:23 【问题描述】:

我知道您不能在单个 UITableView 中混合使用静态和动态单元格类型,但我想不出更好的方式来描述我的问题。

我有几个具有固定内容的预定单元格,我还有未知数量的具有动态内容的单元格位于中间。所以我想让我的桌子看起来像这样:

Fixed
Fixed
Fixed
Dynamic
Dynamic
Dynamic
Dynamic
Dynamic
Fixed
Fixed

那么您究竟建议我如何在cellForRowAtIndexPath 方法中处理这个问题?

谢谢。

【问题讨论】:

用户在视图中时动态单元格的数量是否会发生变化? 【参考方案1】:

苦苦挣扎1天,找到最佳解决方案

为 Swift 4 更新

对于问题的情况:

    将 tableView 的部分设置为 3

    在要应用动态单元格的第二部分添加一个空的tableview单元格,将单元格的标识符更改为WiFiTableViewCell

    创建一个名为WiFiTableViewCell的新XIB文件

    在tableViewController的ViewDidLoad函数中注册Nib

    tableView.register(UINib(nibName: "WiFiTableViewCell", bundle: nil), forCellReuseIdentifier: "WiFiTableViewCell")
    

    添加以下代码以同时使用动态和静态单元格

    override func numberOfSections(in tableView: UITableView) -> Int 
    
        return 3
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        if section == 1 
            return self.dataSource.count
            //the datasource of the dynamic section
        
        return super.tableView(tableView, numberOfRowsInSection: section)
     
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        if indexPath.section == 1 
            let cell = tableView.dequeueReusableCell(withIdentifier: "WiFiTableViewCell") as! WiFiTableViewCell
            return cell
        
        return super.tableView(tableView, cellForRowAt: indexPath)
    
    
     override func tableView(_ tableView: UITableView, indentationLevelForRowAt indexPath: NSIndexPath) -> Int 
         if indexPath.section == 1 
             let newIndexPath = IndexPath(row: 0, section: indexPath.section)
             return super.tableView(tableView, indentationLevelForRowAt: newIndexPath)
         
         return super.tableView(tableView, indentationLevelForRowAt: indexPath)
     
    
     override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
         if indexPath.section == 1 
             return 44
         
         return super.tableView(tableView, heightForRowAt: indexPath)
      
    

【讨论】:

感谢@Shan Ye 的精彩回答。 这很完美。通过register单元格,tableView可以混合静态单元格和动态单元格。 第 5 步是有意义的。这是为了避免错误。 More detail can refer this post.。再次感谢@ShanYe。 不要像我一样忘记第 2 步(添加一个空单元格),这会导致崩溃,让我抓狂。 花了20多小时后你救了我!谢谢@山野【参考方案2】:

正如您所说,您不能混合使用静态和动态单元格。但是,您可以将内容分解为对应于每个组的不同数据数组。然后将表格分成不同的部分,并从 cellForRowAtIndexPath: 中的正确数组加载数据。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

    static NSString *cellID = @"CELLID";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID forIndexPath:indexPath];

    switch (indexPath.section) 
        case 0:
            cell.textLabel.text = self.arrayOfStaticThings1[indexPath.row];
        break;

        case 1:
            cell.textLabel.text = self.arrayOfDynamicThings[indexPath.row];
        break;

        case 2:
            cell.textLabel.text = self.arrayOfStaticThings2[indexPath.row];
        break;

        default:
            break;
    

    return cell;




- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

    switch (section) 
        case 0:
            return self.arrayOfStaticThings1.count;
        break;

        case 1:
            return self.arrayOfDynamicThings.count;
        break;

        case 2:
            return self.arrayOfStaticThings2.count;
        break;

        default:
            return 0;
            break;
    

【讨论】:

我没有使用你的代码,但主要的想法就在这里。谢谢?【参考方案3】:

目前最好、最简单的方法

1) 在动态 TableView 的 Header 和 Footer 中放置两个容器视图 2)将静态TableViews分配给这些容器并取消勾选“启用滚动”

请在https://***.com/a/22524085/1537178查看我的插图

【讨论】:

@surajkthomas 根本没有代码。仅故事板 当我将容器视图放置到页脚并向其添加 uitableviewcontroller 类时出现此错误。容器视图不能放置在运行时重复的元素中。 这确实是最好和最简单的解决方案,在情节提要中创建嵌入视图控制器非常简单,您无需在 tableView:cellForRowAtIndexPath: 和 tableView: 中找出“静态单元格”偏移量: didSelectRowAtIndexPath: 或者你可以把动态TableView放到静态TableView的一个单元格中。 @MazenKasser,非常感谢您的回复。当某些复选框被选中或未选中,或者某些 UILabel 文本是多行时,tableView 的 contentSize 会发生变化。因此,它需要经常将帧大小与 contentSize 同步。 register a cell 用于动态单元格,与静态 tableView 单元格混合。它运行良好,并且易于配置这些单元。【参考方案4】:

suraj k thomas,看看我的这个结构,效果很好。 @firecast 我没有在这个项目中使用约束,但是我确实根据容器的 tableview 高度设置了容器的高度,如下所示:

    ContainerViewController *containerVC = self.childViewControllers.firstObject;
    CGRect frame = self.containerView.frame;
    frame.origin.x = 0;
    frame.origin.y = 0;
    frame.size.width = self.tableView.frame.size.width;
    frame.size.height = containerVC.tableView.contentSize.height;
    self.containerView.frame = frame;
    [self.tableView setTableHeaderView:self.containerView];

希望对您有所帮助,如果您有任何问题,请告诉我。

【讨论】:

我遇到了与在他的结构中询问并在我的应用程序中实现您的结构的问题相同的问题。除了我无法使用情节提要对 ContainerView 应用任何约束这一事实之外,一切都很好。你试过这样做吗 感谢您的更新...我能够像您在上面显示的那样以编程方式完成它,但希望它使用约束来根据各种屏幕尺寸操纵高度。无论如何谢谢:) @firecast 如果您添加一个视图然后在该视图内添加一个容器,则只能对表头视图实施约束,但是我相信您仍然需要以编程方式从 containerVC 设置表头视图高度。高度【参考方案5】:

添加一个新的隐藏 UITableView 来保存您的动态单元格

步骤:

1- 在您的主要UITableViewController 末尾附加新的Section, 在这个Section 里面只添加一个UITableViewCell, 在单元格内插入一个新的UITableView。 让我们将新表称为 tblPrototypes,因为 它将是原型单元格的持有者。

2- 现在将 tblPrototypes 的类型设置为动态原型, 然后根据需要添加尽可能多的原型UITableViewCells。

3- 在 Main Static UITableView 的主控制器中为 tblPrototypes 添加一个 Outlet, 让我们称它为tablePrototypes,当然它的类型是UITableView

编码部分:

首先确保在 UI 中隐藏 tblPrototypes, 由于它是主表中的最后一部分,因此您可以这样做:

@IBOutlet weak var tblPrototypes: UITableView!

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

最后一节将不会呈现。

现在,当您想要显示动态单元格时,您可以这样做:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 

  let needDynamic = true

  if !needDynamic 
    return super.tableView(tableView, cellForRowAt: indexPath)
  

  let cellId = "dynamicCellId1"
  let cell = self.tblPrototypes.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
  // configure the cell

  return cell


【讨论】:

嘿!我确实实现了你的答案。我做了3个部分。第一个是 4 个静态单元。第二个是空的,情节提要中有 0 个单元格。第三个隐藏在动态类型单元格中。我想填充从第 3 部分到第 2 部分的动态单元格。但是在设置了部分和单元格的数量之后,当我尝试将第一个单元格设置为第二个部分时 - 我在空数组范围内得到了 0 索引。但是,当我从情节提要更改第二部分中的单元格数量时,它工作正常。它与 0 个单元格无关。我什至在运行时检查单元格的数量。在情节提要中将第一个动态单元格设置为具有 0 个单元格的部分后,它会崩溃。 您需要覆盖 func tableView:indentationLevelForRowAt: 以避免崩溃【参考方案6】:

    使用动态原型正常实现您的 tableView。 对于每个自定义单元格,使用 1 个原型。举个简单的例子,我们将使用 2 个单元格,AddCell 和 RoomCell。 AddCell 在第一行,RoomCell 在第二行和下面的任何单元格。

    记得将numberofRowsInSection 的计数增加适当数量的静态单元格(在本例中为 1)。因此,如果您要返回数组的计数来确定行数,那么对于此示例,它将为 return array.count + 1,因为我们有 1 个静态单元格。

    我通常也会为每个单元格创建一个自定义类。这通常使在 View Controller 中配置单元格变得更简单,并且是分离代码的好方法,但它是可选的。下面的示例为每个单元格使用自定义类。如果不使用自定义类,请将 if let 语句替换为不带可选转换的 if 语句。

注意:下面的configureCell是自定义类RoomCell中动态配置单元格的方法

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    if indexPath.row == 0 
        if let cell =  tableView.dequeueReusableCell(withIdentifier: "AddCell", for: indexPath) as? AddCell 
            return cell
        
     else 
        if let cell = tableView.dequeueReusableCell(withIdentifier: "RoomCell", for: indexPath) as? RoomCell 
            cell.configureCell(user: user, room: room)
            return cell
        
    
    return UITableViewCell() //returns empty cell if something fails

【讨论】:

以上是关于静态和动态单元格的 UITableView 混合?的主要内容,如果未能解决你的问题,请参考以下文章

涉及 JSON 解析以及静态和动态 UITableView 单元格的 Swift3 项目 - 使其更加面向对象

静态部分/单元格的 UITableView 背景图像

具有静态单元的 UItableView 包含 2 个 UItableview,每个都有具有动态高度的自定义单元

静态单元格的内容没有出现 UITableView

UItableview 单元格的动态高度与 UItableview 单元格内的 UItableview

是否可以在 UITableview 中搜索静态单元格?