9

我有一个项目(由其他人编写),其中有一个在表格视图中显示内容和文本的提要。每个帖子对应于表格视图中的一个部分,每个部分都有自己的行,对应于内容、文本、按钮等元素。

我需要在表格视图单元格内显示带有“更多”按钮的帖子标题的短标签,当点击更多按钮时,标签将扩展到标题适合的任何大小,所有这些都发生在表格视图单元格内。当点击更多按钮时,我将标签的numberOfLines属性更改为零,并且由于单元格具有自动高度,我只需要重新加载该特定标题单元格。numberOfLines(如果我在显示单元格之前首先设置为 0,则单元格会以扩展大小正确显示。)

我试过了:

[tableView beginUpdates]; tableView endUpdates];

我尝试了各种动画选项:

[tableView reloadRowsAtIndexPaths:@[myPath] withRowAnimation:UITableViewRowAnimation(Bottom,Top,None etc)];

我试过了:

[tableView reloadSections:[NSIndexSet indexSetWithIndex:myPath.section] withRowAnimation:UITableViewRowAnimation(Top,Bottom,None etc)];

但是它们都产生了相同的结果:整个表格视图布局变得混乱:它跳转到另一个单元格,一些视图变为空白,单元格相互重叠,单元格内的视频停止播放,并且标签不展开(但内部刷新本身,例如带有一行的简短预览 txt 从顶部/底部等动画,但不展开)。

什么可能导致整个表格视图混乱,以及如何正确地重新加载一个单元格和扩展动画,而不会弄乱整个布局?我已经看到了很多关于此的问题和答案,但他们都推荐了我已经尝试过并在上面解释过的选项。

我的应用面向 iOS 8.0+

更新:这是相关代码(删除了一些与布局无关的内部工作部分):

MyCell *cell = (MyCell *)[tableView dequeueReusableCellWithIdentifier: MyCellIdentifier forIndexPath:indexPath];
cell.delegate = self;
cell.indexPathToReloadOnAnimation = indexPath;
cell.shouldShortenCaption = YES;

id post = self.posts[indexPath.section] ;
[cell setPost:post];

return cell;

在里面setPost:

if(self.shouldShortenCaption){
    captionLabel.numberOfLines = 2;
}else{
    captionLabel.numberOfLines = 0;
}
NSString *text = [some calculated (deterministic) text from post object];

按钮操作很简单:

self.shouldShortenCaption = NO;
[one of the reload codes that I've written above in the question]

更新2:这里有一些关于这个问题的更多方法:

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
    if (section < self.posts.count) {
        return 59;
    }else
        return 0;
}

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    if (section < self.posts.count) {
        MyFeedHeader *header = [tableView dequeueReusableCellWithIdentifier:MyFeedHeaderIdentifier];
        header.delegate = self;
        [header setPostIndex:section];
        [header setPost:self.posts[section]] ;

        return header;
    }
    else
        return nil;
}

Header的setPost:方法基本上是将相关文本设置为标签(与标题无关,它们是完全不同的单元格。有问题的单元格不是标题单元格)。该表没有任何页脚方法。关于高度的唯一方法是上面的方法。

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (section >= self.posts.count) {
        return 1;
    }
    id post = self.posts[section];
    [calculate number of rows, which is deterministic]
    return [number of rows];
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    BOOL hasCursor = self.cursor && self.hasMore ? 1 : 0;
    return self.posts.count + hasCursor;
}

(post count 和 cursor 和 hasMore 也是确定性的)。

更新3:我问了一个问题(虽然有类似的问题,但不是重复的)并得到了一个有用的答案来解决我的问题。投反对票的人能否详细说明他们投反对票的原因?

4

1 回答 1

21

这是一个例子:https ://github.com/DonMag/DynamicCellHeight

表 B 是完成“更多/更少”的一种方式(表 A 是我玩过的另一种布局)。它使用[tableView beginUpdates]; tableView endUpdates];触发表格重新布局的方法。

关键是正确设置所有约束,因此自动布局引擎可以满足您的期望。

这个例子是用 Swift 编写的,但应该很容易翻译回 Obj-C(我想我是先在 Obj-C 中完成的)。

在此处输入图像描述

编辑:一些附加说明...

这是使用动态高度表视图单元格的非常标准的方法。元素之间的垂直间距约束有效地“推出”了单元格的边界。此处的点击在numberOfLines2 和 0 之间切换标签的属性(零表示必要的行数)。beginUpdates对表格视图的/顺序调用endUpdates告诉自动布局引擎重新计算行高,而无需重新加载数据。

对于这个例子,我确实使用了一些“技巧”来获得平滑的展开/折叠效果......您在此处看到的多行标签包含在UIView(with clipsToBoundstrue) 中。还有一个控制高度的第二个重复的多行标签(alpha 0,因此不可见)。我发现numberOfLines将可见标签上的“捕捉”类型更改为 2 行,然后发生大小更改动画......导致文本“跳来跳去”。

只是为了它,为了比较,我将“不太好”的版本添加到我的 GitHub 存储库中。

在此处输入图像描述

于 2017-03-29T14:49:09.650 回答