【问题标题】:How can I refresh a UITableView while a user is re-arranging cells?当用户重新排列单元格时,如何刷新 UITableView?
【发布时间】:2011-09-01 05:59:27
【问题描述】:

我有一个可编辑的 UITableView。当我的用户重新排列单元格时,我希望能够更新表格视图,因为当我重新排列底部单元格并将其插入中间时,我遇到了一个有趣的情况。它会产生不需要的效果,因为底行是圆形的,而中间行不应该是圆形的。我怎样才能防止这种情况发生?

为了实现这种外观,我必须设置每个UITableViewCellbackgroundView。顶部和底部使用的图像与中间的图像不同。

更新

我不确定我是否遗漏了任何案例,因为重新订购时图像仍然混乱。

for (NSIndexPath* visibleIndexPath in tableView.indexPathsForVisibleRows) {
        UITableViewCell* cell = [tableView cellForRowAtIndexPath:visibleIndexPath];

        //Top moving to middle rows
        if (sourceIndexPath.row == 0 && proposedDestinationIndexPath.row != sectionRows - 1) {
            ((UIImageView *)cell.backgroundView).image = [UIImage imageNamed:@"tablemiddle55@2x.png"];
        }
        //Top moving to bottom
        else if (sourceIndexPath.row == 0 && proposedDestinationIndexPath.row == sectionRows - 1) {
            ((UIImageView *)cell.backgroundView).image = [UIImage imageNamed:@"tablebottom55@2x.png"];
        }
        //Top moving to top
        else if (sourceIndexPath.row == 0 && proposedDestinationIndexPath.row == 0) {
            ((UIImageView *)cell.backgroundView).image = [UIImage imageNamed:@"tabletop55@2x.png"];
        }
        //Middle moving to top
        else if (sourceIndexPath.row != 0 && sourceIndexPath.row != sectionRows -1 && proposedDestinationIndexPath.row == 0)
        {
            ((UIImageView *)cell.backgroundView).image = [UIImage imageNamed:@"tabletop55@2x.png"];
        }
        //Middle moving to bottom
        else if (sourceIndexPath.row != 0 && sourceIndexPath.row != sectionRows -1 && proposedDestinationIndexPath.row == sectionRows - 1)
        {
            ((UIImageView *)cell.backgroundView).image = [UIImage imageNamed:@"tablebottom55@2x.png"];
        }
        //Middle moving to middle
        else if (sourceIndexPath.row != 0 && sourceIndexPath.row != sectionRows -1 && 
                 proposedDestinationIndexPath.row != sectionRows -1 && proposedDestinationIndexPath.row !=0)
        {
            ((UIImageView *)cell.backgroundView).image = [UIImage imageNamed:@"tablemiddle55@2x.png"];
        }
        //Bottom moving to top
        else if (sourceIndexPath.row == sectionRows - 1 && proposedDestinationIndexPath.row == 0)
        {
            ((UIImageView *)cell.backgroundView).image = [UIImage imageNamed:@"tabletop@2x.png"];
        }
        //Bottom moving to middle
        else if (sourceIndexPath.row == sectionRows - 1 && proposedDestinationIndexPath.row != 0 && proposedDestinationIndexPath.row != sectionRows - 1)
        {
            ((UIImageView *)cell.backgroundView).image = [UIImage imageNamed:@"tablemiddle@2x.png"];
        }
        //Bottom moving to bottom
        else if (sourceIndexPath.row == sectionRows - 1 && proposedDestinationIndexPath.row == sectionRows - 1)
        {
            ((UIImageView *)cell.backgroundView).image = [UIImage imageNamed:@"tablebottom@2x.png"];
        }
    }

【问题讨论】:

  • 您不应该在imageNamed 中使用@2x 后缀。它会在需要时自动添加。
  • 是否可以通过舍入表格视图的角而不是内部单元格来回避问题?它的外观和行为会有所不同,但它会是对您应用的任何样式规则的另一种解读吗?
  • tableview是圆角的,我只是使用自定义图形。

标签: iphone objective-c cocoa-touch uitableview


【解决方案1】:

好吧,您只需像在tableview:cellForRowAtIndexPath: 中所做的那样更改已更改的单元格的背景视图。

- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath {
   //The rest of your stuff you need to do

   for (NSIndexPath* visibleIndexPath in self.tableView.indexPathsForVisibleRows) {
       UITableViewCell* visibleCell [self.tableView cellForRowAtIndexPath:visibleIndexPath];
       if (visibleIndexPath.row == 0) ((UIImageView *)cell.backgroundView).image = [UIImage imageNamed:@"tabletop55.png"];
       else if (visibleIndexPath.row == [self tableView:tableView numberOfRowsInSection:visibleIndexPath.section) {
           ((UIImageView *)cell.backgroundView).image = [UIImage imageNamed:@"tablebottom55.png"];
       }
       else ((UIImageView *)cell.backgroundView).image = [UIImage imageNamed:@"tablemiddile55.png"];
   }
}

【讨论】:

  • 感谢您的帮助。用代码查看我更新的问题。我错过了任何案例吗?
  • 我认为您应该更改 cellForRowAtIndexPath 委托方法中的背景视图。然后在更改数据源并重新加载表格视图后,单元格将自动找到它的背景视图。
  • 您只更改源单元格,您需要更改每个可见单元格,因为它们可能全部更改。看看我的回答:self.tableView.indexPathsForVisibleRows 里面有一个 for 循环。
  • 感谢 gcamp。我将我的大 if 块卡在了那个 for 循环中,但得到了相同的结果。我做错了吗?
  • 再次编辑了我的答案。但是我认为您没有理解我编写的代码,您需要更改每个可见单元格的背景,无论 sourceIndexPath 和提出的DestinationIndexPath 是什么。我不知道您为什么要检查 if/else 子句中的内容,您需要查找visibleIndexPath
【解决方案2】:

由于for {},您发布的代码大部分是错误的。就目前而言,您可以执行类似“如果目标是这样而源是这样,则修改所有当前可见的单元格”之类的操作。但无论如何,这不是主要问题。

我必须说,在尝试回答这个问题之前,我已经使用tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath: 方法玩了很多时间。现在我更有信心写它了。

对于初学者,如果您不知道发生了什么,将此方法与tableView:cellForRowAtIndexPath: 结合使用并不是一个好的选择。简单地说,即使单元格为动画移动了,但在用户停止拖动单元格之前,这些变化不会真正影响 tableView。

例如,假设索引为 0 的单元格标题为 @"Hello",下一个单元格标题为 @"World",如果开始向下拖动第一个单元格,动画将移动单元格“Hello”向上一行,但为索引 0 处的行调用 tableView:cellForRowAtIndexPath 将始终返回“Hello”单元格。在 tableView 重新排序结束之前 tableView 不受影响,其他一切都只是养眼。

因此,要回答您的问题并即时交换图像(用户移动单元格时),您应该对第一行执行以下操作:

//Top moving to middle rows
if (sourceIndexPath.row == 0 && proposedDestinationIndexPath.row != 0)
{
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:sourceIndexPath.section]];
    ((UIImageView *)cell.backgroundView).image = [UIImage imageNamed:@"tablemiddle55"];
}

用户向下拖动第 0 行,它告诉第 1 行将其背景交换到顶部,因为他将成为新的顶部行。底排或中间排成为第一个必须考虑类似的情况。此外,在这种情况下,不需要带有可见单元格的 for {}

编辑:好的,我设法制作了所有案例,它到处都有一些奇怪的东西,但它大部分时间都有效。此处的代码只是将 detailLabel 更改为“First”/“Middle”/“Last”,但这应该很容易通过 Find&Replace 进行更改。

- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
{
    //NSLog(@"%d -> %d (proposed)", sourceIndexPath.row, proposedDestinationIndexPath.row);

    NSInteger lastRow = [arrayWithContent count]-1;

    // Adjust the row being moved
    if (proposedDestinationIndexPath.row == 0)
        [tableView cellForRowAtIndexPath:sourceIndexPath].detailTextLabel.text = @"First";
    else if (proposedDestinationIndexPath.row == lastRow)
        [tableView cellForRowAtIndexPath:sourceIndexPath].detailTextLabel.text = @"Last";
    else
        [tableView cellForRowAtIndexPath:sourceIndexPath].detailTextLabel.text = @"Middle";

    // Top -> Middle
    if (sourceIndexPath.row == 0 && proposedDestinationIndexPath.row == 1)
    {
        NSLog(@"Top -> Middle");
        [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]].detailTextLabel.text = @"First";
    }
    // Top -> Top (user is screwing around)
    else if (sourceIndexPath.row == 0 && proposedDestinationIndexPath.row == 0)
    {
        NSLog(@"Top -> Top");
        [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]].detailTextLabel.text = @"Middle";
    }
    // Middle -> Top
    else if (sourceIndexPath.row > 0 && proposedDestinationIndexPath.row == 0)
    {
        NSLog(@"Middle -> Top");
        [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]].detailTextLabel.text = @"Middle";
    }
    // Middle -> Bottom
    else if (sourceIndexPath.row < lastRow && proposedDestinationIndexPath.row == lastRow)
    {
        NSLog(@"Middle -> Bottom");
        [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:lastRow inSection:0]].detailTextLabel.text = @"Middle";
    }
    // Bottom -> Middle
    else if (sourceIndexPath.row == lastRow && proposedDestinationIndexPath.row == lastRow-1)
    {
        NSLog(@"Bottom -> Middle");
        [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:(lastRow-1) inSection:0]].detailTextLabel.text = @"Last";
    }
    // Bottom -> Bottom (user is screwing around, AGAIN)
    else if (sourceIndexPath.row == lastRow && proposedDestinationIndexPath.row == lastRow)
    {
        NSLog(@"Bottom -> Bottom");
        [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:(lastRow-1) inSection:0]].detailTextLabel.text = @"Middle";
    }
    // Middle -> Top -> Middle (ugh)
    else if (sourceIndexPath.row > 0 && sourceIndexPath.row < lastRow && proposedDestinationIndexPath.row == 1)
    {
        NSLog(@"Middle -> Top -> Middle");
        [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]].detailTextLabel.text = @"First";
    }
    // Middle -> Bottom -> Middle (ugh x2)
    else if (sourceIndexPath.row > 0 && sourceIndexPath.row < lastRow && proposedDestinationIndexPath.row == lastRow-1)
    {
        NSLog(@"Middle -> Bottom -> Middle");
        [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:lastRow inSection:0]].detailTextLabel.text = @"Last";
    }

    return proposedDestinationIndexPath;
}

【讨论】:

  • 没问题,我很好奇该怎么做,所以我只是把你的 if-else 带到了无穷大甚至更远的地方。我仍然认为有一个更好的方法,也许只是强制正确的单元格自动重新加载。另外,在我的测试中,我注意到一个需要滚动的大表格在拖动第一行并将其移动到最后一个位置(或相反)时可能会出现问题,我认为这是因为单元格一旦出来就如何被可重用排队可见区域。
【解决方案3】:

您应该在用户编辑数据数组时更新它。更新新数组后,您可以调用 reloadData 来刷新 UITableView。

【讨论】:

  • 这不起作用,因为当我尝试重新排列单元格时,表格视图将刷新,用户将无法将单元格移动到建议的目的地。
  • 那么你需要做的是在用户完成编辑后保存数据的新顺序。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多