如何使用 FlowLayout 确定 UICollectionView 的高度
Posted
技术标签:
【中文标题】如何使用 FlowLayout 确定 UICollectionView 的高度【英文标题】:How to determine height of UICollectionView with FlowLayout 【发布时间】:2012-11-27 03:11:10 【问题描述】:我有一个UICollectionView
和一个UICollectionViewFlowLayout
,我想计算它的内容大小(返回intrinsicContentSize
需要通过自动布局调整其高度)。
问题是:即使所有单元格的高度固定且相等,我也不知道UICollectionView
中有多少“行”/行。我也无法通过数据源中的项目数来确定该计数,因为代表数据项的单元格的宽度不同,因此我在UICollectionView
的一行中拥有的项目数也是如此。
由于我在官方文档中找不到有关此主题的任何提示,并且谷歌搜索并没有给我带来任何进一步的信息,因此非常感谢任何帮助和想法。
【问题讨论】:
【参考方案1】:另外,你最好在得到高度之前打电话给reloadData
:
theCollectionView.collectionViewLayout.collectionViewContentSize;
【讨论】:
【参考方案2】:假设您的collectionView 被命名为collectionView,您可以按如下方式获取高度。
let height = collectionView.collectionViewLayout.collectionViewContentSize.height
【讨论】:
【参考方案3】:这个答案基于@Er。维哈尔的回答。您可以使用 RxSwift 轻松实现该解决方案
collectionView.rx.observe(CGSize.self , "contentSize").subscribe(onNext: (size) in
print("sizer \(size)")
).disposed(by: rx.disposeBag)
【讨论】:
【参考方案4】: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)
之前
之后
【讨论】:
【参考方案5】:斯威夫特 4.2
class DynamicCollectionView: UICollectionView
override func layoutSubviews()
super.layoutSubviews()
if bounds.size != intrinsicContentSize
invalidateIntrinsicContentSize()
override var intrinsicContentSize: CGSize
return self.contentSize
【讨论】:
【参考方案6】:斯威夫特 4
class DynamicCollectionView: UICollectionView
override func layoutSubviews()
super.layoutSubviews()
if !__CGSizeEqualToSize(bounds.size, self.intrinsicContentSize)
self.invalidateIntrinsicContentSize()
override var intrinsicContentSize: CGSize
return collectionViewLayout.collectionViewContentSize
【讨论】:
我发现它不适用于 iPhone 6/7 plus 和 XR,XS-MAX【参考方案7】:@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
【讨论】:
【参考方案8】:现在回答这个问题为时已晚,但我最近经历了这个问题。@lee 的above answer 帮助我得到了很多答案。但这个答案仅限于 objective-c,而我在 swift 工作。 @lee参考您的回答,请允许我让快速用户轻松解决此问题。为此,请按照以下步骤操作:
在声明部分声明一个CGFloat
变量:
var height : CGFloat!
在viewDidAppear
,您可以通过以下方式获得它:
height = self.myCollectionView.collectionViewLayout.collectionViewContentSize().height
也许当您 reload
数据然后需要用新数据计算新高度时,您可以通过:addObserver
来监听您的 CollectionView
在 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
别忘了移除观察者:
override func viewWillDisappear(animated: Bool)
super.viewWillDisappear(true)
....
....
self.myCollectionView.removeObserver(self, forKeyPath: "contentSize")
我希望这能帮助您快速解决问题。
【讨论】:
@ShikhaSharma:您可以在“ViewDidDisappear”方法中添加 removeObserver 代码,只有在视图确认其消失后才会删除观察者。请检查更新的答案。 收到此错误:An -observeValueForKeyPath:ofObject:change:context: 消息已收到但未处理。 @ShikhaSharma:抱歉,指定方法是我的错误。尝试将 removeobserver 代码放在 viewWillDisappear 中。 刚刚使用了它,它工作得很好——它的优点是在屏幕实际显示给用户之前通知我的回调,这样我就可以根据正在渲染的 UICollectionView 的最终大小。【参考方案9】:user1046037 答案的 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
【讨论】:
我是个新手,我不确定在我的 ViewController 中的何处以及如何使用它,您能否用答案进行编辑.....? 只需在 Storyboard 中将此类设置为您的收藏视图【参考方案10】:user1046037 用 Swift 回答...
class DynamicCollectionView: UICollectionView
override func layoutSubviews()
super.layoutSubviews()
if bounds.size != intrinsicContentSize()
invalidateIntrinsicContentSize()
override func intrinsicContentSize() -> CGSize
return self.contentSize
【讨论】:
它工作得很好,但是如果你有类似上面UILabel
的内容,来自collectionView
的内容会通过上面的其他元素,你还有其他解决方案吗?【参考方案11】:
在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];
【讨论】:
【参考方案12】:如果您使用自动布局,那么您可以创建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
【讨论】:
对我不起作用...我在 UITableViewCell 中使用我的 CollectionView 并希望随着使用 ios8 UITableViewAutomaticDimension 的集合视图的高度增长,tableview 的高度也会增长但我的 collectionview 仍然很小: ( 太棒了。在 UIScrollView 内对我的 UICollectionView 进行简短而甜蜜的解决方案! 一个重要的事情是在集合视图中禁用滚动和滚动条 和Georg一样的问题,高约50px,应该超过400 是的,我将 collectionview 设置为“不滚动,没有 scollbars”,然后重新加载它,然后设置 tableview 的内容。此外,collectionview 是一个子类,它返回它的内容大小作为 intrinsicContentSize。希望有帮助!【参考方案13】:哇!出于某种原因,经过数小时的研究,我现在找到了一个非常简单的问题答案:我完全找错了地方,翻遍了我在 UICollectionView
上找到的所有文档。
简单易用的解决方案在于底层布局:只需在myCollectionView.collectionViewLayout
属性上调用collectionViewContentSize
,即可获得内容的高度和宽度为CGSize
。就这么简单。
【讨论】:
哇,我希望 UITableView 有类似的东西 Ignatus, @jbandi, Chris 等人,你能扩展一下吗?当我使用具有较大项目间距的水平滚动方向进行测试时(以便项目水平布局),集合视图返回了无效的内在内容大小(-1,-1),而 collectionViewContentSize 返回了有效的内容集合视图的边界 - 不考虑只有一行被空间包围。简而言之,它不是很内在。谢谢! 滚动视图的collectionViewContentSize和contentSize有什么区别? 对谁有帮助:在此之前我必须做一个“layoutIfNeeded()”,这样我才能让它工作。collectionViewContentSize
什么时候设置?我们什么时候可以从中读取?以上是关于如何使用 FlowLayout 确定 UICollectionView 的高度的主要内容,如果未能解决你的问题,请参考以下文章
如何使用默认 FlowLayout 在 JPanel 中将 JButton 居中?
UITableViewCell 中的 UICollectionView?
如何将我的 UICollectionView Flowlayout 更改为具有水平滚动的垂直列表