如何将 UICollectionView 的高度调整为 UICollectionView 的内容大小的高度?

我希望 UICollectionView (红色的那个)缩小到本例中内容大小的高度 UICollectionViewCell (黄色的那个) ,因为有很多空白。我试着用:

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


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

但是 return self.collection.contentSize总是返回(宽度,0) 由于这个原因,它收缩得太多,以至于高度值为30(这是我在 XIB 文件中设置的高度值,尽管我使用的是 Constant > = 30)。

enter image description here

142418 次浏览

首先计算单元格的数量,然后将其与单元格的高度相乘,然后在此方法中返回高度

    collectionView.frame = CGRectMake (x,y,w,collectionView.collectionViewLayout.collectionViewContentSize.height); //objective c
//[collectionView reloadData];
collectionView.frame = CGRect(x: 0, y: 0, width: width, height: collectionView.collectionViewLayout.collectionViewContentSize.height) // swift

我的建议如下:

  1. Add a height constraint to your collection view.
  2. 设置优先级为999。
  3. 将其常量设置为在故事板上能够合理显示的任何值。
  4. 将集合视图的底部相等约束更改为更大或相等。
  5. 将高度约束连接到插座。
  6. Every time you reload the data on the collection view do the following:

还可以通过将集合视图的 Inset 添加到内容大小来考虑它。

代码示例:

CGFloat height = myCollectionView.collectionViewLayout.collectionViewContentSize.height
heightConstraint.constant = height
self.view.setNeedsLayout() Or self.view.layoutIfNeeded()

说明: 号外,如果你看懂了,你就不用看了。当然! !

UI 将尝试反映所有的约束,而不管它们的优先级是什么。因为存在一个高度约束,其优先级较低为 (999),并且类型为大于等于的底部约束。每当高度约束常数设置为小于父视图高度的值时,集合视图将等于给定的高度,从而实现两个约束。

但是,当高度约束常数设置为大于父视图高度的值时,这两个约束都不能实现。因此,只有具有较高优先级的约束才能实现,这就是较大或相等的底部约束。

以下只是一个经验的猜测。因此,它达到了一个约束。但是,它也试图使 错误在产生的 UI 中用于其他未实现的较低优先级约束 越低越好。因此,集合视图高度将等于父视图大小。

You have to set height constraint as equal to content size

HeightConstraint.constant = collection.contentSize.height

跟着做。

  1. UICollectionView的第一个设置高度约束
  2. 这里 calendarBaseViewHeightUICollectionView高度变量
  3. 在重新加载集合视图后调用该函数

    func resizeCollectionViewSize(){
    calendarBaseViewHeight.constant = collectionView.contentSize.height
    }
    

最后,我对 UICollectionView进行了子类化并重写了一些方法,如下所示。

  • intrinsicContentSize返回 self.collectionViewLayout.collectionViewContentSize可以确保始终具有正确的大小
  • 然后当它可能改变的时候就调用它(就像在 reloadData上一样)

密码:

override func reloadData() {
super.reloadData()
self.invalidateIntrinsicContentSize()
}


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

但是请注意,如果显示大量数据,即使它们不适合在屏幕上显示,也会失去“单元格重用”。

1)设置 CollectionView 的固定高度。

2)创建 CollectionView 高度常数的出口。 比如:

IBOutlet NSLayoutConstraint * conconHeight;

3) Add below method in your .m file:

- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];


CGFloat height = collectionMenu.collectionViewLayout.collectionViewContentSize.height;
constHeight.constant = height;
}

UICollectionView上设置您的约束,如 TrailingLeadingBottom:

UICollectionView constraints

如果你看我的身高约束更详细,因为它是纯粹的故事板外观,所以我不会得到错误,我有它的 Remove at build time。真正的高度约束在下面的代码中设置。

UICollectionView height constraint

我的 DrawerCollectionView代码被设置为集合视图 Custom Class:

UICollectionView custom class

import UIKit


class DrawerCollectionView: UICollectionView {


override func didMoveToSuperview() {
super.didMoveToSuperview()


heightAnchor.constraint(equalToConstant: contentSize.height).isActive = true
}
}

In Swift 5 and Xcode 10.2.1

我的 CollectionView 名称是 MyCollectionView

  1. 修正 CollectionView 的高度

  2. 为 CollectionViewHeight 创建插座

    IBOutlet weak var myCollectionViewHeight: NSLayoutConstraint!
    
  3. 使用以下代码

    override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    let height = myCollectionView.collectionViewLayout.collectionViewContentSize.height
    myCollectionViewHeight.constant = height
    self.view.layoutIfNeeded()
    }
    

基于文本内容的单元格动态宽度..。

UICollectionView 的动态单元格宽度取决于标签宽度

为我工作

    let heightRes = resCollectionView.collectionViewLayout.collectionViewContentSize.height
foodHeightConstrant.constant = height.advanced(by: 1 )


foodCollectionView.setNeedsLayout()
foodCollectionView.layoutIfNeeded()

