【问题标题】:Update UITableView height when tweet loaded加载推文时更新 UITableView 高度
【发布时间】:2017-11-27 21:01:08
【问题描述】:

我有一个UITableViewCell,其中包含一个带有自动布局的TWTRTweetView。我正在加载这样的推文:

- (void)loadTweetWithId:(NSString *)tweetId {

    if (mTweetId == nil || ![mTweetId isEqualToString:tweetId]) {
        mTweetId = tweetId;
        [[[TWTRAPIClient alloc] init] loadTweetWithID:tweetId completion:^(TWTRTweet *tweet, NSError *error) {
            if (tweet) {
                NSLog(@"Tweet loaded!");
                [mTweetView configureWithTweet:tweet];
                [mTweetView setShowActionButtons:YES];
                //[mTweetView setDelegate:self];
                [mTweetView setPresenterViewController:self.viewController];
                [mTweetView setNeedsLayout];
                [mTweetView layoutIfNeeded];
                [mTweetView layoutSubviews];
                hc.constant = mTweetView.frame.size.height;
                [self updateConstraints];
                [self layoutIfNeeded];
                [self layoutSubviews];
                [self.tableView setNeedsLayout];
                [self.tableView layoutIfNeeded];
                [self.tableView layoutSubviews];
            } else {
                NSLog(@"Tweet load error: %@", [error localizedDescription]);
            }
        }];
    }
}

当推文加载单元格不会调整大小时,除非我将其滚动并向后滚动。正如您在代码 sn-p 中看到的那样,我尝试了几种方法。但这些都不是。我的表格视图使用全自动布局方法,它没有为行函数实现单元格高度。我该如何解决这个问题?

更新:

使用:

[self.tableView beginUpdates];
[self.tableView endUpdates];

是不可能的,因为当我这样做时,所有单元格都被重绘并且发生了非常大的跳跃,这是不可接受的。此外,我已经确认推文完成块在主线程中运行。

更新 2:

我还尝试使用推文 ID 缓存推文视图,并为相关索引路径重新加载单元格,并为推文 ID 提供相同的推文视图。单元格高度已更正,但在向外/向内滚动之前它不会变得可见。

更新 3:

我在单元格的 xib 中为推文视图提供了约束,并且高度约束已连接。所以这不是主线程问题。我还提到在索引处重新加载特定单元格不起作用。

在使用其他解决方案时,我看到了一些使用 TWTRTweetTableViewCell 的示例 TwitterKit 代码,但正在预加载推文以配置单元格。所以我也做了同样的事情。这当然是一种解决方法。

【问题讨论】:

  • 当使用自动调整大小的表格视图时,我有时会很幸运地一个接一个地调用 [self.tableView beginUpdates];[self.tableView endUpdates]; - 你试过了吗?
  • 这看起来像是一大堆额外的/不需要的“布局”东西——你是不是添加了越来越多的东西?无论如何,从您发布的代码中很难判断,但我猜您的 completion 块正在后台线程上运行。所有 UI 更新都必须在主线程上完成。搜索 objective c uitableview update on main thread 以获取示例。
  • 迟到了,抱歉。是否检查了 mTweetView.frame.size.height 在完成回调中是否有更新的值?
  • 推文加载完成后,在heightForRowAtIndexPath 定义单元格高度后调用tableViewreloadData 函数。
  • @ayazmon reloadData 不是一个选项。

标签: ios uitableview twitter twitterkit


【解决方案1】:

更新答案:

你做错了一些可能导致(或至少促成)跳跃的事情:

  • 切勿自己致电layoutSubviews 这是系统调用来解决您的约束的方法。连续调用setNeedsLayoutlayoutIfNeeded时自动触发。

  • 同样适用于updateConstraints它在布局过程中被系统调用。您可以通过随后调用setNeedsUpdateContraintsupdateConstraintsIfNeeded 来手动触发它。此外,仅当您在自定义视图(或单元格)中实际实现(覆盖)该方法时,它才会生效。

  • 当您在视图上调用layoutIfNeeded 时,它会布置其子视图。因此,当您更改约束mTweetView 的约束常量时,它可能不会产生任何影响(除非视图层次结构在触发布局传递期间无效)。您需要在mTweetView 的超级视图上调用layoutIfNeeded,这是单元格的内容视图(从您添加到帖子中的屏幕截图来看):

    [contentView layoutIfNeeded];
    

此外,您还需要注意一件可能导致闪烁的事情:

  • 正在回收表格视图中的单元格。每次重复使用一个单元格时,您都会加载一条新推文。我猜它来自异步网络请求?如果是这样,当您快速滚动时,您为该单元格实例加载的第一条推文的完成块可能会返回您为该(回收的)单元格加载的第二条推文的完成块之后或者你的互联网连接真的很慢。确保在重复使用单元格时取消请求或以某种方式使其无效(prepareForReuse 方法)。

