【问题标题】:UITableView: Handle cell selection in a mixed cell table view static and dynamic cellsUITableView:在混合单元格表视图静态和动态单元格中处理单元格选择
【发布时间】:2012-10-03 05:27:39
【问题描述】:

我正在尝试在分组表格视图中混合动态和静态单元格:我想在顶部获得 两个带有静态单元格的部分,然后是 动态单元格部分(请参考下面的截图)。我已将表格视图内容设置为静态单元格

编辑

根据 AppleFreak 的建议,我将代码更改如下:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell;
    if (indexPath.section <= 1) { // section <= 1 indicates static cells
        cell = [super tableView:tableView cellForRowAtIndexPath:indexPath]; 
    } else { // section > 1 indicates dynamic cells
        CellIdentifier = [NSString stringWithFormat:@"section%idynamic",indexPath.section];
        cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
    }
return cell;

}

但是,我的应用程序崩溃并显示错误消息

由于未捕获的异常而终止应用程序 'NSInternalInconsistencyException',原因:'UITableView 数据源 必须从 tableView 返回一个单元格:cellForRowAtIndexPath:'

对于第 0 节和第 0 行。从 cell = [super tableView:tableView cellForRowAtIndexPath:indexPath] 返回的第 0 节和第 0 行的单元格是 nil

我的代码有什么问题?我的网点有什么问题吗?我没有设置任何插座,因为我正在继承UITableViewController 并且据说没有设置任何用于设置tableview 的插座(?)。有关如何更好地做到这一点的任何建议?

编辑二

我在故事板中重新创建了我的场景(请参阅上面更新的屏幕截图)并重写了视图控制器,以便从一个新的基础开始。我还按照 applefreak 的建议阅读了 Apple 论坛中的描述。但是,我使用numberOfSectionsInTableView:tableView 方法解决了我的第一个问题,其中我将静态部分的数量(两个)增加了一个。

  - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return [super numberOfSectionsInTableView:tableView] + 1 ; }

应用程序崩溃并显示错误消息:

由于未捕获的异常“NSRangeException”而终止应用程序,原因: '*** -[__NSArrayI objectAtIndex:]: 索引 2 超出范围 [0 .. 1]'

即使我遵循了 Apple 和 applefreak 的建议,为什么这段代码对我不起作用?在 iOS 6 中 tableView 可能发生了一些变化?

解决方案:我现在在下面的答案中使用 AppleFreaks 代码示例来解决这个问题。谢谢你,AppleFreak!

编辑 III:单元格选择:

如何在混合(动态和静态单元格)单元格表格视图中处理单元格选择? 我什么时候打电话给super,什么时候打电话给self tableView? 当我使用

[[super tableView] selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone]

并尝试使用以下命令检查选定的索引路径:

UITableView *tableView = [super tableView];
if ( [[tableView indexPathForSelectedRow] isEqual:customGrowthIndexPath] ) { .. }

我得到nil 的返回值。

由于我找不到错误的根源,非常感谢您的帮助

【问题讨论】:

  • 您是否按照课程文档注册了笔尖? '重要提示:在调用此方法之前,您必须使用 registerNib:forCellReuseIdentifier: 或 registerClass:forCellReuseIdentifier: 方法注册类或 nib 文件。'

标签: objective-c ios ios5 uitableview


【解决方案1】:

对于静态单元格,您需要调用超级方法。我假设您将扩展 UITableViewController。见下文

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell;

    /* Detect cell is static or dynamic(prototype) based on the index path and your settings */

    if ("Cell is prototype") 
       cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
   else if ("Cell is static")
       cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];

  // Modify cell properties if you want

   return cell;
}

有关混合单元的更多信息,请参阅苹果论坛上的Mixing static and dynamic table view content 讨论。

[编辑]

如果您还没有阅读上面的苹果链接,请仔细阅读。对于动态内容,您将首次使用代码本身中的给定标识符构建单元格。下次在病房中,您将出列单元而不是构建它!还是老样子。

此外,请记住静态数据源认为只有 2 个部分(例如)。你不能问它关于第 2 节的问题,因为它认为只有第 0 节和第 1 节。如果你要在表格末尾以外的任何地方插入动态内容,你需要在转发数据时对 super 撒谎源方法。例如,您的 numberOfRowsInSection: 方法应如下所示:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (section == 1) {
        return 1;
    }
    else if (section > 1){
        section--; // Basically you are forming sections for dynamic content
    }

    return [super tableView:tableView numberOfRowsInSection:section];
}

关键是对您的动态内容进行调整,以便静态数据源仍能获得它所期望的值

[编辑]

这是完整的工作示例并经过测试。只需复制代码中的所有以下方法,它应该可以直接工作。当您有混合单元格时,您必须覆盖所有 tableview 方法。根据您的要求返回“numberOfSectionsInTableView”中静态和动态部分的总数,然后在剩余的每个方法中返回;如果有问题的部分或行是静态的,只需调用 super,如果它是动态的,则像在普通 UITableViewController 子类中那样传回相关细节。在此示例中,我只是返回 nil 或硬编码值。

有关更多信息,请查看苹果论坛上的this 主题。

- (int)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 3;
}

- (NSString*)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    return nil;
}

- (NSString*)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
{
    return nil;
}

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
    return NO;
}

- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
    return NO;
}

-(float)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return 44.0f;
}

- (float)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
    return 44.0f;
}

- (float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 44.0f;
}

- (UIView*)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
    return nil;
}

-(UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    return nil;
}

-(int)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 5;
}

- (int)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if(section == 0)
        return 2;
    if(section == 1)
        return 2;

    return 5;
}

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if(indexPath.section <= 1)
        return [super tableView:tableView cellForRowAtIndexPath:indexPath];

    static NSString *CellIdentifier = @"Cell";


    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil)
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];


    cell.textLabel.text = @"dynamic row";

    return cell;
}

[编辑]

您不会在 didSelectRowAtIndexPath 中调用 super。这是直截了当的。请参阅下面的代码。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
     int row = indexPath.row;
     [tableView deselectRowAtIndexPath:indexPath animated:YES];

     UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
     //process the cell
}

【讨论】:

  • 我已根据您的建议更改了代码,但仍有问题(请参阅上面的更新问题)。 cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];returns nil 在我的情况下。你知道我的代码有什么问题吗?我的插座有什么问题吗?谢谢你,苹果怪胎!
  • 这很奇怪!我做了完全相同的事情,并且没有任何问题。让我检查一下,我会尽快回复您。只是不要忘记提供标识符。如果您在此处调用 Super,则无需注册静态单元格。你看到苹果链接了吗?
  • 我没有做任何不同的事情!从您附上的图片来看,您似乎没有两个部分是静态的?他们是三个?对于动态单元格,您不需要将它们添加到 XIB 或场景中。您将从代码中执行此操作。我有所有静态单元格类型自定义,其中包含不同的图像和标签。我没有为静态单元设置重用标识符,也没有明确注册它们。它可以直接工作。
  • cell = [super tableView:tableView cellForRowAtIndexPath:indexPath]检索单元格后如何设置表格单元格样式?如果你没有在 Interface Builder 中设置你的动态(=原型)单元格,你是如何在代码中设置的?您如何将重用标识符分配给这些单元格?谢谢!
  • 我已经编辑了我的问题:当我返回的部分数量高于静态部分的数量时,我的应用程序在 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 方法中崩溃。我正在使用 iOS 6。
【解决方案2】:

最佳且最简单将自定义动态单元格与静态单元格一起使用的方法:

1) 将 Container View 放在动态 TableView 的 Header 中 2)将Static TableView分配给这个Container并取消勾选“Scrolling Enabled”

【讨论】:

    【解决方案3】:

    如果没有要出列的单元格,则单元格将为 nil,因此您必须分配/初始化一个新单元格。请在尝试出队后检查单元格的值,如果为 nil,则创建一个新单元格。

    【讨论】:

    • 我正在使用 iOS 6,根据 Apple 的 documentation dequeueResusableCellWithIdentifier:forIndexPath 总是返回一个实例化的单元格:“返回类型:一个带有相关重用标识符的 UITableViewCell 对象。这个方法总是返回一个有效单元格。"
    • 好吧,不知道你用的是iOS6 :)
    【解决方案4】:

    感谢 applefreak 的全面回答。我将在这里添加我的建议,如果您为静态部分添加虚拟部分,则不需要任何部分计算。您甚至可以在那里添加占位符元素。这样您就不必重新创建NSIndexPaths。一件重要的事情是重写每个使用 NSIndexPaths 的方法,因为这些方法会由于数组索引不匹配而导致应用程序崩溃。

    此外,我完全放弃了使用出队机制并静态创建单元格,因为我拥有的动态内容没有那么多单元格。这使得tableView:cellForRowAtIndexPath: 非常简单。

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        if (indexPath.section == 0)
        {
            return _locationCells[indexPath.row];
        }
        else
        {
            return [super tableView:tableView cellForRowAtIndexPath:indexPath];
        }
    }
    

    记住占位符部分。

    【讨论】:

    • 您是如何创建 _locationCells 以及在哪里创建的?
    • 我在视图控制器的viewDidLoad 方法中创建它们。我使用initWithStyle:reuseIdentifier: 并将标识符设置为nil,因为没有什么可重用的。在我的应用程序的另一部分,我使用表格视图的dequeueResusableCellWithIdentifier:forIndexPath,因为单元格是从 nib 文件加载的。
    • 谢谢,有道理,但不幸的是我没有时间测试这个。所以你的意思是 initWithStyle:reuseIdentifier 你可以创建自定义单元格。
    • 是的,如果自定义是指空的或预定义的单元格。但是,当要放置多个子视图时,我发现使用带有 nib 的自定义单元格类要容易得多。
    【解决方案5】:
    UITableViewCell *cell = [self dequeueReusableCellWithIdentifier:@"cellIdentify"];
    if (cell == nil)
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cellIdentify"];
    

    只是你不调用alloc。 如果你不想重用,就不要调用 dequeueReusableCellWithIdentifier。

    【讨论】:

      【解决方案6】:

      这可以通过为具有动态单元格的部分添加“假”部分来简单地解决。唯一需要更改的是 cellForRowAt 函数,您可以在其中将“假”部分的动态单元格出列,而不是让它们从情节提要中的内容中使用。对于其余的单元格,您调用

      super.tableView(tableview, cellforRowAt: indexPath)
      

      无需重写tableViewController的所有功能

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多