采取的解决方案 d4Rk,这是伟大的,除了在我的情况下,它会继续切断底部的我的收集视图(太短)。我发现这是因为内部内容的大小有时是0,这会打乱计算。IDK.我只知道这个修好了。

import UIKit


class SelfSizedCollectionView: UICollectionView {
override func reloadData() {
super.reloadData()
self.invalidateIntrinsicContentSize()
}


override var intrinsicContentSize: CGSize {
let s = self.collectionViewLayout.collectionViewContentSize
return CGSize(width: max(s.width, 1), height: max(s.height,1))
}


}

看看牢房的高度,像这样

let cellHeight = cell.frame.height

获取集合视图的原点

let cvOrigin = collectionView.frame.origin

获取集合视图的宽度

let cvWidth = collectionView.bounds.width

设置内容视图的框架

collection.frame = CGRect(x: cvOrigin.x, y: cvOrigin.y, width: cvWidth, height: cellHeight )

This seemed like the simplest solution for me.

class SelfSizingCollectionView: UICollectionView {
override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
super.init(frame: frame, collectionViewLayout: layout)
commonInit()
}


required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}


private func commonInit() {
isScrollEnabled = false
}


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


override func reloadData() {
super.reloadData()
self.invalidateIntrinsicContentSize()
}


override var intrinsicContentSize: CGSize {
return contentSize
}
}

您可能不需要重写 reloadData

  1. 子类 UICollectionView 如下所示
  2. 删除高度约束(如果有)
  3. 打开内部尺寸

-

class ContentSizedCollectionView: UICollectionView {
override var contentSize:CGSize {
didSet {
invalidateIntrinsicContentSize()
}
}


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

如果设置集合视图的高度约束。只需观察 viewDidLoad 中的 contentSize更改并更新约束即可。

        self.contentSizeObservation = collectionView.observe(\.contentSize, options: [.initial, .new]) { [weak self] collectionView, change in
guard let `self` = self else { return }
guard self.collectionView.contentSize != .zero else { return }
self.collectionViewHeightLayoutConstraint.constant = self.collectionView.contentSize.height
}

I have a multi-line, multi-selection UICollectionView subclass where the cells are of fixed height and left-aligned flowing from left to right. It's embedded in a vertical stack view that's inside a vertical scroll view. See the UI component below the label "Property Types".

enter image description here

为了使集合视图适合其 contentSize的高度,我必须这样做(注意,这都在 UICollectionView子类中) :

  1. 给集合视图一个优先级为 999的非零最小高度约束。将集合视图的大小自动调整为其内容高度,在零高度的情况下根本无法工作。

    let minimumHeight = heightAnchor.constraint(greaterThanOrEqualToConstant: 1)
    minimumHeight.priority = UILayoutPriority(999)
    minimumHeight.isActive = true
    
  2. 对于垂直轴,将集合视图的内容拥抱优先级设置为 .required

    setContentHuggingPriority(.required, for: .vertical)
    
  3. Calling reloadData() is followed by the following calls:

    invalidateIntrinsicContentSize()
    setNeedsLayout()
    layoutIfNeeded()
    

    例如,我的子类中有一个 setItems()函数:

    func setItems(_ items: [Item]) {
    self.items = items
    selectedIndices = []
    reloadData()
    invalidateIntrinsicContentSize()
    setNeedsLayout()
    layoutIfNeeded()
    }
    
  4. Override contentSize and intrinsicContentSize as follows:

    override var intrinsicContentSize: CGSize {
    return contentSize
    }
    
    
    override var contentSize: CGSize {
    didSet {
    invalidateIntrinsicContentSize()
    setNeedsLayout()
    layoutIfNeeded()
    }
    }
    

将 UICollectionView 的高度调整为其内容大小 的高度

SWIFT 5

final class MyViewController: UIViewController {


// it's important to declare layout as separate constant due to late update in viewDidLayoutSubviews()
private let layout = UICollectionViewFlowLayout()
private lazy var collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)




override func viewDidLoad() {
super.viewDidLoad()
    

setupCollectionView()
setupCollectionViewConstraints()
}


override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
    

updateFlowLayout()
}


private func setupCollectionView() {
view.addSubview(collectionView)
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "UICollectionViewCell")
collectionView.dataSource = self
}


private func setupCollectionViewConstraints() {
// your collectionView constraints setup
}


private func updateFlowLayout() {
let height = collectionView.collectionViewLayout.collectionViewContentSize.height
layout.itemSize = CGSize(width: view.frame.width, height: height)
layout.scrollDirection = .horizontal
layout.minimumInteritemSpacing = .zero
layout.minimumLineSpacing = .zero
layout.sectionInset = UIEdgeInsets.zero
}
}


extension MyViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {...}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {...}
}

我在 UITableView 单元格中使用了 UICollectionView。

在集合视图的父视图中,我像这样更新了 layoutSubviews方法中的高度约束

override func layoutSubviews() {
heightConstraint.constant = myCollectionView.collectionViewLayout.collectionViewContentSize.height
}

然后在返回手机之前,在 cellForRowAtIndexpath中调用这个

cell.layoutIfNeeded()