【问题标题】:How to determine height of UICollectionView with FlowLayout如何使用 FlowLayout 确定 UICollectionView 的高度
【发布时间】:2012-11-27 03:11:10
【问题描述】:

我有一个UICollectionView 和一个UICollectionViewFlowLayout,我想计算它的内容大小(返回intrinsicContentSize 需要通过自动布局调整其高度)。

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

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

【问题讨论】:

    标签: ios height uicollectionview autolayout


    【解决方案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 来监听您的 CollectionViewviewWillAppear 完成重新加载数据时:

                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;
                

                也许当您重新加载数据然后需要使用新数据计算新高度时,您可以通过以下方式获得它: 当您的CollectionViewviewdidload 完成重新加载数据时,添加观察者来监听:

                [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 什么时候设置?我们什么时候可以从中读取?
                  猜你喜欢
                  • 1970-01-01
                  • 2012-10-12
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2021-10-23
                  • 1970-01-01
                  • 1970-01-01
                  • 2017-07-15
                  相关资源
                  最近更新 更多