UITableView:处理混合单元格表中的单元格选择视图静态和动态单元格

时间:2012-10-12 11:45:33

标签: objective-c ios ios5 uitableview

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

Mixing dynamic and static table view cells

修改

根据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 dataSource   必须从tableView:cellForRowAtIndexPath:'

返回一个单元格

表示第0部分和第0行。从cell = [super tableView:tableView cellForRowAtIndexPath:indexPath]返回的第0部分和第0行的单元格为nil

我的代码出了什么问题?我的网点可能有问题吗?我没有设置任何出口因为我是UITableViewController的子类,并且据说没有设置tableview的任何出口(?)。关于如何更好地做到这一点的任何建议?

enter image description here

编辑II

我在故事板中重新创建了我的场景(请参阅我上面更新的屏幕截图)并重写视图控制器以便从新基础开始。我也在Apple的论坛中阅读了applefreak建议的描述。但是,我运行方法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的返回值。

由于我无法找到错误的来源,我真的很感激您的帮助

6 个答案:

答案 0 :(得分:13)

对于静态单元格,您需要调用super方法。我假设您将扩展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;
}

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

[编辑]

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

此外,请记住,静态数据源认为只有2个部分(例如)。你不能问第2部分,因为它认为只有第0和第1部分。如果你要将动态内容插入表格的末尾,你需要在转发数据时说谎超级源方法。例如,您的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或硬编码值。

有关更多信息,请查看Apple论坛上的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
}

答案 1 :(得分:1)

BEST&amp; YET EASIEST 使用自定义动态单元格与静态单元格的方法:

1)将容器视图放置在动态TableView的标头中 2)将静态TableView分配给此Container并取消选中“Scrolling Enabled”

答案 2 :(得分:0)

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

答案 3 :(得分:0)

UITableViewCell *cell = [self dequeueReusableCellWithIdentifier:@"cellIdentify"];
if (cell == nil)
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cellIdentify"];

你不要叫alloc。 如果您不想重用,请不要调用dequeueReusableCellWithIdentifier。

答案 4 :(得分:0)

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

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

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

请记住占位符部分。

答案 5 :(得分:0)

这可以通过为具有动态单元格的添加“假”部分来简单地解决。唯一需要改变的是cellForRowAt函数,您可以在其中为“假”部分出列动态单元格,而不是让它们从故事板中的内容中使用。对于剩下的细胞,你打电话给

super.tableView(tableview, cellforRowAt: indexPath)

无需覆盖tableViewController的所有功能