如何动态计算自定义 expand/collapsable UITableViewCell 的高度
How to calculate the height of a custom expand/collapsable UITableViewCell dynamically
我有一个有趣的场景。我有一些在单独的 xib 文件中设计的自定义 UITableViewCells。其中之一有一个 UIImageView,它将加载大小不固定的图像,因此这意味着 UIImageView 的高度必须是灵活的。该单元格还有一个包含一些 UILabel 的 UIView,并且 UIView 的大小是恒定的,比如 100。我想在 didselectrowatindexpath
事件上展开和折叠单元格。要折叠单元格,我必须隐藏具有一些标签的 UIView。请在这方面指导我实现目标。
另外我的问题是 "How can I calculate the height of the row when cell is expanded and collapsed." 谢谢
编辑:这是我试过的。 . .但是失败了
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
static DynamicTableViewCell *cell = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
});
[self setUpCell:cell atIndexPath:indexPath];
CGFloat cellHeight = [self calculateHeightForConfiguredSizingCell:cell];
if(cellHeight >0) {
if(cell.isExpanded) {
return cellHeight;
}
else
{
return (cellHeight - detailViewHeight); // cell.detailView.frame.size.height = 100
}
}
else {
return cellHeight;
}
}
首先,由于性能原因,您不应该对您的单元格实例有任何引用。
其次,您应该使用模型以正确的方式构建您的细胞。提供的代码根本不显示模型存储的使用情况。
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
// Say you have a array of models NSArray<YourModel *> *dataSource;
YourModel *model = dataSource[indexPath.row]; // hope you have only one section.
}
第三,这是使用任何架构(如 MVVM 或 VIPER 或 MVC)的好方法,因为如果你没有这样的架构,你可能会在未来的产品支持中遇到问题。所以在 MVVM 的情况下,YourModel 就像 ViewModel。
要定义动态高度单元格的状态,请使用 属性 isExpanded
。这是一个很好的观点,但它应该在另一个地方定义 - YourModel
。如果你以正确的方式做到这一点,你就会知道没有细胞的细胞状态,实际上。
@interface YourModel ...
@property BOOL isExpanded;
@end
确保您在 didSelect 中正确更改了状态:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
YourModel *model = dataSource[indexPath.row];
model.isExpanded = !model.isExpanded; // inverse works like switch
// Then relayout your row
[tableView beginUpdates];
// I commented next line because it might not be needed for you
// Test it please
// [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
[tableView endUpdates];
}
所以回到 heightForRow:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
// Say you have a array of models NSArray<YourModel *> *dataSource;
YourModel *model = dataSource[indexPath.row]; // hope you have only one section.
// It's better to extract next code to function or any class, but not in your YourModel.
CGSize imageSize = [model.image doSizeCalulation]; // Use your algorithm to calculate image size
CGSize shortText = [model.shortText sizeWithAttributes:@[/* font attributes */]];
// If the cell is expanded then we should calculate height of text else height is zero.
CGSize fullText = model.isExpanded ? [model.fullText sizeWithAttributes:@[/* font attributes */]]; : 0;
// just sum
return imageSize.height + shortText.height + fullText.height;
}
实现此目的的另一种方法是使用 UITableViewAutomaticDimension
(只需 return 在 heightForRow 方法中)。在那种情况下,您应该正确设置约束,并在运行时根据 isExpanded 属性.
更改 fullText 高度约束的常量
我有一个有趣的场景。我有一些在单独的 xib 文件中设计的自定义 UITableViewCells。其中之一有一个 UIImageView,它将加载大小不固定的图像,因此这意味着 UIImageView 的高度必须是灵活的。该单元格还有一个包含一些 UILabel 的 UIView,并且 UIView 的大小是恒定的,比如 100。我想在 didselectrowatindexpath
事件上展开和折叠单元格。要折叠单元格,我必须隐藏具有一些标签的 UIView。请在这方面指导我实现目标。
另外我的问题是 "How can I calculate the height of the row when cell is expanded and collapsed." 谢谢
编辑:这是我试过的。 . .但是失败了
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
static DynamicTableViewCell *cell = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
});
[self setUpCell:cell atIndexPath:indexPath];
CGFloat cellHeight = [self calculateHeightForConfiguredSizingCell:cell];
if(cellHeight >0) {
if(cell.isExpanded) {
return cellHeight;
}
else
{
return (cellHeight - detailViewHeight); // cell.detailView.frame.size.height = 100
}
}
else {
return cellHeight;
}
}
首先,由于性能原因,您不应该对您的单元格实例有任何引用。
其次,您应该使用模型以正确的方式构建您的细胞。提供的代码根本不显示模型存储的使用情况。
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
// Say you have a array of models NSArray<YourModel *> *dataSource;
YourModel *model = dataSource[indexPath.row]; // hope you have only one section.
}
第三,这是使用任何架构(如 MVVM 或 VIPER 或 MVC)的好方法,因为如果你没有这样的架构,你可能会在未来的产品支持中遇到问题。所以在 MVVM 的情况下,YourModel 就像 ViewModel。
要定义动态高度单元格的状态,请使用 属性 isExpanded
。这是一个很好的观点,但它应该在另一个地方定义 - YourModel
。如果你以正确的方式做到这一点,你就会知道没有细胞的细胞状态,实际上。
@interface YourModel ...
@property BOOL isExpanded;
@end
确保您在 didSelect 中正确更改了状态:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
YourModel *model = dataSource[indexPath.row];
model.isExpanded = !model.isExpanded; // inverse works like switch
// Then relayout your row
[tableView beginUpdates];
// I commented next line because it might not be needed for you
// Test it please
// [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
[tableView endUpdates];
}
所以回到 heightForRow:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
// Say you have a array of models NSArray<YourModel *> *dataSource;
YourModel *model = dataSource[indexPath.row]; // hope you have only one section.
// It's better to extract next code to function or any class, but not in your YourModel.
CGSize imageSize = [model.image doSizeCalulation]; // Use your algorithm to calculate image size
CGSize shortText = [model.shortText sizeWithAttributes:@[/* font attributes */]];
// If the cell is expanded then we should calculate height of text else height is zero.
CGSize fullText = model.isExpanded ? [model.fullText sizeWithAttributes:@[/* font attributes */]]; : 0;
// just sum
return imageSize.height + shortText.height + fullText.height;
}
实现此目的的另一种方法是使用 UITableViewAutomaticDimension
(只需 return 在 heightForRow 方法中)。在那种情况下,您应该正确设置约束,并在运行时根据 isExpanded 属性.