如何使用FlowLayout确定UICollectionView的高度

时间:2012-12-09 14:54:26

标签: ios height uicollectionview autolayout

我有UICollectionView UICollectionViewFlowLayout,我想计算其内容大小(通过AutoLayout调整其高度所需的intrinsicContentSize返回)。

问题是:即使我对所有单元格都有一个固定且相等的高度,我也不知道UICollectionView中有多少“行”/行。我也无法通过数据源中的项目数来确定计数,因为表示数据项的单元格的宽度不同,因此我在UICollectionView的一行中的项目数也是如此。 / p>

由于我在官方文档中找不到关于此主题的任何提示,谷歌搜索没有给我带来任何进一步的帮助和想法,我们将非常感激。

13 个答案:

答案 0 :(得分:239)

哇!出于某种原因,经过几个小时的研究,我现在找到了一个非常简单的问题答案:我在错误的地方搜索,挖掘了我在UICollectionView找到的所有文档。

简单易用的解决方案在于底层布局:只需在collectionViewContentSize属性上调用myCollectionView.collectionViewLayout,即可获得内容的高度和宽度CGSize。就这么简单。

答案 1 :(得分:34)

如果您使用自动布局,则可以创建UICollectionView

的子类

如果您使用下面的代码,那么您不必为集合视图指定任何高度约束,因为它会根据集合视图的内容而有所不同。

以下是实施:

@interface DynamicCollectionView : UICollectionView

@end

@implementation DynamicCollectionView

- (void) layoutSubviews
{
    [super layoutSubviews];

    if (!CGSizeEqualToSize(self.bounds.size, [self intrinsicContentSize]))
    {
        [self invalidateIntrinsicContentSize];
    }
}

- (CGSize)intrinsicContentSize
{
    CGSize intrinsicContentSize = self.contentSize;

    return intrinsicContentSize;
}

@end

答案 2 :(得分:19)

viewDidAppear您可以通过以下方式获取:

float height = self.myCollectionView.collectionViewLayout.collectionViewContentSize.height;

也许当您重新加载数据时,需要使用新数据计算新高度,然后您可以通过以下方式获取: 添加观察者,以便在CollectionView完成重新加载数据时viewdidload

[self.myCollectionView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionOld context:NULL];

然后添加波纹管功能以获得新高度或在collectionview完成重新加载后执行任何操作:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary  *)change context:(void *)context
{
    //Whatever you do here when the reloadData finished
    float newHeight = self.myCollectionView.collectionViewLayout.collectionViewContentSize.height;    
}

不要忘记删除观察者:

[self.myCollectionView removeObserver:self forKeyPath:@"contentSize" context:NULL];

答案 3 :(得分:11)

用户104437回答Swift ...

class DynamicCollectionView: UICollectionView {
    override func layoutSubviews() {
        super.layoutSubviews()
        if bounds.size != intrinsicContentSize() {
            invalidateIntrinsicContentSize()
        }
    }

    override func intrinsicContentSize() -> CGSize {
        return self.contentSize
    }
}

答案 4 :(得分:8)

用户104437回答的Swift 3代码

import UIKit

class DynamicCollectionView: UICollectionView {

    override func layoutSubviews() {
        super.layoutSubviews()
        if !__CGSizeEqualToSize(bounds.size, self.intrinsicContentSize) {
            self.invalidateIntrinsicContentSize()
        }

    }

    override var intrinsicContentSize: CGSize {
        return contentSize
    }

}

答案 5 :(得分:3)

现在回答这个问题为时已晚,但我最近已经解决了这个问题。
@ lee' s above answer帮我解决了很多问题。但答案仅限于 objective-c ,而我正在 swift 工作。
@lee参考你的回答,请允许我让快速用户轻松解决这个问题。为此,请遵循以下步骤:

在声明部分声明CGFloat变量:

var height : CGFloat!

viewDidAppear您可以通过以下方式获取:

height = self.myCollectionView.collectionViewLayout.collectionViewContentSize().height

也许当您reload数据需要使用新数据计算新高度时,您可以通过addObserver获取它,以便在CollectionView完成重新加载{{1}数据时进行监听}}:

viewWillAppear

然后添加波纹管功能以获得新高度或在override func viewWillAppear(animated: Bool) { super.viewWillAppear(true) .... .... self.shapeCollectionView.addObserver(self, forKeyPath: "contentSize", options: NSKeyValueObservingOptions.Old, context: nil) } 完成重新加载后执行任何操作:

collectionview

不要忘记删除观察者:

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
        let newHeight : CGFloat = self.myCollectionView.collectionViewLayout.collectionViewContentSize().height

        var frame : CGRect! = self.myCollectionView.frame
        frame.size.height = newHeight

        self.myCollectionView.frame = frame
    }

我希望这可以帮助您快速解决您的问题。

答案 6 :(得分:3)

Swift 4

class DynamicCollectionView: UICollectionView {
  override func layoutSubviews() {
    super.layoutSubviews()
    if !__CGSizeEqualToSize(bounds.size, self.intrinsicContentSize) {
      self.invalidateIntrinsicContentSize()
    }
  }

  override var intrinsicContentSize: CGSize {
    return collectionViewLayout.collectionViewContentSize
  }
}

答案 7 :(得分:1)

Swift 4.2

class DynamicCollectionView: UICollectionView {
    override func layoutSubviews() {
        super.layoutSubviews()
        if bounds.size != intrinsicContentSize {
            invalidateIntrinsicContentSize()
        }
    }

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

答案 8 :(得分:0)

@ user1046037的Swift版本:

public class DynamicCollectionView: UICollectionView {

    override public func layoutSubviews() {
        super.layoutSubviews()
        if !bounds.size.equalTo(intrinsicContentSize) {
            invalidateIntrinsicContentSize()
        }
    }

    override public var intrinsicContentSize: CGSize {
        let intrinsicContentSize: CGSize = contentSize
        return intrinsicContentSize
    }
}

答案 9 :(得分:0)

此外:您最好先致电reloadData,然后再通过:myCollectionView.collectionViewLayout.collectionViewContentSize

答案 10 :(得分:0)

Swift 4.2,Xcode 10.1,iOS 12.1:

由于某种原因,collectionView.contentSize.height的显示尺寸小于我的收藏夹视图的已解析高度。首先,我使用的是相对于超级视图高度的1/2的自动布局约束。 要解决此问题,我将约束更改为相对于视图的“安全区域”。

这使我可以使用collectionView.contentSize.height设置单元格高度以填充收藏视图:

private func setCellSize() {
    let height: CGFloat = (collectionView.contentSize.height) / CGFloat(numberOfRows)
    let width: CGFloat = view.frame.width - CGFloat(horizontalCellMargin * 2)

    let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
    layout.itemSize = CGSize(width: width, height: height)
}

之前

height constraint relative to superview bad simulator result

之后

height constraint relative to safe area good simulator result

答案 11 :(得分:0)

此答案基于@Er。维哈尔的答案。您可以使用RxSwift轻松实现该解决方案

     collectionView.rx.observe(CGSize.self , "contentSize").subscribe(onNext: { (size) in
        print("sizer \(size)")
    }).disposed(by: rx.disposeBag)

答案 12 :(得分:0)

假设您的collectionView命名为 collectionView ,您可以按照以下方式进行调整。

let height = collectionView.collectionViewLayout.collectionViewContentSize.height