请确保您已解决所有这些问题,并查看动画现在是否按预期工作。 (我在下面的原始答案仍然有效。)


原答案:

我很确定

[self.tableView beginUpdates];
[self.tableView endUpdates];

唯一的方法让单元格在显示时自动调整大小。

原因:

出于历史性能原因,UITableView 始终适用于固定高度的单元格(内部)。即使通过设置estimatedRowHeight 等来使用自定大小的单元格,表格视图也会在单元格出列时计算单元格的高度,即之前它出现在屏幕上。然后,它会为单元格添加一些内部约束,以使其固定宽度固定高度恰好匹配自动布局计算的大小。

这些内部约束仅在需要时更新,即在重新加载行时。现在,当您在单元格内添加任何约束时,您将“对抗”这些具有 required 优先级(又名 1000)的内部约束。换句话说:没有办法赢!

更新这些内部(固定)单元格约束的唯一方法是告诉表视图它应该这样做。据我所知,唯一的公共(记录)API 是

- (void)beginUpdates;
- (void)endUpdates;

所以剩下的唯一问题是:

为什么这种方法不适合您?

我认为在调整单元格大小后重新绘制单元格是合法的。当您展开单元格以显示比之前更长的推文时,无论如何,单元格需要重新绘制!

您可能不会(也不应该)一直调整所有可见单元格的大小。 (这会让用户感到非常困惑......)

【讨论】:

  • 当我使用 beginUpdates - endUpdates 大跳跃发生。
  • 虽然这个答案可能无法解决您的问题,但我相信它仍然可以正确回答您的问题“为什么自动布局不能正确更新单元格内容”。
  • 您必须接受这样一个事实:beginUpdates + endUpdates 方法是在单元格可见时实现单元格高度调整的唯一记录方法。我已经彻底测试过了,效果很好。因此,如果您已经解决了上述所有问题,那么错误就在您的代码中的其他地方。
  • 我没有询问记录的方式是什么。我已经说过我需要更新它而不跳转。如您所见,我已经尝试过您的建议,但不适合我的情况。
  • 顺便说一句:您可能还想检查您为 hc 常量设置的值是否正确(即,此时单元格的布局是否正确)。一般来说,我完全不鼓励对内容视图的高度使用这样的约束。如果mTweetView 完全受约束并且可以自行布局,您可以简单地将其四边约束到contentView 的边缘,您将获得自动调整单元格大小。如果不是,您的单元格布局不正确。
【解决方案2】:

在您加载推文后,尝试重新加载该特定单元格,

- (void)reloadRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths 
              withRowAnimation:(UITableViewRowAnimation)animation;

【讨论】:

  • 请阅读我的更新。我已经说过重新加载单元格不起作用。
【解决方案3】:

我遇到了类似的问题,我通过在 dispatch_async 中添加我的所有代码来解决这个问题,以确保它在主线程上运行。

 dispatch_async(dispatch_get_main_queue(), ^{ 
      /*CODE HERE*/
 });

所以你的代码应该是这样的:

- (void)loadTweetWithId:(NSString *)tweetId {

  if (mTweetId == nil || ![mTweetId isEqualToString:tweetId]) {
      mTweetId = tweetId;
    [[[TWTRAPIClient alloc] init] loadTweetWithID:tweetId completion:^(TWTRTweet *tweet, NSError *error) {

        dispatch_async(dispatch_get_main_queue(), ^{ 

        if (tweet) {
            NSLog(@"Tweet loaded!");
            [mTweetView configureWithTweet:tweet];
            [mTweetView setShowActionButtons:YES];
            //[mTweetView setDelegate:self];
            [mTweetView setPresenterViewController:self.viewController];
            [mTweetView setNeedsLayout];
            [mTweetView layoutIfNeeded];
            [mTweetView layoutSubviews];
            hc.constant = mTweetView.frame.size.height;
            [self updateConstraints];
            [self layoutIfNeeded];
            [self layoutSubviews];
            [self.tableView setNeedsLayout];
            [self.tableView layoutIfNeeded];
            [self.tableView layoutSubviews];
        } else {
            NSLog(@"Tweet load error: %@", [error localizedDescription]);
        }

    });

    }];
  }
 }

【讨论】:

  • 我已经告诉过完成块在主队列中。但是为了公平起见,在否决您之前,我已经测试了您的建议,但没有奏效。
猜你喜欢
  • 1970-01-01
  • 2016-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多