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


79

我希望UICollectionView(红色的)缩小到内容大小的高度,在这种情况下,UICollectionViewCells(黄色的)是因为有很多空白空间。我尝试使用的是:

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总是返回(width,0),因此,它会缩小到高度30的值(尽管我在constaint> = 30的情况下在XIB文件中为高度设置的值)。

在此处输入图片说明


1
您必须采用ColletionView的高度约束出口并像这样调整高度heightConstraint.constant = collectionView.contentSize.height
dahiya_boy

您使用的是自定义布局还是Apple提供的UICollectionViewFlowLayout?
Georgi Boyadzhiev

我正在使用默认的一个UICollectionViewFlowLayout
charbinary

比您应该使用collectionViewLayout.collectionViewContentSize,请参阅@ hasan83的答案。这对您来说是一种可能性。
Georgi Boyadzhiev

Answers:


172

我建议以下内容:

  1. 向您的集合视图添加高度限制。
  2. 将其优先级设置为999。
  3. 将其常数设置为使其在情节提要板上合理可见的任何值。
  4. 将集合视图的底部相等约束更改为更大或相等。
  5. 将高度限制器连接到插座。
  6. 每次在集合视图上重新加载数据时,请执行以下操作:

您可能还想通过将集合视图添加到内容大小来考虑它的插图。

代码样例:

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

说明:额外,如果您了解它,则不必阅读。明显!!

用户界面将尝试反映所有约束,无论它们的优先级是什么。由于高度限制的优先级较低(999),而底部限制的优先级较高或相等。只要将高度限制常数设置为小于父视图高度的值,收集视图将等于给定高度,从而实现两个限制。

但是,当高度约束常数设置为大于父视图高度的值时,将无法实现两个约束。因此,将仅获得具有较高优先级的约束,该约束是更大或相等的底部约束。

以下只是经验的猜测。因此,它达到一个常数。但是,它还会尝试使其他未实现的较低优先级约束的结果UI中的错误尽可能低。因此,集合视图的高度将等于父视图的大小。


矿山扩张到一定程度,但并不完美。它错过了大约3 4行标签。任何想法?外观如下:ibb.co/jeO9Rv ibb.co/iV8b6v
nr5

@Nil您的收藏视图上是否有页眉或页脚?页脚和页眉的高度必须添加。
哈桑

没关系,它有效。将高度限制设置为比例高度,这就是为什么仅设置常数不会产生太大差异的原因。
nr5

当我们交谈时,您是否知道如何将单元固定在顶部?在我的水平collectionview中,某些单元格未固定在顶部。只是随机漂浮在中间。此处:ibb.co/fHbSwv
nr5

@ hasan83通过这种方式,我得到了更多的收藏视图高度,有什么建议吗?
Mitesh Dobareeya

17

1)设置您的CollectionView的Fix Height。

2)创建此CollectionView高度常量的出口。喜欢 :

IBOutlet NSLayoutConstraint * constHeight;

3)在您的.m文件中添加以下方法:

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

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

3
使用Swift 5和工作Xcode 10.2.1。谢谢。
Pankaj Kulkarni,

15

最后,通过对UICollectionView和重写了一些方法,如下所示。

  • 返回self.collectionViewLayout.collectionViewContentSizeintrinsicContentSize确保,总是有正确的尺寸
  • 然后只要它可能更改就调用它(如reloadData

码:

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

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

但是请注意,即使显示大数据集,即使屏幕上无法容纳这些数据,也会丢失“单元重用”。


这可以使UICollectionView最初的内容大小变大,但是如果内容更改(即:插入或删除行),则不会调整大小。如果我调用重载数据,则集合视图在调整大小时会停顿。有什么办法可以阻止这种口吃吗?
cabyambo

您是否尝试self.invalidateIntrinsicContentSize()不打电话就打电话reloadData()?也许这可行。
d4Rk '19

1
到目前为止,最漂亮的解决方案-至少对于我的用例而言。谢谢。它解决了时间安排问题,布局需要所有其他约束,并且需要调整视图的大小来确定内容的大小-这是可行的。
n13

1
实际上-我必须将固有大小限制为至少1-永不为0-才能正常工作。否则,计算中会出现小错误,从而将视图底部减少几个像素。
n13

1
@AnthonyMDev因为使用这种方法,所以您正在调整集合视图的大小以同时适合所有项目,因此所有项目都可以随时加载。
d4Rk

10

您必须将高度限制设置为等于内容大小

HeightConstraint.constant = collection.contentSize.height 

10

在Swift 5和Xcode 10.2.1中

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

它在您的代码中是什么myCollectionView。在哪里声明
Karthi

@ Karthi Rasu,myCollectionView是您的集合视图高度限制。如果使用情节提要,请修复collectionView的高度。
iOS

1
完美的解决方案!
Vinayak Bhor

5

对于我来说,这似乎是最简单的解决方案。

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
这是在iOS 14上对我唯一有效的方法。谢谢!
Teddy K

3

做以下。

  1. 首先设置高度限制 UICollectionView
  2. calendarBaseViewHeightUICollectionView高度可变
  3. 重新加载集合视图后调用该函数

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

3

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))
    }

}

2

首先计算单元格数量,然后将其乘以单元格高度,然后以这种方法返回高度

    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

此方法返回索引路径处特定单元格的大小,如果将高度设置为noOfCell * heightOfCell,则将设置所有单元格的高度。
Georgi Boyadzhiev

@Georgi Boyadzhiev,是的。
charbinary

2
  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)
    }
}

0

在您UICollectionView设定的限制,例如TrailingLeadingBottom

UICollectionView约束

如果您更详细地查看我的身高限制,因为它纯粹是用于演示图板,因此我不会出错,所以我可以做到Remove at build time。实际高度限制在下面的代码中设置。

UICollectionView高度限制

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

UICollectionView自定义类

import UIKit

class DrawerCollectionView: UICollectionView {

    override func didMoveToSuperview() {
        super.didMoveToSuperview()

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

尝试过,但这对我不起作用。d4Rk的另一种子分类解决方案进行了细微修改
n13

0

为我工作

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

    foodCollectionView.setNeedsLayout()
    foodCollectionView.layoutIfNeeded()

0

获取单元格的高度。像这样

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 )

0

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

        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
        }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.