如何以编程方式设置 UICollectionViewCell 宽度和高度

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

现在我宁愿改变他们的尺寸,例如。

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

我试着设置我的 CellForItemAtIndexPath

collectionCell.size = size

但没成功。

有办法做到吗?

编辑 :

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

304509 次浏览

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

一定要加上这个协议

UICollectionViewDelegate


UICollectionViewDataSource


UICollectionViewDelegateFlowLayout

如果您正在使用 迅猛5代码11,以后您需要设置 Estimate Sizenone使用故事板,以使其正常工作。如果不设置该值,则下面的代码将不能按预期工作。

enter image description here

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

目标 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)));
}

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

也许您还应该禁用单元格上的自动布局约束,以便这个答案能够正常工作。

试试下面的方法

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

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

终于找到答案了。 你应该延长 UICollectionViewDelegateFlowLayout
这应该与上面的答案一起工作。

确保在 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)
}
}

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

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

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

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

Swift 4

有两种方法可以更改 CollectionView 的大小。
第一种方法 -> 添加此协议 视图代表流布局 < br > 用于 在我的例子中,我想把单元格分成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
}
}

第二种方法 -> 你的 不要必须添加 视图代表流布局,但是你必须在 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
}
}

无论你以第一种方式还是第二种方式编写代码,你都会得到与上面相同的结果。是我写的。这招对我很管用

enter image description here

Swift4 Swift 4 ios 集合视图 Collectionview 示例 xcode 最新代码工作示例

将其添加到顶部的“委托”部分

视图代表流布局

并使用这个函数

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

///// 示例完整代码

创建集合视图和故事板中的 Collectionview 单元格
@ IBOutlet softvar 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
}
}

Swift3Swift4中,你可以通过添加 视图代表流布局来改变细胞大小,实现方法如下:

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)

用程序设计的 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)
}()

Swift 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.
}

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

如果使用故事板并覆盖 视图代表流布局,那么在 Swift 5和 Xcode 11中也将 < strong > Estimate size 设置为 Nothing enter image description here

一个简单的方法:

如果你只是需要一个 简单的固定尺寸:

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”。

向集合视图中添加初始化程序并不容易:

集合视图... 带初始化程序:

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!)在你的项目中。

因此,您需要从情节串连图板中设置 CollectionView 的属性,在单元格部分估计 Size 为 no,并且在 ViewController 中,您需要具有实现此方法的委托方法: optional func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize

尝试使用 UICollectionViewgenerateFlowLayout 方法。在 Xcode 11或更高版本中,您需要从故事板中将 EstimateSize 设置为无。

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

绝对简单的方法:

class YourCollection: UIViewController,
UICollectionViewDelegate,
UICollectionViewDataSource {

您必须添加“ UICollectionViewgenerateFlowLayout”,否则无法自动完成:

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)

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

}

如果像我一样,需要根据集合视图的宽度动态更新自定义流布局的 itemSize,则应重写 UICollectionViewFlowLayoutprepare()方法。这是 WWDC 视频演示了这种技术

class MyLayout: UICollectionViewFlowLayout {
    

override func prepare() {
super.prepare()
        

guard let collectionView = collectionView else { return }
        

itemSize = CGSize(width: ..., height: ...)
}
    

}

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

  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

对于 StoryBoard 用户的回答是: “在大小检查器中,将您的收集单元格大小从自定义更改为自动”。

screenshot link

Swift 5

以编程方式完成的解决方案

// In viewDidLoad
if let cvLayout = horizontalCV.collectionViewLayout as? UICollectionViewFlowLayout{
cvLayout.estimatedItemSize = .zero
}




extension TUIViewController: UICollectionViewDelegateFlowLayout {
    

func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: (collectionView.frame.size.width)/7, height:50)
}
    

func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
    

func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
    

func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets.zero
}
    

}

奖励: 当设备旋转时处理:

  override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {
super.willTransition(to: newCollection, with: coordinator)
// Have the collection view re-layout its cells.
coordinator.animate(
alongsideTransition: { _ in self.horizontalCV.collectionViewLayout.invalidateLayout() },
completion: { _ in }
)
}