UITableViewCell里面的UICollectionView – dynamic高度?
我们的一个应用程序屏幕要求我们在UITableViewCell
放置一个UICollectionView
。 这个UICollectionView
将有一个dynamic数量的项目,导致一个高度,必须dynamic计算。 但是,我遇到了问题,试图计算embedded的UICollectionView
的高度。
我们的总体UIViewController
是在Storyboard中创build的,并且使用了自动布局。 但是,我不知道如何根据UICollectionView
的高度来dynamic增加UITableViewCell
的高度。
任何人都可以提供一些关于如何完成这一点的提示或build议?
正确的答案是YES ,你可以做到这一点。
几周前我遇到了这个问题。 它实际上比你想象的要容易。 把你的单元格放入NIB(或故事板),并钉住它们让自动布局完成所有的工作
鉴于以下结构:
的TableView
TableViewCell
的CollectionView
CollectionViewCell
CollectionViewCell
CollectionViewCell
[…可变数量的单元格或不同的单元格大小]
解决scheme是告诉自动布局首先计算collectionViewCell大小,然后计算集合视图的contentSize,并将其用作单元的大小。 这是“做魔术”的UIView方法:
-(void)systemLayoutSizeFittingSize:(CGSize)targetSize withHorizontalFittingPriority:(UILayoutPriority)horizontalFittingPriority verticalFittingPriority:(UILayoutPriority)verticalFittingPriority
你必须在这里设置TableViewCell的大小,在你的情况下是CollectionView的contentSize。
CollectionViewCell
在CollectionViewCell中 ,每次更改模型时都必须告诉单元格布局(例如,您使用文本设置UILabel,然后单元格必须重新布局)。
- (void)bindWithModel:(id)model { // Do whatever you may need to bind with your data and // tell the collection view cell's contentView to resize [self.contentView setNeedsLayout]; } // Other stuff here...
TableViewCell
TableViewCell做的神奇。 它有一个出口到你的collectionView,使用UICollectionViewFlowLayout的 estimatedItemSize为collectionView单元格启用自动布局。
然后,诀窍是在systemLayoutSizeFittingSize方法中设置tableView单元格的大小 。 (注意:iOS8或更高版本)
注意:我尝试使用tableView的代表单元格的高度方法-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
。但是自动布局系统计算CollectionView的contentSize 已经太迟了,可能会发现错误resize的细胞
@implementation TableCell - (void)awakeFromNib { [super awakeFromNib]; UICollectionViewFlowLayout *flow = (UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout; // Configure the collectionView flow.minimumInteritemSpacing = ...; // This enables the magic of auto layout. // Setting estimatedItemSize different to CGSizeZero // on flow Layout enables auto layout for collectionView cells. // https://developer.apple.com/videos/play/wwdc2014-226/ flow.estimatedItemSize = CGSizeMake(1, 1); // Disable the scroll on your collection view // to avoid running into multiple scroll issues. [self.collectionView setScrollEnabled:NO]; } - (void)bindWithModel:(id)model { // Do your stuff here to configure the tableViewCell // Tell the cell to redraw its contentView [self.contentView layoutIfNeeded]; } // THIS IS THE MOST IMPORTANT METHOD // // This method tells the auto layout // You cannot calculate the collectionView content size in any other place, // because you run into race condition issues. // NOTE: Works for iOS 8 or later - (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize withHorizontalFittingPriority:(UILayoutPriority)horizontalFittingPriority verticalFittingPriority:(UILayoutPriority)verticalFittingPriority { // With autolayout enabled on collection view's cells we need to force a collection view relayout with the shown size (width) self.collectionView.frame = CGRectMake(0, 0, targetSize.width, MAXFLOAT); [self.collectionView layoutIfNeeded]; // If the cell's size has to be exactly the content // Size of the collection View, just return the // collectionViewLayout's collectionViewContentSize. return [self.collectionView.collectionViewLayout collectionViewContentSize]; } // Other stuff here... @end
TableViewController
请记住在TableViewController中为tableView单元格启用自动布局系统:
- (void)viewDidLoad { [super viewDidLoad]; // Enable automatic row auto layout calculations self.tableView.rowHeight = UITableViewAutomaticDimension; // Set the estimatedRowHeight to a non-0 value to enable auto layout. self.tableView.estimatedRowHeight = 10; }
信用: @ rbarbera帮助解决这个问题
我想,我的方式更简单,然后由@PabloRomeu提出。
第1步。从UICollectionView
创build出口到UITableViewCell subclass
,其中放置UICollectionView
。 让,它的名字将是collectionView
步骤2.在IB中添加UICollectionView
高度约束,并为UITableViewCell subclass
创build出口。 让,它的名字将是collectionViewHeight
。
第3步。在tableView:cellForRowAtIndexPath:
添加代码:
// deque a cell cell.frame = tableView.bounds; [cell layoutIfNeeded]; [cell.collectionView reloadData]; cell.collectionViewHeight.constant = cell.collectionView.collectionViewLayout.collectionViewContentSize.height;
表视图和集合视图都是UIScrollView
子类,因此不希望被embedded到另一个滚动视图中,因为他们试图计算内容大小,重用单元格等等。
我build议你只用一个集合视图来实现你的目的。
你可以把它分成几部分,把一些部分的布局视为表格视图,把其他部分视为一个集合视图。 毕竟没有什么你不能用集合视图来实现,你可以用表视图。
如果您的collections视图“零件”具有基本的网格布局,则还可以使用常规的表格单元格来处理它们。 如果你不需要iOS 5的支持,你应该更好地使用收集意见。
我会把一个静态方法集合视图类,将返回一个大小的基础上它将有的内容。 然后在heightForRowAtIndexPath
使用该方法返回适当的大小。
另外请注意,当你embedded这些types的viewControllers时,你会得到一些奇怪的行为。 我做了一次,有一些奇怪的记忆问题,我从来没有解决。
也许我的变体将是有用的; 我在过去的两个小时里已经决定了这个任务。 我不假装它是100%正确或最佳的,但我的技能非常小,我想听取专家的意见。 谢谢。 一个重要的注意事项:这适用于静态表 – 它是由我目前的工作指定的。 所以,我使用的是viewViewLilloutSubviews的tableView 。 还有一点点
private var iconsCellHeight: CGFloat = 500 func updateTable(table: UITableView, withDuration duration: NSTimeInterval) { UIView.animateWithDuration(duration, animations: { () -> Void in table.beginUpdates() table.endUpdates() }) } override func viewWillLayoutSubviews() { if let iconsCell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 1)) as? CategoryCardIconsCell { let collectionViewContentHeight = iconsCell.iconsCollectionView.contentSize.height if collectionViewContentHeight + 17 != iconsCellHeight { iconsCellHeight = collectionViewContentHeight + 17 updateTable(tableView, withDuration: 0.2) } } } override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { switch (indexPath.section, indexPath.row) { case ... case (1,0): return iconsCellHeight default: return tableView.rowHeight } }
- 我知道,collectionView位于第二部分的第一行;
- 让行的高度是17 p。 比内容高度大;
- iconsCellHeight是程序启动时的一个随机数(我知道,纵向格式必须是392,但并不重要)。 如果collectionView + 17的内容不等于这个数字,那么改变它的值。 下一次在这种情况下,条件为FALSE;
- 毕竟更新tableView。 在我的情况下,它的两个操作的组合(为了更好地更新扩展行);
- 当然,在heightForRowAtIndexPath中添加一行代码。
Pablo Romeu解决scheme的一个替代scheme是自定义UICollectionView,而不是在表格视图单元格中进行工作。
根本的问题是默认情况下,集合视图没有固有的大小,所以不能通知自动布局要使用的维度。 你可以通过创build一个返回有用的固有尺寸的自定义子类来弥补这一点。
创buildUICollectionView的子类并覆盖以下方法
override func intrinsicContentSize() -> CGSize { self.layoutIfNeeded() var size = super.contentSize if size.width == 0 || size.height == 0 { // return a default size size = CGSize(width: 600, height:44) } return size } override func reloadData() { super.reloadData() self.layoutIfNeeded() self.invalidateIntrinsicContentSize() }
(你也应该重写相关的方法:reloadSections,reloadItemsAtIndexPaths和reloadData()类似)
调用layoutIfNeeded将强制集合视图重新计算内容大小,然后将其用作新的内在大小。
此外,您需要显式处理表视图控制器中对视图大小的更改(例如,在设备旋转时)
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator) dispatch_async(dispatch_get_main_queue()) { self.tableView.reloadData() } }
1.创build虚拟细胞。
2.使用当前数据在UICollectionView的UICollectionViewLayout上使用collectionViewContentSize方法。
在你的UITableViewDelegate中:
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return ceil(itemCount/4.0f)*collectionViewCellHeight; }
用实际值replaceitemCount和CollectionViewCellHeight。 如果你有一个数组数组itemCount可能是:
self.items[indexPath.row].count
pipe他呢。
如果您的collectionViewCell具有规则的边界,则可以根据itemSize
, sectionInset
, minimumLineSpacing
, minimumInteritemSpacing
等属性计算集合的高度。