UICollectionView自动调整高度

时间:2013-12-26 22:50:21

标签: ios objective-c uicollectionview nslayoutconstraint

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

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

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

collection view only showing part of the content after frame resize

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

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

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}

我不明白为什么不保留帧更改,更改它的是什么。

在某些时候,我会用流布局中获得的值替换硬编码值,但我想排除这一点,并尽可能保持我的示例。

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

8 个答案:

答案 0 :(得分:103)

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

更新约束的值
self.verticalLayoutConstraint.constant = self.collectionView.contentSize.height;

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

对我来说,通过手动更新约束而不是告诉iOS来做到这一点:“使集合视图的框架高度尽可能大”对我来说感觉不对,但它是最好的我到目前为止已经提出来了。如果你有答案,请发一个更好的答案。

答案 1 :(得分:2)

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];

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

答案 2 :(得分:2)

这是一种通过其内在大小绑定CollectionView高度的方法。 我用它在TableView Cell中正确调整CollectionView的大小(动态单元格高度)。而且效果很好。

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

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

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

reloadData()
layoutIfNeeded()

答案 3 :(得分:1)

我找到的最简单的方法是按原样覆盖sizeThatFits:方法:

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

    return self.collectionViewLayout.collectionViewContentSize;
}

答案 4 :(得分:1)

与自定义UICollectionView类一起使用似乎效果很好。

class AutoSizedCollectionView: UICollectionView {

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

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

在界面生成器中设置您的自定义类:

enter image description here

这样,您还可以在界面生成器中将集合视图的固有大小设置为“占位符”,从而不必设置高度限制。

enter image description here

希望这对其他人有帮助。

答案 5 :(得分:0)

您可以试用我的自定义AGCollectionView课程

  • 使用故事板或以编程方式为collectionView指定高度约束。

- 将此课程分配给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
                }
            }
        }
    }
}

答案 6 :(得分:0)

  1. 为CollectionView高度约束添加IBOutlet ->就像@IBOutlet弱var collectionViewHeight:NSLayoutConstraint!
  2. 在下面的代码片段中添加

enter image description here

答案 7 :(得分:-3)

对我而言,我认为更简单

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