使用“自动布局”更新集合视图高度以适合表视图单元格中的所有单元格

时间:2015-04-13 03:24:54

标签: ios uitableview swift autolayout uicollectionview

我想利用iOS 8中新的动态UITableViewCell高度。我需要在UICollectionView内放置UITableViewCell。我想确保集合视图中的所有单元格都在屏幕上可见,因此表格单元格的高度应该增加以适合集合视图。我几乎有这个工作。我只是无法让表格单元格大小合适 - 它的长度太长或太短,并且在我与表格交互之前会看到一些布局问题(更多内容见下文)。

我已将集合视图的自动布局约束设置为表格的单元格contentView:前导,尾随,顶部和底部。然后我在集合视图上创建了一个高度约束,这样我就可以在计算适当的高度后动态更新它的constant以适应集合视图中的所有单元格(因为我认为没有办法自动执行此操作)。

以下是设置的其余部分。

viewDidLoad {
    self.tableView.rowHeight = UITableViewAutomaticDimension
    self.tableView.estimatedRowHeight = 44
}

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()

    let cellDimension = self.collectionView.frame.size.width / 7 //always 7 columns

    let flowLayout = self.collectionView.collectionViewLayout as! UICollectionViewFlowLayout
    flowLayout.itemSize = CGSizeMake(cellDimension, cellDimension)

    self.collectionViewHeightConstraint.constant = cellDimension * 4 //always 4 rows
}

我没有实施heightForRowAtIndexPath

此设置会导致冲突的垂直约束。我已经尝试降低约束的优先级并在一堆组合中改变关系,但没有一个导致所需的行为。如果我将高度约束的优先级降低到999,则表格视图单元格最初太高,但在我向上和向下滚动表格视图后,表格单元格高度更新为预期高度。对于其他一些组合,结果是表格单元格太短但整个集合视图渗出,表格单元格太短而集合视图被切断,或者表格单元格太高,基于什么优先级和我已经应用于约束的关系。此外,在视图设置为动画时,集合视图单元格不会以适当的大小显示(但它们会在动画完成时正确调整),或者如果我重新加载表格,则集合视图单元格的大小不正确,直到我滚动桌子。

如何解决这些外观问题以获取动态表格视图单元格高度,其中包含一个完全可见的集合视图,其中包含基于显示宽度的动态单元格大小?

3 个答案:

答案 0 :(得分:1)

从设置collectionView单元格和大小的代码中我可以理解,在我看来,你想要有方形集合单元格,并且有4行7个单元格,并且全部可见。

如果向单元格中的collectionView添加约束到所有4个边距(顶部,底部,左侧和右侧),然后将7:4的Aspect Ratio Constraint添加到collectionView,则tableview应该能够计算正确尺寸的自动细胞高度。

答案 1 :(得分:0)

以下是我如何处理这个问题,我认为可以在IB中完成所有工作。

首先,我为CV单元设置了最小尺寸,然后我将CV的拥抱优先级设置为尽可能紧密地拥抱其内容。这应该保证,除了所有外部影响之外,CV将尝试尽可能小的尺寸使其所有细胞都可见。

接下来,我将使用TBV单元格的内容视图和CV播放相同的游戏,也就是说,我将TBV单元格内容视图的拥抱优先级设置为尽可能紧密地拥抱CV。同样,这应该强调,忽略外部影响,TBV单元应保持其需要保持的最小尺寸,以便完整地显示CV。

答案 2 :(得分:0)

看看forkingdog如何在这里解决了tableview单元的动态高度相同的问题> https://github.com/forkingdog/UITableView-FDTemplateLayoutCell

你应该能够为uicollectionview切换出imageview。 enter image description here

在他的桌面视图中 - 而不是使用开箱即用的估计行高 - 你需要像

这样的东西
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return [tableView fd_heightForCellWithIdentifier:@"FDFeedCell" configuration:^(FDFeedCell *cell) {
        cell.entity = self.feedEntities[indexPath.row];
    }];
}



#import "UITableView+FDTemplateLayoutCell.h"
#import <objc/runtime.h>

@implementation UITableView (FDTemplateLayoutCell)

- (id)fd_templateCellForReuseIdentifier:(NSString *)identifier;
{
    NSAssert(identifier.length > 0, @"Expects a valid identifier - %@", identifier);

    NSMutableDictionary *templateCellsByIdentifiers = objc_getAssociatedObject(self, _cmd);
    if (!templateCellsByIdentifiers) {
        templateCellsByIdentifiers = @{}.mutableCopy;
        objc_setAssociatedObject(self, _cmd, templateCellsByIdentifiers, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }

    UITableViewCell *templateCell = templateCellsByIdentifiers[identifier];
    if (!templateCell) {
        templateCell = [self dequeueReusableCellWithIdentifier:identifier];
        templateCellsByIdentifiers[identifier] = templateCell;
    }

    return templateCell;
}

- (CGFloat)fd_heightForCellWithIdentifier:(NSString *)identifier configuration:(void (^)(id))configuration
{
    // Fetch a cached template cell for `identifier`.
    UITableViewCell *cell = [self fd_templateCellForReuseIdentifier:identifier];

    // Reset to initial height as first created, otherwise the cell's height wouldn't retract if it
    // had larger height before it gets reused.
    cell.contentView.bounds = CGRectMake(0, 0, CGRectGetWidth(self.frame), self.rowHeight);

    // Manually calls to ensure consistent behavior with actual cells (that are displayed on screen).
    [cell prepareForReuse];

    // Customize and provide content for our template cell.
    if (configuration) {
        configuration(cell);
    }

    // Add a hard width constraint to make dynamic content views (like labels) expand vertically instead
    // of growing horizontally, in a flow-layout manner.
    NSLayoutConstraint *tempWidthConstraint =
    [NSLayoutConstraint constraintWithItem:cell.contentView
                                 attribute:NSLayoutAttributeWidth
                                 relatedBy:NSLayoutRelationEqual
                                    toItem:nil
                                 attribute:NSLayoutAttributeNotAnAttribute
                                multiplier:1.0
                                  constant:CGRectGetWidth(self.frame)];
    [cell.contentView addConstraint:tempWidthConstraint];

    // Auto layout does its math
    CGSize fittingSize = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];

    [cell.contentView removeConstraint:tempWidthConstraint];

    // Add 1px extra space for separator line if needed, simulating default UITableViewCell.
    if (self.separatorStyle != UITableViewCellSeparatorStyleNone) {
        fittingSize.height += 1.0 / [UIScreen mainScreen].scale;
    }

    return fittingSize.height;
}

@end