Como definir UICollectionViewCell Width e Height programaticamente


100

Estou tentando implementar um CollectionView. Quando estou usando o Autolayout, minhas células não mudam o tamanho, mas o alinhamento.

Agora, prefiro alterar seus tamanhos para, por exemplo,

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

Eu tentei definir no meu CellForItemAtIndexPath

collectionCell.size = size

não funcionou embora.

Existe uma maneira de conseguir isso?

editar :

Parece que as respostas só mudarão a largura e a altura da minha CollectionView. Existe conflito nas restrições possíveis? Alguma ideia sobre isso?

Respostas:


257

Use este método para definir a largura da altura da célula personalizada.

Certifique-se de adicionar estes protocolos

UICollectionViewDelegate

UICollectionViewDataSource

UICollectionViewDelegateFlowLayout

Se você estiver usando rápida 5 ou xcode 11 e, posteriormente, você precisa definir Estimate Sizea noneusar storyboard, a fim de fazê-lo funcionar corretamente. Se você não definir isso, o código abaixo não funcionará conforme o esperado.

insira a descrição da imagem aqui

Swift 4 ou posterior

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

1
@RamyAlZuhouri Editou minha resposta. Por favor, verifique e me avise se ainda precisarmos torná-la mais clara
PinkeshGjr

8
Estou tão acostumado a fazer tudo programaticamente que agora isso parece tão estranho para mim. No Storyboard, definir o tamanho estimado como Nenhum e adicionar o UICollectionViewDelegateFlowLayout é o que faz o truque
Lance Samaria

5
Definir o tamanho da estimativa como nenhum funcionou para mim. Obrigado @PinkeshGjr
Mohan

5
Estou feliz por ter encontrado isso, perdi 2 horas perseguindo isso apenas para aprender o mágico 'Tamanho estimado para nenhum'
Klajd Deda

3
definir o tamanho estimado para nenhum salvou meus dias.
tounaobun 01 de

73

Certifique-se de adicionar o protocolo UICollectionViewDelegateFlowLayoutem sua classdeclaração

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

Não se esqueça de usar layout de fluxo e não customizado. Então o seu é o único que funcionou para mim. Obrigado!
Sean

como podemos dar altura dinâmica aqui dando altura estática como 100,0
sangavi

62

Se alguém estiver usando storyboard e substituindo UICollectionViewDelegateFlowLayout , em swift 5 e Xcode 11 também defina o tamanho da estimativa como Nenhum insira a descrição da imagem aqui


1
Isso foi útil. Obrigado!!
Naval Hasan

Isso era definitivamente o que eu estava prestes a enlouquecer. A menos que você defina como nenhum, você não consegue ver o tamanho correto que você forneceu no método sizeForItem.
Yusuf Kamil AK

1
Definir o tamanho estimado como nenhum corrigiu tudo
MMK

1
Thnx definindo tamanho estimado para nenhum corrigido pelo problema
Salman500 de

2
Boa solução. Aqui está o meu diagnóstico desse problema de acordo com a documentação da Apple : UICollectionViewFlowLayoutparece ser o padrão estimatedItemSizeao UICollectionViewFlowLayout.automaticSizeusar o IB, embora a documentação diga que deveria CGSizeZero. Como afirma a Apple, automaticSize"habilita células autodimensionadas para a visualização de sua coleção". É por isso que outras alterações de tamanho no IB não fazem nada.
Andrew Kirna

20

Finalmente obtive a resposta. Você deve estender UICollectionViewDelegateFlowLayout
Isso deve estar funcionando com as respostas acima.


Você poderia escrever um exemplo?
Mamdouh El Nakeeb,

Na verdade fiz uma extensão com os protocolos datasource e delegateFlowLayout e não funcionou. O que funcionou foi separar a parte do FlowLayout em uma extensão própria. Não sei por que, mas funcionou no swift 3.
Skywalker

15

rápido 4.1

Você tem 2 maneiras de alterar o tamanho de CollectionView.
Primeira forma -> adicione este protocolo UICollectionViewDelegateFlowLayout
para No meu caso, quero dividir a célula em 3 partes em uma linha. Eu fiz este código abaixo

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

Segunda forma -> você não precisa adicionar UICollectionViewDelegateFlowLayout, mas precisa escrever algum código na função viewDidload em vez de como código abaixo

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

O que quer que você escreva um código como a primeira ou segunda maneira, você obterá o mesmo resultado acima. Eu escrevi. Funcionou para mim

insira a descrição da imagem aqui


