【问题标题】:How to set UICollectionViewCell Width and Height programmatically如何以编程方式设置 UICollectionViewCell 宽度和高度
【发布时间】:2016-10-27 22:27:54
【问题描述】:

我正在尝试实现CollectionView。 当我使用自动布局时,我的单元格不会改变大小,但它们的对齐方式。

现在我宁愿将它们的大小更改为例如

var size = CGSize(width: self.view.frame.width/10, height: self.view.frame.width/10)

我尝试在我的CellForItemAtIndexPath中设置

collectionCell.size = size

它没有工作。

有没有办法做到这一点?

编辑

看来,答案只会改变我的 CollectionView 宽度和高度本身。约束可能存在冲突吗?有什么想法吗?

【问题讨论】:

    标签: swift uicollectionview


    【解决方案1】:

    使用此方法设置自定义单元格高度宽度。

    确保添加此协议

    UICollectionViewDelegate
    
    UICollectionViewDataSource
    
    UICollectionViewDelegateFlowLayout
    

    如果您正在使用 swift 5xcode 11 及更高版本,则需要使用情节提要将 Estimate Size 设置为 none 以使其正常工作。如果您不设置,则下面的代码将无法按预期工作。

    Swift 4 或更高版本

    extension YourViewController: UICollectionViewDelegate {
        //Write Delegate Code Here
    }
    
    extension YourViewController: UICollectionViewDataSource {
        //Write DataSource Code Here
    }
    
    extension YourViewController: UICollectionViewDelegateFlowLayout {
        func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
            return CGSize(width: screenWidth, height: screenWidth)
        }
    }
    

    Objective-C

    @interface YourViewController : UIViewController<UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout>
    
    - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
    {
        return CGSizeMake(CGRectGetWidth(collectionView.frame), (CGRectGetHeight(collectionView.frame)));
    }
    

    【讨论】:

    • @RamyAlZuhouri 编辑了我的答案,请检查并让我知道我们是否仍需要使其更清楚
    • 我已经习惯了以编程方式做所有事情,现在这对我来说似乎很陌生。在情节提要中将 Estimated Size 设置为 None 并添加 UICollectionViewDelegateFlowLayout 是什么技巧
    • 将估计大小设置为无对我有用。谢谢@PinkeshGjr
    • 我很高兴我找到了这个,我浪费了 2 个小时来追逐这个只是为了学习神奇的“估计大小为零”
    • 将 Estimate Size 设置为 none 节省了我的时间。
    【解决方案2】:

    如果使用故事板并覆盖 UICollectionViewDelegateFlowLayout,那么在 swift 5 和 Xcode 11 中也将 Estimate size 设置为 None

    【讨论】:

    • 这很有帮助。谢谢!!
    • 将估计大小设置为 none 可以解决所有问题
    • Thnx 将估计大小设置为无问题修复
    • 很好的修复。这是我根据Apple's documentation 对这个问题的诊断:UICollectionViewFlowLayout 在使用 IB 时似乎默认为estimatedItemSizeUICollectionViewFlowLayout.automaticSize,即使文档说它应该默认为CGSizeZero。正如 Apple 所说,automaticSize“为您的收藏视图启用自调整大小的单元格。”这就是为什么 IB 中的其他大小变化无济于事。
    • 刚刚为我节省了几个小时,我一直在努力寻找解决办法
    【解决方案3】:

    确保在您的class 声明中添加协议UICollectionViewDelegateFlowLayout

    class MyCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout
    {
        //MARK: - UICollectionViewDelegateFlowLayout
    
        func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
        {
           return CGSize(width: 100.0, height: 100.0)
        }
    }
    

    【讨论】:

    • 别忘了使用流式布局而不是自定义。那么你是唯一对我有用的。谢谢!
    • 我们如何在这里给出动态高度,将静态高度设为 100.0
    【解决方案4】:

    终于找到答案了。 你应该扩展UICollectionViewDelegateFlowLayout
    这应该与上面的答案一起使用。

    【讨论】:

    • 你能写一个例子吗?
    • 实际上我用 datasource 和 delegateFlowLayout 协议做了一个扩展,但它没有工作。起作用的是将 FlowLayout 部分分离为它自己的扩展。不知道为什么,但它在 swift 3 中起作用。
    【解决方案5】:

    斯威夫特 4

    你有两种方法可以改变 CollectionView 的大小。
    第一种方法 -> 添加这个协议 UICollectionViewDelegateFlowLayout
    for 就我而言,我想将单元格分成一行中的 3 部分。我在下面做了这段代码

    extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource ,UICollectionViewDelegateFlowLayout{
        func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
        {
                // In this function is the code you must implement to your code project if you want to change size of Collection view
                let width  = (view.frame.width-20)/3
                return CGSize(width: width, height: width)
        }
    
        func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
            return collectionData.count
        }
        
        func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath)
            if let label = cell.viewWithTag(100) as? UILabel {
                label.text = collectionData[indexPath.row]
            }
            return cell
        }
    }
    

    第二种方式 -> 你不必 必须添加 UICollectionViewDelegateFlowLayout 但你必须在 viewDidload 函数中编写一些代码 改为下面的代码

    class ViewController: UIViewController {
    @IBOutlet weak var collectionView1: UICollectionView!
            var collectionData = ["1.", "2.", "3.", "4.", "5.", "6.", "7.", "8.", "9.", "10.", "11.", "12."]
    
        override func viewDidLoad() {
            super.viewDidLoad()
            let width = (view.frame.width-20)/3
            let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
            layout.itemSize = CGSize(width: width, height: width) 
        }
    }
    

    extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource {
       
    
        func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
            return collectionData.count
        }
        
        func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath)
            if let label = cell.viewWithTag(100) as? UILabel {
                label.text = collectionData[indexPath.row]
            }
       
            return cell
        }
    }
    

    无论您以第一种方式还是第二种方式编写代码,您都会得到与上述相同的结果。我写的。 它对我有用

    【讨论】:

    • 直接来自 raywenderlich.com ?
    【解决方案6】:

    根据 iPhone 尺寸的尺寸比例:

    以下是针对 iPhone 尺寸设置不同宽度和高度的单元格的方法:

    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
        let width = (self.view.frame.size.width - 12 * 3) / 3 //some width
        let height = width * 1.5 //ratio
        return CGSize(width: width, height: height)
    }
    

    也许您还应该禁用单元格上的 AutoLayout 约束以使此答案起作用。

    【讨论】:

    • 我尝试了这个和上述所有解决方案,但是单元格中的内容没有自动调整大小,我该如何解决这个问题
    【解决方案7】:

    Swift3Swift4 中,您可以通过添加 UICollectionViewDelegateFlowLayout 来更改单元格大小并像这样实现它:

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
            return CGSize(width: 100, height: 100)
        }
    

    或者如果以编程方式创建 UICollectionView,您可以这样做:

        let layout = UICollectionViewFlowLayout()
                        layout.scrollDirection = .horizontal //this is for direction
                        layout.minimumInteritemSpacing = 0 // this is for spacing between cells
                        layout.itemSize = CGSize(width: view.frame.width, height: view.frame.height) //this is for cell size
    let collectionView = UICollectionView(frame: self.view.bounds, collectionViewLayout: layout)
    

    【讨论】:

      【解决方案8】:

      集合视图有一个 layout 对象。在您的情况下,它可能是一个流布局 (UICollectionViewFlowLayout)。设置流布局的itemSize 属性。

      【讨论】:

      • 试过这个。给了我和以前一样的问题。不知何故,我的 CollectionView 改变了它的大小,而不是我的单元格。
      • 嗯,这完全取决于您何时这样做。你还没有展示你的真实代码,所以谁知道你在做什么?我向你保证它确实有效。
      【解决方案9】:

      swift4 swift 4 ios 集合视图 collectionview 示例 xcode 最新代码工作示例

      将此添加到顶部的委托部分

      UICollectionViewDelegateFlowLayout

      并使用此功能

      func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
          let width = (self.view.frame.size.width - 20) / 3 //some width
          let height = width * 1.5 //ratio
          return CGSize(width: width, height: height)
      }
      

      ///// 示例完整代码

      在故事板中的集合视图和集合视图单元格上创建将集合引用为
      @IBOutlet 弱 var cvContent: UICollectionView!

      将其粘贴到视图控制器中

       import UIKit
      
      class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
      
          var arrVeg = [String]()
          var arrFruits = [String]()
          var arrCurrent = [String]()
          
          @IBOutlet weak var cvContent: UICollectionView!
          
        
          
          override func viewDidLoad() {
              super.viewDidLoad()
              arrVeg = ["Carrot","Potato", "Tomato","Carrot","Potato", "Tomato","Carrot","Potato", "Tomato","Carrot","Potato", "Tomato"]
              
              arrVeg = ["Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange"]
              
              
              arrCurrent = arrVeg
          }
          //MARK: - CollectionView
          
      
      
          func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
              let width = (self.view.frame.size.width - 20) / 3 //some width
              let height = width * 1.5 //ratio
              return CGSize(width: width, height: height)
          }
          
          func numberOfSections(in collectionView: UICollectionView) -> Int {
      
              return 1
          }
          
          func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
              
              
              return arrCurrent.count
          }
          
          
          
          func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
              let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! ContentCollectionViewCell
              cell.backgroundColor =  UIColor.green
              return cell
          }
      }
      

      【讨论】:

        【解决方案10】:

        试试下面的方法

        func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
            return CGSize(width: 100.0, height: 100.0)
        }
        

        【讨论】:

          【解决方案11】:

          Swift 5 编程

          lazy var collectionView: UICollectionView = {
                  let layout = UICollectionViewFlowLayout()
                  layout.scrollDirection = .horizontal
          
                  //Provide Width and Height According to your need
                  let cellWidth = UIScreen.main.bounds.width / 10
                  let cellHeight = UIScreen.main.bounds.height / 10
                  layout.itemSize = CGSize(width: cellWidth, height: cellHeight)
          
                  //You can also provide estimated Height and Width
                  layout.estimatedItemSize = CGSize(width: cellWidth, height: cellHeight)
          
                  //For Setting the Spacing between cells
                  layout.minimumInteritemSpacing = 0
                  layout.minimumLineSpacing = 0
          
                  return UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
              }()
          

          【讨论】:

            【解决方案12】:

            斯威夫特 5

            添加这些协议

             - `UICollectionViewDelegate`
               
               
             - `UICollectionViewDataSource`
               
             
             - `UICollectionViewDelegateFlowLayout`
            

            您的代码将如下所示

            extension YourViewController: UICollectionViewDelegate {
                //Write Delegate Code Here
            }
            
            extension YourViewController: UICollectionViewDataSource {
                //Write DataSource Code Here
            }
            
            extension YourViewController: UICollectionViewDelegateFlowLayout {
                func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
                    return CGSize(width: screenWidth, height: screenWidth)
                }
            }
            

            现在看到此效果生效的最后一个关键步骤是转到 Viewcontroller 中的 viedDidLoad 函数。

                override func viewDidLoad() {
                    super.viewDidLoad()
                    collection.dataSource = self // Add this
                    collection.delegate = self // Add this
                    
                    // Do any additional setup after loading the view.
                }
            

            如果不告诉您的视图委托是哪个类,它将无法工作。

            【讨论】:

              【解决方案13】:

              另一种方法是直接在流布局中设置值

                  let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
                  layout.itemSize = CGSize(width: size, height: size)
              

              【讨论】:

                【解决方案14】:

                绝对简单的方法:

                class YourCollection: UIViewController,
                     UICollectionViewDelegate,
                     UICollectionViewDataSource {
                

                您必须添加“UICollectionViewDelegateFlowLayout”,否则没有自动完成:

                class YourCollection: UIViewController,
                     UICollectionViewDelegate,
                     UICollectionViewDataSource,
                     UICollectionViewDelegateFlowLayout {
                

                键入“sizeForItemAt...”。大功告成!

                class YourCollection: UIViewController,
                     UICollectionViewDelegate,
                     UICollectionViewDataSource,
                     UICollectionViewDelegateFlowLayout {
                 
                     func collectionView(_ collectionView: UICollectionView,
                      layout collectionViewLayout: UICollectionViewLayout,
                      sizeForItemAt indexPath: IndexPath) -> CGSize {
                     
                     return CGSize(width: 37, height: 63)
                }
                

                就是这样。

                例如,如果您想要“每个单元格填充整个集合视图”:

                     guard let b = view.superview?.bounds else { .. }
                     return CGSize(width: b.width, height: b.height)
                

                【讨论】:

                  【解决方案15】:

                  因此,您需要从情节提要中将单元格部分中collectionView 的属性估计为无,并且在您的ViewController 中,您需要有实现此方法的委托方法:optional func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -&gt; CGSize

                  【讨论】:

                    【解决方案16】:

                    尝试使用 UICollectionViewDelegateFlowLayout 方法。在 Xcode 11 或更高版本中,您需要在 storyboard 中将 Estimate Size 设置为 none。

                    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: 
                    UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
                        let padding: CGFloat =  170
                        let collectionViewSize = advertCollectionView.frame.size.width - padding
                        return CGSize(width: collectionViewSize/2, height: collectionViewSize/2)
                    }
                    

                    【讨论】:

                      【解决方案17】:

                      一个简单的方法:

                      如果您只需要简单的固定尺寸

                      class SizedCollectionView: UIICollectionView {
                          override func common() {
                              super.common()
                              let l = UICollectionViewFlowLayout()
                              l.itemSize = CGSize(width: 42, height: 42)
                              collectionViewLayout = l
                          }
                      }
                      

                      仅此而已。

                      在故事板中,只需将类从 UICollectionView 更改为 SizedCollectionView。

                      但是!!!

                      注意基类有“UI 'I' CollectionView”。 'I' 表示初始化器。

                      将初始化程序添加到集合视图并不容易。这是一种常见的方法:

                      集合视图...带初始化器:

                      import UIKit
                      
                      class UIICollectionView: UICollectionView {
                          private var commoned: Bool = false
                          
                          override func didMoveToWindow() {
                              super.didMoveToWindow()
                              if window != nil && !commoned {
                                  commoned = true
                                  common()
                              }
                          }
                          
                          internal func common() {
                          }
                      }
                      

                      在大多数项目中,您需要“带有初始化程序的集合视图”。所以你可能无论如何都会在你的项目中拥有UIICollectionView(注意额外的I for Initializer!)。

                      【讨论】:

                        【解决方案18】:

                        Swift 5,程序化 UICollectionView 设置单元格宽度和高度

                        // MARK: MyViewController
                        
                        final class MyViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
                            
                            private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
                                let layout = UICollectionViewFlowLayout()
                                let spacing: CGFloat = 1
                                let numOfColumns: CGFloat = 3
                                let itemSize: CGFloat = (UIScreen.main.bounds.width - (numOfColumns - spacing) - 2) / 3
                                layout.itemSize = CGSize(width: itemSize, height: itemSize)
                                layout.minimumInteritemSpacing = spacing
                                layout.minimumLineSpacing = spacing
                                layout.sectionInset = UIEdgeInsets(top: spacing, left: spacing, bottom: spacing, right: spacing)
                                return layout
                            }()
                            
                            private lazy var collectionView: UICollectionView = {
                                let collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: collectionViewLayout)
                                collectionView.backgroundColor = .white
                                collectionView.dataSource = self
                                collectionView.delegate = self
                                collectionView.translatesAutoresizingMaskIntoConstraints = false
                                return collectionView
                            }()
                            
                            override func viewDidLoad() {
                                super.viewDidLoad()
                                configureCollectionView()
                            }
                            
                            private func configureCollectionView() {
                                view.addSubview(collectionView)
                                NSLayoutConstraint.activate([
                                    collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
                                    collectionView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
                                    collectionView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
                                    collectionView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor)
                                ])
                                collectionView.register(PhotoCell.self, forCellWithReuseIdentifier: "PhotoCell")
                            }
                            
                            // MARK: UICollectionViewDataSource
                        
                            func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
                                return 20
                            }
                            
                            func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
                                let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoCell", for: indexPath) as! PhotoCell
                                cell.backgroundColor = .red
                                return cell
                            }
                            
                        }
                        
                        // MARK: PhotoCell
                        
                        final class PhotoCell: UICollectionViewCell {
                            
                            lazy var imageView: UIImageView = {
                                let imageView = UIImageView()
                                imageView.contentMode = .scaleAspectFill
                                imageView.translatesAutoresizingMaskIntoConstraints = false
                                imageView.layer.masksToBounds = true
                                return imageView
                            }()
                            
                            override init(frame: CGRect) {
                                super.init(frame: frame)
                                setupViews()
                            }
                            
                            required init?(coder aDecoder: NSCoder) {
                                fatalError("init?(coder:) not implemented")
                            }
                            
                            func setupViews() {
                                addSubview(imageView)
                                NSLayoutConstraint.activate([
                                    topAnchor.constraint(equalTo: topAnchor),
                                    bottomAnchor.constraint(equalTo: bottomAnchor),
                                    leadingAnchor.constraint(equalTo: leadingAnchor),
                                    trailingAnchor.constraint(equalTo: trailingAnchor)
                                ])
                            }
                            
                        }
                        

                        【讨论】:

                          【解决方案19】:

                          如果像我一样,您需要根据集合视图的宽度动态更新自定义流布局的 itemSize,您应该覆盖 UICollectionViewFlowLayoutprepare() 方法。这是WWDC video demoing this technique

                          class MyLayout: UICollectionViewFlowLayout {
                              
                              override func prepare() {
                                  super.prepare()
                                  
                                  guard let collectionView = collectionView else { return }
                                  
                                  itemSize = CGSize(width: ..., height: ...)
                              }
                              
                          }
                          

                          【讨论】:

                            【解决方案20】:

                            如果您不使用 UICollectionViewController,则需要通过设置委托 UICollectionViewDelegate、UICollectionViewDataSource、UICollectionViewDelegateFlowLayout 来为其添加一致性。

                              extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout
                            

                            之后,您必须为添加到 ViewController 的集合视图设置一个委托。

                              collectionView.delegate = self
                              collectionView.dataSource = self
                            
                            
                              
                            

                            最后,你必须为你的集合视图添加布局:

                              let collectionLayout = UICollectionViewFlowLayout()
                              collectionView.collectionViewLayout = collectionLayout
                            

                            完成这些步骤后,您可以在 func 中更改大小:

                              func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
                            

                            【讨论】:

                              【解决方案21】:

                              这是我的版本,根据您的要求找到合适的比例以获得单元格大小。

                              - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath 
                              { 
                              return CGSizeMake(CGRectGetWidth(collectionView.frame)/4, CGRectGetHeight(collectionView.frame)/4); 
                              } 
                              

                              【讨论】:

                                猜你喜欢
                                • 1970-01-01
                                • 2011-03-09
                                • 1970-01-01
                                • 2018-02-16
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                • 2015-10-04
                                相关资源
                                最近更新 更多