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

时间:2017-02-24 11:52:38

标签: ios objective-c swift autolayout

我希望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总是返回(宽度,0) 由于这个原因,它缩小到高度值30(我在xib文件中为高度设置的值,虽然我有constaint> = 30)。

enter image description here

16 个答案:

答案 0 :(得分:97)

我建议如下:

  
      
  1. 向集合视图添加高度约束。
  2.   
  3. 将其优先级设置为999。
  4.   
  5. 将其常量设置为可在故事板上合理显示的任何值。
  6.   
  7. 将集合视图的底部相等约束更改为大于或等于。
  8.   
  9. 将高度限制连接到插座。
  10.   
  11. 每次在集合视图上重新加载数据时,请执行以下操作:
  12.   

代码示例:

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

说明:额外的,如果您理解,您不必阅读。显然!!

UI将尝试反映所有约束,无论它们的优先级如何。由于高度约束的优先级较低(999),因此底部约束类型大于或等于。每当高度约束常量设置为小于父视图高度的值时,集合视图将等于给定高度,从而实现两个约束。

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

以下只是对经验的猜测。因此,它实现了一个常量。但是,它还尝试在结果用户界面中将错误用于其他未实现的较低优先级约束尽可能最低。因此,集合视图高度将等于父视图大小。

答案 1 :(得分:9)

我最后通过继承UICollectionView并覆盖了一些方法,如下所示。

  • self.collectionViewLayout.collectionViewContentSize返回intrinsicContentSize,确保始终拥有正确的尺寸
  • 然后只要它发生变化就可以调用它(比如reloadData

代码:

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

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

但请注意,如果您显示大量数据,则会丢失“重复使用单元格”,尽管它们不适合屏幕。

答案 2 :(得分:5)

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

HeightConstraint.constant = collection.contentSize.height 

答案 3 :(得分:5)

1)设置CollectionView的Fix Height。

2)创建此CollectionView高度常数的出口。    像:

  

IBOutlet NSLayoutConstraint * constHeight;

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

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

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

答案 4 :(得分:2)

请遵循。

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

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

答案 5 :(得分:2)

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

}

答案 6 :(得分: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)
    }
}

答案 7 :(得分:1)

首先计算细胞数,然后将其与细胞高度相乘,然后在此方法中返回高度

    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

答案 8 :(得分:0)

在您的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
    }
}

答案 9 :(得分:0)

在Swift 5和Xcode 10.2.1中

1)修复CollectionView的高度

2)创建您的CollectionView的出口

IBOutlet weak var myCollectionViewHeight: NSLayoutConstraint!

3)使用以下代码

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

答案 10 :(得分:0)

为我工作

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

    foodCollectionView.setNeedsLayout()
    foodCollectionView.layoutIfNeeded()

答案 11 :(得分: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 )

答案 12 :(得分:0)

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

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

答案 13 :(得分:0)

如果设置了集合视图的高度约束。只需观察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
        }

答案 14 :(得分:0)

我有一个多行、多选的 UICollectionView 子类,其中单元格具有固定高度且左对齐从左到右流动。它嵌入在垂直滚动视图内的垂直堆栈视图中。请参阅标签“属性类型”下方的 UI 组件。

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. 调用 reloadData() 之后是以下调用:

    invalidateIntrinsicContentSize()
    setNeedsLayout()
    layoutIfNeeded()
    

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

    func setItems(_ items: [Item]) {
      self.items = items
      selectedIndices = []
      reloadData()
      invalidateIntrinsicContentSize()
      setNeedsLayout()
      layoutIfNeeded()
    }
    
  4. 按如下方式覆盖 contentSizeintrinsicContentSize

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

答案 15 :(得分:0)

将 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 {...}
}