2
Direto de raywenderlich.com 😂
Andrew Kirna

11

Proporção de tamanho de acordo com o tamanho do iPhone:

Aqui está o que você pode fazer para ter diferentes larguras e alturas para as células em relação ao tamanho do 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)
}

E talvez você também deva desabilitar suas restrições de AutoLayout na célula para que essa resposta funcione.


Eu tentei isso e todas as soluções acima, mas o conteúdo de uma célula não está sendo
redimensionado automaticamente

7

A visualização da coleção possui um objeto de layout . No seu caso, provavelmente é um layout de fluxo ( UICollectionViewFlowLayout ). Defina a itemSizepropriedade do layout de fluxo .


Tentei isso. me dá o mesmo problema de antes. de alguma forma, meu CollectionView muda seu tamanho em vez de minhas células.
JVS

2
Bem, tudo depende de quando você faz isso. Você não mostrou seu código real, então quem sabe o que você está fazendo? Garanto que funciona.
matt

7

em Swift3 e Swift4 você pode alterar o tamanho da célula adicionando UICollectionViewDelegateFlowLayout e implementando assim:

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

ou se criar UICollectionView programaticamente, você pode fazer assim:

    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)

4

swift4 swift 4 ios coleção ver exemplo de coleção ver exemplo de xcode último código de trabalho

Adicione isto na seção Delegado do topo

UICollectionViewDelegateFlowLayout

e usar esta função

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

///// amostra de código completo

criar na visualização da coleção e a célula da visualização da coleção no storyboard dão referência à coleção como
@IBOutlet fraco var cvContent: UICollectionView!

cole isso no controlador de visualização

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

2

Experimente o método abaixo

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

2

Swift 5 programaticamente

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

1
**Swift 5**
To make this work you have to do the following.

Add these protocols

 - UICollectionViewDelegate


 - UICollectionViewDataSource


 - UICollectionViewDelegateFlowLayout

Your code will then look like this

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

Now the final and crucial step to see this take effect is to go to your viedDidLoad function inside your Viewcontroller.

    override func viewDidLoad() {
        super.viewDidLoad()
        collection.dataSource = self // Add this
        collection.delegate = self // Add this

        // Do any additional setup after loading the view.
    }

Without telling your view which class the delegate is it won't work.

1

2020, maneira absolutamente simples:

class YourCollection: UIViewController,
     UICollectionViewDelegate,
     UICollectionViewDataSource {

Você deve adicionar "UICollectionViewDelegateFlowLayout" ou não há preenchimento automático:

class YourCollection: UIViewController,
     UICollectionViewDelegate,
     UICollectionViewDataSource,
     UICollectionViewDelegateFlowLayout {

Digite "sizeForItemAt ...". Você Terminou!

class YourCollection: UIViewController,
     UICollectionViewDelegate,
     UICollectionViewDataSource,
     UICollectionViewDelegateFlowLayout {

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

     return CGSize(width: 37, height: 63)
}

É isso aí.

Exemplo, se você quiser "cada célula preenche a visualização da coleção inteira":

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

0

Outra maneira é definir o valor diretamente no layout de fluxo

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

0

Portanto, você precisa definir a partir do storyboard para o atributo para collectionView na seção de célula, estimar o tamanho para nenhum, e em seu ViewController você precisa ter um método delegado para implementar este método: optional func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize


0

Tente usar o método UICollectionViewDelegateFlowLayout. No Xcode 11 ou posterior, você precisa definir o tamanho estimado para nenhum no storyboard.

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

0

Uma maneira simples:

Se você só precisa de um tamanho fixo simples :

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

Isso é tudo que há para fazer.

No storyboard, basta alterar a classe de UICollectionView para SizedCollectionView.

Mas !!!

Observe que a classe base é "UI 'I' CollectionView". 'I' para inicializador.

Não é tão fácil adicionar um inicializador a uma visão de coleção. Esta é uma abordagem comum:

Visualização da coleção ... com inicializador:

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

Na maioria dos projetos, você precisa de "uma visão de coleção com um inicializador". Portanto, você provavelmente terá UIICollectionView(observe o I extra para Initializer!) Em seu projeto.


0

Swift 5, configuração de UICollectionView programática Largura e altura da célula

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

-4

Esta é a minha versão, encontre sua proporção adequada para obter o tamanho da célula de acordo com sua necessidade.

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath 
{ 
return CGSizeMake(CGRectGetWidth(collectionView.frame)/4, CGRectGetHeight(collectionView.frame)/4); 
} 
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.