简体   繁体   English

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

[英]Update collection view height to fit all cells within a table view cell using Auto Layout

I would like to take advantage of the dynamic UITableViewCell height new in iOS 8. I need to place a UICollectionView within a UITableViewCell . 我想利用iOS 8中动态的UITableViewCell高度。我需要在UITableViewCell放置一个UICollectionView I want to ensure all of the cells in the collection view are visible on screen, so the table cell should increase in height to fit the collection view. 我想确保集合视图中的所有单元格都在屏幕上可见,因此表格单元格的高度应该增加以适合集合视图。 I almost have this working. 我几乎有这个工作。 I just haven't been able to get the table cell to be the right size - it's either too long or too short in height, and some layout issues are visible until I interact with the table (more on that below). 我只是无法使表格单元格大小合适 - 它的长度太长或太短,并且在我与表格交互之前可以看到一些布局问题(下面有更多内容)。

I've set up auto layout constraints for the collection view to the table's cell's contentView : leading, trailing, top, and bottom. 我已经将集合视图的自动布局约束设置为表格单元格的contentView :leading,trailing,top和bottom。 I then created a height constraint on the collection view so I can update its constant on the fly after calculating the appropriate height to fit all cells in the collection view (because I don't think there's a way to do that automatically). 然后我在集合视图上创建了一个高度约束,这样我就可以在计算适当的高度后动态更新它的constant ,以适应集合视图中的所有单元格(因为我认为没有办法自动执行此操作)。

Here is the rest of the setup. 这是设置的其余部分。

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
}

I have not implemented heightForRowAtIndexPath . 我还没有实现heightForRowAtIndexPath

This setup results in conflicting vertical constraints. 此设置会导致冲突的垂直约束。 I've tried reducing the priority of the constraints and changing the relation in a bunch of combinations, but none resulted in the desired behavior. 我已经尝试降低约束的优先级并在一堆组合中改变关系,但没有一个导致所需的行为。 If I reduce the priority of the height constraint to 999, the table view cell is too tall at first, but after I scroll up and down the table view the table cell height updates to the expected height. 如果我将高度约束的优先级降低到999,则表格视图单元格最初太高,但在我向上和向下滚动表格视图后,表格单元格高度更新为预期高度。 With some other combinations, the result is either the table cell is too short yet the full collection view bleeds out, the table cell is too short and the collection view is cut off, or the table cell is too tall, based on what priority and relations I've applied to the constraints. 对于其他一些组合,结果是表格单元格太短但整个集合视图渗出,表格单元格太短而集合视图被切断,或者表格单元格太高,基于什么优先级和我已经应用于约束的关系。 Additionally, the collection view cells are not displayed at the proper size while the view is animating in (but they're properly adjusted by the time animation finishes), or if I reload the table the collection view cells are the incorrect size until I scroll the table. 此外,在视图设置为动画时,集合视图单元格不会以适当的大小显示(但它们会在动画完成时正确调整),或者如果我重新加载表格,则集合视图单元格的大小不正确,直到我滚动桌子。

How can I resolve these appearance issues to obtain a dynamic table view cell height that contains a fully visible collection view featuring dynamic cell size based on the display's width? 如何解决这些外观问题以获得动态表格视图单元格高度,其中包含基于显示宽度的动态单元格大小的完全可见的集合视图?

From what i can understand from you code in setting up the collectionView cells and size, it seems to me that you want to have square collection cells, and have 4 rows of 7 cells and all fully visible. 从我可以理解你的代码来设置collectionView单元格和大小,在我看来,你想要有方形的收集单元格,并有4行7个单元格,所有完全可见。

If you add constraints to the collectionView that is in the cell to all 4 margins(top, bottom, left and right) and then add an Aspect Ratio Constraint of 7:4 to the collectionView, the tableview should be able to calculate cell height automatically for you at the right size. 如果向单元格中的collectionView添加约束到所有4个边距(顶部,底部,左侧和右侧),然后将7:4的纵横比约束添加到collectionView,则tableview应该能够自动计算单元格高度为您提供合适的尺寸。

Here's how I'd approach this, and I think it can be done all in IB. 这是我如何处理这个问题,我认为它可以在IB中完成。

First, I'd set minimum sizes for the CV cells then I'd set the hugging priority of the CV to hug its contents as tightly as possible. 首先,我为CV单元设置了最小尺寸,然后我将CV的拥抱优先级设置为尽可能紧紧地拥抱其内容。 That should guarantee that, all external influences apart, the CV will try to have the smallest possible size that makes all of its cells visible. 这应该保证,除了所有外部影响之外,CV将尝试具有使其所有细胞可见的最小可能尺寸。

Next, I'd play the same game with the TBV cell's content view and the CV, that is, I'd set the hugging priority of the TBV cell's content view to hug the CV as tightly as possible. 接下来,我将使用TBV单元格的内容视图和CV播放相同的游戏,也就是说,我将TBV单元格内容视图的拥抱优先级设置为尽可能紧密地拥抱CV。 Again, this should enforce that, external influences neglected, the TBV cell should keep the smallest size it needs to keep in order to display the CV in full. 同样,这应该强调,忽略外部影响,TBV单元应保持其需要保持的最小尺寸,以便完整地显示CV。

Have a look at how forkingdog has solved the same problem of dynamic heights of tableview cells here > https://github.com/forkingdog/UITableView-FDTemplateLayoutCell 看看forkingdog如何在这里解决了tableview单元动态高度的相同问题> https://github.com/forkingdog/UITableView-FDTemplateLayoutCell

You should be able to switch out the imageview for uicollectionview. 你应该能够为uicollectionview切换出imageview。 在此输入图像描述

In his tableview - rather than using the out of the box estimated row height - you'll need something like 在他的桌面视图中 - 而不是使用开箱即用的估计行高 - 你需要类似的东西

- (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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM