ios UICollectionView 自动调整高度

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20792299/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 22:53:50  来源:igfitidea点击:

UICollectionView autosize height

iosobjective-cuicollectionviewnslayoutconstraint

提问by Martijn de Milliano

How do I properly resize a UICollectionView so that it fully displays its contents? I have tried many things, including setting its frame, calling reloadDataand invalidating the layout:

如何正确调整 UICollectionView 的大小以使其完全显示其内容?我尝试了很多东西,包括设置它的框架,调用reloadData和使布局无效:

self.collectionView.contentSize = CGSizeMake(300, 2000);
self.collectionView.frame = CGRectMake(0, 0, 300, 2000);
[self.collectionView reloadData];
[self.collectionView.collectionViewLayout invalidateLayout];

but none of this has any effect. After pressing the button I still see the initial view, like this:

但这都没有任何影响。按下按钮后,我仍然看到初始视图,如下所示:

collection view only showing part of the content after frame resize

集合视图仅显示调整框架大小后的部分内容

I have a small demo program where I have a data source producing 100 elements. In Interface Builder I initially set the size of the UICollectionView to a small value so that not all elements fit, after that I press a button after which the code above is executed. I expect the UICollectionView to now show all elements, but it doesn't.

我有一个小型演示程序,其中有一个生成 100 个元素的数据源。在 Interface Builder 中,我最初将 UICollectionView 的大小设置为一个较小的值,以便并非所有元素都适合,之后我按下一个按钮,然后执行上面的代码。我希望 UICollectionView 现在显示所有元素,但事实并非如此。

EDIT:The demo program can be found at https://github.com/mjdemilliano/TestUICollectionView.

编辑:演示程序可以在https://github.com/mjdemilliano/TestUICollectionView找到。

EDIT2:I have observed that the frame update is lost at some point, because if I press the button again, the current frame is back to the old value. After adding some log statements in the button event handler, the log output is:

EDIT2:我观察到帧更新在某个时候丢失了,因为如果我再次按下按钮,当前帧将返回到旧值。在按钮事件处理程序中添加一些日志语句后,日志输出为:

before: frame = {{0, 58}, {320, 331}}, contentSize = {320, 1190}
update button pressed
after: frame = {{0, 0}, {300, 2000}}, contentSize = {300, 2000}
before: frame = {{0, 58}, {320, 331}}, contentSize = {320, 1190}
update button pressed
after: frame = {{0, 0}, {300, 2000}}, contentSize = {300, 2000}

I don't understand why the frame change is not kept, what is changing it.

我不明白为什么不保留框架变化,是什么改变了它。

At some point I will replace the hardcoded values by values obtained from the flow layout, but I wanted to rule that out and keep my example as simple as possible.

在某些时候,我将用从流布局中获得的值替换硬编码值,但我想排除这种情况并尽可能保持我的示例简单。

Context: What I want to do eventually is the following: I have a scrollable view with various controls like labels and images, and a collection view with dynamic content. I want to scroll all that, not just the collection view, therefore I am not using the collection view's own scrolling facilities, which work fine.

上下文:我最终想要做的是以下内容:我有一个带有各种控件(如标签和图像)的可滚动视图,以及一个带有动态内容的集合视图。我想滚动所有这些,而不仅仅是集合视图,因此我没有使用集合视图自己的滚动工具,它工作正常。

回答by Martijn de Milliano

I solved this eventually by fixing all Auto Layout issues, fixing the height of the collection view using a constraint. Then, whenever I know the content has changed I update the value of the constraint using the value collectionView.contentSize.height:

我最终通过修复所有自动布局问题解决了这个问题,使用约束来修复集合视图的高度。然后,每当我知道内容已更改时,我都会使用 value 更新约束的值collectionView.contentSize.height

self.verticalLayoutConstraint.constant = self.collectionView.contentSize.height;

Then the collection view is resized properly and it behaves nicely within the overall scrollview. I have updated the GitHub test project with my changes.

然后集合视图被正确调整大小,它在整个滚动视图中表现良好。我已经用我的更改更新了 GitHub 测试项目。

To me, doing this by updating the constraint manually instead of being able to tell iOS: "make the frame height of the collection view as large as needed" does not feel right to me, but it's the best I have come up with so far. Please post a better answer if you have one.

对我来说,通过手动更新约束而不是能够告诉 iOS:“根据需要使集合视图的框架高度尽可能大”来做到这一点对我来说并不合适,但这是我迄今为止想到的最好的. 如果您有更好的答案,请发布更好的答案。

回答by Trevor

