【问题标题】:Calling reloadRowsAtIndexPaths removes tableView contentOffset调用 reloadRowsAtIndexPaths 删除 tableView contentOffset
【发布时间】:2011-09-01 00:07:54
【问题描述】:

每当我打电话时

reloadRowsAtIndexPaths

我的 UITableView contentOffset 被删除了,是否有一个委托方法可以用来捕获表格视图更新并再次设置偏移量,以便它保持原位并且不会在视图中设置动画,或者只是阻止它这样做?

我在 viewDidLoad 中设置 contentOffest:

self.tableView.contentOffset = CGPointMake(0, 43);

这是一个示例用法:

[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:[params valueForKey:@"index"], nil] withRowAnimation:UITableViewRowAnimationFade];

这会删除 contentOffset 并将其动画化到视图中,这是我不想要的。

更具体地说,当正在重新加载的行位于 indexPath.section 0 和 indexPath.row 0(即顶行)时,这似乎会发生。


更多信息

我在异步请求从服务器获取图像后调用 reloadRowsAtIndexPaths。它基本上是这样工作的:

  • cellForRowAtIndexPath 被调用,检查磁盘上是否存在拇指文件,如果文件不存在,则在其位置加载占位符,并在后台线程中启动异步请求以获取图像。
  • 图像下载完成后,我调用reloadRowsAtIndexPaths 以获取正确的单元格,以便正确的图像淡入以代替占位符图像。
  • 单元格的数量可能会有所不同,因为在 cellForRowAtIndexPath 中调用了请求,以便图像在单元格加载时加载

cellForRowAtIndexPath 文件检查

paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
path = [[paths objectAtIndex:0] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@_small.gif",[[listItems objectAtIndex:indexPath.row] valueForKey:@"slug"]]];

    if([[NSFileManager defaultManager] fileExistsAtPath:path]){

        listCell.imageView.image = [UIImage imageWithData:[NSData dataWithContentsOfFile:path]];

    } else {

        listCell.imageView.image = [UIImage imageNamed:@"small_placeholder.gif"];

        NSMutableDictionary *params = [[NSMutableDictionary alloc] initWithObjectsAndKeys:[[[listItems objectAtIndex:indexPath.row] valueForKey:@"image"] valueForKey:@"small"],@"image",[NSString stringWithFormat:@"%@_small.gif",[[listItems objectAtIndex:indexPath.row] valueForKey:@"slug"]], @"name",indexPath,@"index",@"listFileComplete",@"notification",nil];

        [NSThread detachNewThreadSelector:@selector(loadImages:) toTarget:self withObject:params];

        [params release];

    }

文件下载通知:

-(void)fileComplete:(NSNotification *)notification {

    [self performSelectorOnMainThread:@selector(reloadMainThread:) withObject:[notification userInfo] waitUntilDone:NO];
}

单元格重新加载(我对部分进行了硬编码,因为一个奇怪的部分编号被传递的错误很少导致崩溃:

-(void)reloadMainThread:(NSDictionary *)params {

    NSIndexPath *index;

    switch ([[params valueForKey:@"index"] section]) {
        case 0:
            index = [NSIndexPath indexPathForRow:[[params valueForKey:@"index"] row] inSection:0];
            [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:[params valueForKey:@"index"], nil] withRowAnimation:UITableViewRowAnimationNone];
            break;
        default:
            index = [NSIndexPath indexPathForRow:[[params valueForKey:@"index"] row] inSection:2];
            [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:index,nil] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }

}

【问题讨论】:

    标签: iphone objective-c uitableview


    【解决方案1】:

    编辑:我最初的答案可能没有集中在核心问题上

    您是否在调用reloadRows... 之前更改了行数? reloadRows... 专门用于动画值更改,因此您的代码应如下所示:

    UICell *cell = [self cellForRowAtIndexPath:indexPath];
    cell.label.text = @"Something new";
    [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]];
    

    这或多或少是你的样子,但 tableview 忘记了它在哪里?


    之前的讨论

    您不会在重新加载时调用 -beginUpdates-endUpdates。你调用-beginUpdates-endUpdates 围绕你对支持数据的相关修改,在此期间你应该调用-insertRowsAtIndexPaths:withRowAnimation: 及其亲属。如果调用更新例程,则不需要调用重新加载例程。在更新过程中重新加载是未定义的行为。

    有关何时使用-beginUpdates 的详细信息,请参阅Batch Insertion, Deletion, and Reloading of Rows and Sections

    【讨论】:

    • 感谢您的提示,我想我的问题是 reloadRowsAtIndexPaths 而不是 beginUpdates,因为删除了 begin/end 后问题仍然存在
    • 已编辑;我可能误解了其余代码的样子。
    • 我已经更新了我的问题,以便更深入地了解我的问题
    • 您的解决方案稍有变化就可以解决问题,而不是调用 reloadRowsAtIndexPaths 虽然我只是调用了 setNeedsDisplay
    【解决方案2】:

    您是否尝试过以下方法:

    CGPoint offset = [self.tableView contentOffset];
    CGSize size = [self.tableView contentSize];
    
    CGFloat percentScrolled = offset.y / size.height;
    
    // call reloadRowsAtIndexPaths, inserts, deletes etc.
    // ...
    
    CGSize newSize = [self.tableView contentSize];
    CGSize newOffset = CGPointMake(0, newSize.height * percentScrolled);
    
    [self.tableView setContentOffset:newOffset animated:NO];
    

    这似乎有点太琐碎了,不确定它是否会起作用,但值得一试。

    【讨论】:

    • 如果它不停止tableView的滚动效果会很好
    【解决方案3】:

    替换

    [_tableView reloadData];
    

    [_tableView  reloadRowsAtIndexPaths:...withRowAnimation:...];
    

    会很好的。

    【讨论】:

      【解决方案4】:

      听起来您遇到了这个问题,因为行高估计不正确。因为(出于某种神秘原因)表格视图会在使用估计的行高重新加载某些单元格后确定新的偏移量,您希望确保 tableView:estimatedHeightForRowAtIndexPath 为已渲染的单元格返回正确的数据。为此,您可以在字典中缓存看到的行高:

      override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
          heightForIndexPath[indexPath] = cell.frame.height
      }
      

      然后使用此正确数据或您对尚未加载的单元格的估计:

      override func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
          return heightForIndexPath[indexPath] ?? averageRowHeight
      }
      

      (非常感谢 eyuelt 洞察到使用估计的行高来确定新的偏移量。)

      【讨论】:

      • 哇哇哇!最佳答案,我希望我能投票 10 倍!!!非常感谢,丹尼尔,我希望将来你会发现我的答案之一和我现在发现的一样有用
      • Wowwwwwwwwwwwwwww....我到处寻找解决我的重叠单元格问题的方法,这个答案似乎已经解决了。非常爱,丹尼尔!
      【解决方案5】:

      我用这个:

      -(void)keepTableviewContentOffSetCell:(cellClass *)cell{
          CGRect rect = cell.frame;
          self.tableView.estimatedRowHeight = rect.size.height ;
      }
      

      您可以在重新加载单元格之前使用它。重新加载单元格时表格视图不会滚动。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-07-07
        • 1970-01-01
        • 2015-07-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-20
        相关资源
        最近更新 更多