重新排序单元格后重新加载自定义UITableViewCell

时间:2010-11-21 10:18:40

标签: iphone cocoa-touch uikit uitableview

UITableView使用自定义UITableViewCell。单元格可以具有三种类型的背景图像之一(在每个单元格的.backgroundView.image属性中设置):顶部,中间或底部。顶部和底部图像用于第一个和最后一个单元格,并且具有圆角(非常类似于分组的UITableView个单元格)。 UITableView中的所有其他“中间”单元格都具有矩形中间背景图像。

我的问题是,在UITableView编辑模式下重新排序单元格时,单元格不会根据新位置刷新不同的背景图像。例如,如果我将第一个单元格移动到表格的中间,它仍然保留其原始的“顶部”背景图像(带有圆角),并且出现在表格视图顶部的新单元格仍然具有其原始“中间”背景图片,这看起来有点奇怪。

我可以通过在表视图上执行reloadData来解决这个问题,但这样做的问题是不能给出更改的优美动画。我注意到,当移动/拖动单元格时重新排序标准分组UITableView时,相关单元格上的背景图像会发生变化(甚至在移动的单元格被放入其新位置之前),这看起来非常好。我想达到同样的目的。

为此,我实现了tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath,每次在表视图中拖动一行时都会调用它。在此我尝试了各种设置backgroundView.image的方法,包括直接设置图像,然后明确告诉它使用setNeedsLayoutsetNeedsDisplay重绘单元格和/或图像但似乎没有使细胞重绘。我NSLog'对这些更改的结果进行了调整,它们似乎正在提交到单元格,因为正确的值出现在NSLog中,但单元格似乎没有在屏幕上更新。

如果有人能够指出我做错了什么,或者建议一个更好的方法来实现工作结果,我将非常感激。谢谢!

编辑:以下代码从赏金中提取并格式化,以便更容易消化:

UIImage *rowBackground;
UIImage *selectionBackground;
NSInteger sectionRows = [_tableView numberOfRowsInSection:[indexPath section]];
NSInteger row = [indexPath row];
if (row == 0 && row == sectionRows - 1)
{
    rowBackground = [UIImage imageNamed:@"field_title_bkg.png"];
    selectionBackground = [UIImage imageNamed:@"field_title_bkg.png"];
}
else if (row == 0)
{
    rowBackground = [UIImage imageNamed:@"table_row_top_bkg.png"];
    selectionBackground = [UIImage imageNamed:@"table_row_top_bkg.png"];
}
else if (row == sectionRows - 1)
{
    rowBackground = [UIImage imageNamed:@"table_bottom_row_bkg.png"];
    selectionBackground = [UIImage imageNamed:@"table_bottom_row_bkg.png"];
}
else
{
    rowBackground = [UIImage imageNamed:@"table_row_bkg.png"];
    selectionBackground = [UIImage imageNamed:@"table_row_bkg.png"];
}
UIImageView *rowBackGroundImageView = [[UIImageView alloc] initWithImage:rowBackground];
UIImageView *rowBackGroundSelectionImageView = [[UIImageView alloc] initWithImage:selectionBackground];
if (row != sectionRows - 1)
{
    UIImageView *sep = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cell_separator.png"]];
    [sep setFrame:CGRectMake(20, 56, 280, 1)];
    [rowBackGroundImageView addSubview:sep];
}
[cell setBackgroundView:rowBackGroundImageView];
[rowBackGroundImageView release];

6 个答案:

答案 0 :(得分:4)

在项目中写下以下代码,它应该按照预期工作。

- (NSIndexPath *)tableView:(UITableView *)tableView
targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath
      toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
{
    NSInteger sectionRows = [tableView numberOfRowsInSection:[sourceIndexPath section]];

    UITableViewCell *sourceCell = [tableView cellForRowAtIndexPath:sourceIndexPath];
    UITableViewCell *destCell = [tableView cellForRowAtIndexPath:proposedDestinationIndexPath];

    if(sourceIndexPath.row == 0 && proposedDestinationIndexPath.row == 1)
    {
        ((UIImageView *)destCell.backgroundView).image = [UIImage imageNamed:@"table_row_top_bkg.png"];

        if(proposedDestinationIndexPath.row == sectionRows - 1)
            ((UIImageView *)sourceCell.backgroundView).image = [UIImage imageNamed:@"table_bottom_row_bkg.png"];
        else
            ((UIImageView *)sourceCell.backgroundView).image = [UIImage imageNamed:@"table_row_bkg.png"];
    }

    else if(sourceIndexPath.row == sectionRows - 1 && proposedDestinationIndexPath.row == sectionRows - 2)
    {
        ((UIImageView *)destCell.backgroundView).image = [UIImage imageNamed:@"table_bottom_row_bkg.png"];

        if(proposedDestinationIndexPath.row == 0)
            ((UIImageView *)sourceCell.backgroundView).image = [UIImage imageNamed:@"table_row_top_bkg.png"];
        else
            ((UIImageView *)sourceCell.backgroundView).image = [UIImage imageNamed:@"table_row_bkg.png"];
    }

    else if(proposedDestinationIndexPath.row == 0)
    {
        ((UIImageView *)sourceCell.backgroundView).image = [UIImage imageNamed:@"table_row_top_bkg.png"];

        destCell = [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:proposedDestinationIndexPath.section]];
        if(sectionRows == 2)
            ((UIImageView *)destCell.backgroundView).image = [UIImage imageNamed:@"table_bottom_row_bkg.png"];
        else
            ((UIImageView *)destCell.backgroundView).image = [UIImage imageNamed:@"table_row_bkg.png"];
    }

    else if(proposedDestinationIndexPath.row == sectionRows - 1)
    {
        ((UIImageView *)sourceCell.backgroundView).image = [UIImage imageNamed:@"table_bottom_row_bkg.png"];

        destCell = [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:sectionRows - 1 inSection:proposedDestinationIndexPath.section]];
        if(sectionRows == 2)
            ((UIImageView *)destCell.backgroundView).image = [UIImage imageNamed:@"table_row_top_bkg.png"];
        else
            ((UIImageView *)destCell.backgroundView).image = [UIImage imageNamed:@"table_row_bkg.png"];
    }

    return proposedDestinationIndexPath;
}

答案 1 :(得分:1)

如果您只想重新加载几个单元格而不是整个表格,您可以使用:

reloadRowsAtIndexPaths:withRowAnimation:

可用作UITableView的实例方法。

答案 2 :(得分:1)

试试这个:

[tableView beginUpdates];
[tableView endUpdates];

答案 3 :(得分:0)

我没有尝试过,但为什么不在cellForRowAtIndexPath方法上测试indexPath.row值并为第一行和最后一行提供不同的backgroundView.image值?

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

我希望这会有所帮助。 干杯, ROG

答案 4 :(得分:0)

<强> (this solution only works for the reordering of rows within the same section. It'll fail when dragging and dropping rows to a different section)

在重新排序后更新单元格的详细信息标签文本时遇到了同样的问题。

我用以下代码解决了它:

- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath  toIndexPath:(NSIndexPath *)toIndexPath 
{
UITableViewCell* cell = [self.table cellForRowAtIndexPath:fromIndexPath]; 
cell.detailTextLabel.text = @"NEW STRING";
}

请注意,您必须更新 fromIndexPath 处的单元格,因为在此方法返回之前,似乎表格视图的内部状态不会更新。如果您在toIndexPath获取单元格,则在重新排序完成后,您将看到相邻单元格已更新。 (无论是顶部还是底部)。

答案 5 :(得分:0)

在ios sdk中部分重新加载行的api运行不正常(这就是为什么ppl在这里关注这篇文章)

在重新排序动画结束后,我最终使用计时器重新加载整个数据。 它对我有用。

- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath 
{
    //things to be done when reordering rows
    ....


    //issue a timer to reload data
    NSTimer* timer = [NSTimer scheduledTimerWithTimeInterval: 0.1
                                             target: self
                                           selector:@selector(updateRow)
                                           userInfo: nil repeats:NO];


}


-(void) updateRow
{

    [self.table reloadData];

}