It seems to work nicely with a custom UICollectionView class.

它似乎与自定义 UICollectionView 类配合得很好。

class AutoSizedCollectionView: UICollectionView {

    override var contentSize: CGSize {
        didSet {
            invalidateIntrinsicContentSize()
        }
    }

    override var intrinsicContentSize: CGSize {
        layoutIfNeeded()
        return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
    }
}

Set your custom class in the interface builder:

在界面构建器中设置您的自定义类:

enter image description here

在此处输入图片说明

This way you can also set your collection views intrinsic size to 'placeholder' in interface builder to avoid having to set a height constraint.

通过这种方式,您还可以在界面构建器中将集合视图的固有大小设置为“占位符”,以避免设置高度约束。

enter image description here

在此处输入图片说明

I hope this helps someone else.

我希望这对其他人有帮助。

回答by Craig Holliday

Here's my implementation in Swift 3:

这是我在 Swift 3 中的实现:

override func sizeThatFits(_ size: CGSize) -> CGSize {
    if (self.superview != nil) {
        self.superview?.layoutIfNeeded()
    }

    return collectionView.contentSize
}

回答by flame3

UICollectionViewFlowLayout *flowLayout;
flowLayout = [[UICollectionViewFlowLayout alloc]init];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionVertical];
[flowLayout setMinimumInteritemSpacing:0.0f];
[flowLayout setMinimumLineSpacing:0.0f];
[self.collectionView setPagingEnabled:NO];
[flowLayout setItemSize:CGSizeMake(322.0, 148.0)];  //important to leave no white space between the images
[self.collectionView setCollectionViewLayout:flowLayout];

I found that autolayout in the storyboard is not helping too much. A correct setting for the UICollectionViewFlowLayout for your collectionView is the real help. If you adjust item size with setItemSize, you may get the result you want.

我发现故事板中的自动布局并没有太大帮助。为您的 collectionView 正确设置 UICollectionViewFlowLayout 是真正的帮助。如果您使用 setItemSize 调整项目大小,您可能会得到您想要的结果。

回答by Nicolas Buquet

The simplest method I found is to override sizeThatFits:methods as is:

我发现的最简单的方法是按sizeThatFits:原样覆盖方法:

- (CGSize)sizeThatFits:(CGSize)size
{
    if( self.superview )
        [self.superview layoutIfNeeded]; // to force evaluate the real layout

    return self.collectionViewLayout.collectionViewContentSize;
}

回答by AmitP

Here's a way to bind the CollectionView's height via it's intrinsic size. I used it to properly size a CollectionView inside a TableView Cell (with dynamic cells height). and it works perfectly.

这是一种通过其固有大小绑定 CollectionView 高度的方法。我用它来正确调整 TableView 单元格内的 CollectionView 大小(具有动态单元格高度)。它完美无缺。

First, add this to your UICollectionView subclass:

首先,将其添加到您的 UICollectionView 子类中:

override var intrinsicContentSize: CGSize {
    get {
        return self.contentSize
    }
}

Then call layoutIfNeeded() after you reload data:

然后在重新加载数据后调用 layoutIfNeeded():

reloadData()
layoutIfNeeded()

回答by AshvinGudaliya

You can try out my custom AGCollectionViewclass

你可以试试我的自定义AGCollectionView课程

  • Assign a height constraint of collectionView using a storyboard or programmatically.
  • 使用故事板或以编程方式分配 collectionView 的高度约束。

- Assign this class to your UICollectionView.

- 将此课程分配给您的UICollectionView.

class AGCollectionView: UICollectionView {

    fileprivate var heightConstraint: NSLayoutConstraint!

    override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
        super.init(frame: frame, collectionViewLayout: layout)
        self.associateConstraints()
    }

    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.associateConstraints()
    }

    override open func layoutSubviews() {
        super.layoutSubviews()

        if self.heightConstraint != nil {
            self.heightConstraint.constant = floor(self.contentSize.height)
        }
        else{
            self.sizeToFit()
            print("Set a heightConstraint set size to fit content")
        }
    }

    func associateConstraints() {
        // iterate through height constraints and identify

        for constraint: NSLayoutConstraint in constraints {
            if constraint.firstAttribute == .height {
                if constraint.relation == .equal {
                    heightConstraint = constraint
                }
            }
        }
    }
}

回答by user2511630

For me it is even simpler I think

对我来说,我认为更简单

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath

{
//add following code line after adding cells, before Return
...........
.........
scrollView.contentSize = = collectionView.contentSize;

//now scrollView size is equal to collectionView size. No matter how small or big it is.

return cell;
}