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?

JVS
fonte

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)));
}
PinkeshGjr
fonte
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)
    }
}
pierre23
fonte
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

Spydy
fonte
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.

saburo
fonte
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

Sup.Ia
fonte
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.

AnthoPak
fonte
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 .

mate
fonte
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)
Mohsen mokhtari
fonte
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
    }
}
Ullas Pujary
fonte
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)
}
Nilesh Patel
fonte
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)
    }()
Shubham Mishra
fonte
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.
Taka
fonte
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)
Fattie
fonte
0

Outra maneira é definir o valor diretamente no layout de fluxo

    let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
    layout.itemSize = CGSize(width: size, height: size)
Antzi
fonte
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

dgalluccio
fonte
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)
}
Muhammad Shariq Hasnain
fonte
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.

Fattie
fonte
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)
        ])
    }
    
}
Suhit Patil
fonte
-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); 
} 
Rahul K Rajan
fonte