用像Instagram这样的“更多”button展开UITableView中的UILabel

我有一个项目(这是由其他人写的),其中有一个饲料的内容和文本显示在一个表视图。 每个post对应于表格视图中的一个部分,每个部分都有自己的行,对应于内容,文本,像button等元素。

我需要在表格视图单元格内使用“更多”button来显示标题的简短标签,当点击更多button时,标签将展开为标题适合的任何大小,全部发生在表格视图单元格内。 当点击更多button时,我将标签的numberOfLines属性更改为零,并且由于单元格具有自动高度,所有我需要的是重新加载该特定的标题单元格。 (如果在显示单元格之前将numberOfLines设置为0,则单元格会正确显示扩展的大小。)

我试过了:

[tableView beginUpdates]; tableView endUpdates];

我已经尝试过各种animation选项:

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

我试过了:

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

但他们都产生了相同的结果:整个表视图布局变得混乱:它跳转到另一个单元格,一些视图变成空白,单元格重叠,单元格内的video停止播放,标签不扩展(但刷新内部本身,如简短的预览TXT一行从顶部/底部animation,但不扩大)。

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

我的应用程序的目标是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]; 

button操作很简单:

 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; } 

标题的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数和游标和hasMore也是确定性的)。

更新3:我问了一个问题(这不是重复的,即使有类似的问题),并得到了一个有用的答案,解决了我的问题。 请问下面的人请详细说明他们低估的原因吗?

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

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

关键是要正确设置所有的约束,所以自动布局引擎可以做到你所期望的。

这个例子是在Swift中,但是应该很容易地转换回Obj-C(我想我是先在Obj-C中做的)。

在这里输入图像说明

编辑:一些额外的笔记…

这是使用dynamic高度表格视图单元的一个非常标准的方法。 元素之间的垂直间隔约束有效地“推出”了单元格的边界。 点击此处切换2和0之间的标签的numberOfLines属性(零意味着根据需要多行)。 对表视图上的beginUpdates / endUpdates进行的顺序调用将通知自动布局引擎重新计算行高, 无需重新加载数据。

对于这个例子,我确实使用了一些“欺骗”来获得平滑的展开/折叠效果……你在这里看到的多行标签包含在一个UIView (with clipsToBounds true)中。 有第二个,重复的多行标签(alpha 0,所以它是不可见的),正在控制的高度。 我发现,将可见标签上的numberOfLines改为“snapped”为2行,然后发生尺寸改变animation…导致文本“跳来跳去”。

只是为了这个,为了比较起见,我在GitHub上添加了“不太好”的版本。

在这里输入图像说明