6

我有一个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]);
            }
        }];
    }
}

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

更新:

使用:

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

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

跳转视频

更新 2:

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

更新 3:

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

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

4

3 回答 3

1

更新答案:

你做错了几件事可能导致(或至少有助于)跳跃:

  • 永远不要给layoutSubviews自己打电话。 这是系统调用来解决您的约束的方法。连续调用setNeedsLayout时自动触发。layoutIfNeeded

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

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

    [contentView layoutIfNeeded];
    

此外,您还需要注意一件事也会导致闪烁:

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

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


原答案:

我很确定

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

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

原因:

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

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

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

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

所以剩下的唯一问题是:

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

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

您可能不会(也不应该)一直调整所有可见单元格的大小。(这对用户来说会很混乱......)

于 2017-07-05T21:36:08.483 回答
0

我有类似的问题,我通过在 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]);
        }

    });

    }];
  }
 }
于 2017-07-04T08:03:35.650 回答
0

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

- (void)reloadRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths 
              withRowAnimation:(UITableViewRowAnimation)animation;
于 2017-07-04T06:19:00.607 回答