Come impostare la larghezza e l'altezza di UICollectionViewCell a livello di codice


103

Sto cercando di implementare un file CollectionView. Quando utilizzo il layout automatico, le mie celle non cambieranno le dimensioni, ma il loro allineamento.

Ora preferirei cambiare le loro dimensioni ad es

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

Ho provato a impostare nel mio file CellForItemAtIndexPath

collectionCell.size = size

non ha funzionato però.

C'è un modo per raggiungere questo obiettivo?

modifica :

Sembra che le risposte cambieranno solo la larghezza e l'altezza stessa di CollectionView. È possibile un conflitto nei vincoli? Qualche idea su questo?

Risposte:


267

Usa questo metodo per impostare la larghezza dell'altezza della cella personalizzata.

Assicurati di aggiungere questi protocolli

UICollectionViewDelegate

UICollectionViewDataSource

UICollectionViewDelegateFlowLayout

Se stai usando swift 5 o xcode 11 e versioni successive, devi impostare Estimate Sizel' noneuso dello storyboard per farlo funzionare correttamente. Se non lo imposti, il codice seguente non funzionerà come previsto.

inserisci qui la descrizione dell'immagine

Swift 4 o successivo

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

Obiettivo-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 Ho modificato la mia risposta per favore controlla e fammi sapere se dobbiamo ancora renderlo più chiaro
PinkeshGjr

8
Sono così abituato a fare tutto in modo programmatico che questo mi sembra così estraneo ora. Nello Storyboard l'impostazione Estimated Size su None e l'aggiunta di UICollectionViewDelegateFlowLayout è ciò che fa il trucco
Lance Samaria

5
L'impostazione della dimensione stimata su nessuna ha funzionato per me. Grazie @PinkeshGjr
Mohan

5
sono contento di averlo trovato, ho sprecato 2 ore a inseguirlo solo per imparare la magica 'Stima delle dimensioni a nessuno'
Klajd Deda

3
impostare Dimensioni stimate su nessuno ha salvato i miei giorni.
tounaobun

73

Assicurati di aggiungere il protocollo UICollectionViewDelegateFlowLayoutnella tua classdichiarazione

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

Non dimenticare di utilizzare il layout di flusso e non personalizzato. Allora il tuo è l'unico che ha funzionato per me. Grazie!
Sean

come possiamo dare l'altezza dinamica qui dando un'altezza statica come 100.0
sangavi

65

Se si utilizza lo storyboard e si sovrascrive UICollectionViewDelegateFlowLayout, in swift 5 e Xcode 11 impostare anche la dimensione stimata su Nessuno inserisci qui la descrizione dell'immagine


2
È stato utile. Grazie!!
Naval Hasan

Questo era sicuramente quello che stavo per impazzire. A meno che non lo imposti su none, non sei in grado di vedere la dimensione corretta che hai dato nel metodo sizeForItem.
Yusuf Kamil AK

2
L'impostazione della dimensione della stima su nessuna ha risolto tutto
MMK

2
Thnx ha impostato la dimensione della stima su nessuno risolto dal problema
Salman500

2
Buona soluzione. Ecco la mia diagnosi di questo problema in base alla documentazione di Apple : UICollectionViewFlowLayoutsembra di default estimatedItemSizeper UICollectionViewFlowLayout.automaticSizequando si utilizza IB, anche se la documentazione dice che dovrebbe default CGSizeZero. Come afferma Apple, automaticSize"abilita le celle a ridimensionamento automatico per la visualizzazione della raccolta". Ecco perché altri cambiamenti di dimensione in IB non fanno nulla.
Andrew Kirna,

20

Finalmente ho la risposta. Dovresti estendere UICollectionViewDelegateFlowLayout
Questo dovrebbe funzionare con le risposte sopra.


Puoi scrivere un esempio?
Mamdouh El Nakeeb

In realtà ho fatto un'estensione con entrambi i protocolli datasource e delegateFlowLayout e non ha funzionato. Ciò che ha funzionato è stato separare la parte FlowLayout in un'estensione propria. Non so perché, ma ha funzionato in swift 3.
Skywalker

15

swift 4.1

Hai 2 modi per cambiare la dimensione di CollectionView.
Primo modo -> aggiungi questo protocollo UICollectionViewDelegateFlowLayout
per Nel mio caso voglio dividere la cella in 3 parti in una riga. Ho fatto questo codice di seguito

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

Secondo modo -> non devi aggiungere UICollectionViewDelegateFlowLayout ma devi scrivere del codice nella funzione viewDidload invece come codice sotto

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

Qualunque cosa tu scriva un codice come primo o secondo modo, otterrai lo stesso risultato di cui sopra. L'ho scritto io. Ha funzionato per me

inserisci qui la descrizione dell'immagine


2
Direttamente da raywenderlich.com 😂
Andrew Kirna

12

Rapporto dimensioni in base alle dimensioni dell'iPhone:

Ecco cosa puoi fare per avere larghezza e altezza diverse per le celle riguardo alle dimensioni dell'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 forse dovresti anche disabilitare i vincoli di AutoLayout sulla cella affinché questa risposta funzioni.


Ho provato questo e tutte le soluzioni di cui sopra ma i contenuti in una cella non si ridimensionano automaticamente, come posso risolvere questo problema
Biasi Wiga

7

La vista collezione ha un layout di oggetto. Nel tuo caso, è probabilmente un layout di flusso ( UICollectionViewFlowLayout ). Imposta la itemSizeproprietà del layout di flusso .


Ho provato questo. mi dà lo stesso problema di prima. in qualche modo il mio CollectionView cambia le sue dimensioni piuttosto che le mie celle.
JVS

2
Bene, tutto dipende da quando lo fai. Non hai mostrato il tuo vero codice, quindi chissà cosa stai facendo? Ti assicuro che funziona.
matt

7

in Swift3 e Swift4 puoi cambiare la dimensione della cella aggiungendo UICollectionViewDelegateFlowLayout e implementandolo in questo modo:

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

o se crei UICollectionView a livello di codice puoi farlo in questo modo:

    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 collection view collectionview example xcode ultimo codice di esempio funzionante

Aggiungilo nella sezione Delegato in alto

UICollectionViewDelegateFlowLayout

e utilizzare questa funzione

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

///// codice completo di esempio

create nella visualizzazione della raccolta e nella cella collectionview nello storyboard fare riferimento alla raccolta come
@IBOutlet weak var cvContent: UICollectionView!

incollalo nel controller di visualizzazione

 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

Prova sotto il metodo

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

2

Swift 5 a livello di programmazione

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, modo assolutamente semplice:

class YourCollection: UIViewController,
     UICollectionViewDelegate,
     UICollectionViewDataSource {

Devi aggiungere "UICollectionViewDelegateFlowLayout" oppure non è presente il completamento automatico:

class YourCollection: UIViewController,
     UICollectionViewDelegate,
     UICollectionViewDataSource,
     UICollectionViewDelegateFlowLayout {

Digita "sizeForItemAt ...". Hai finito!

class YourCollection: UIViewController,
     UICollectionViewDelegate,
     UICollectionViewDataSource,
     UICollectionViewDelegateFlowLayout {

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

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

Questo è tutto.

Esempio, se vuoi che "ogni cella riempia l'intera vista della raccolta":

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

0

Un altro modo è impostare il valore direttamente nel layout di flusso

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

0

Quindi è necessario impostare dallo storyboard per l'attributo per collectionView nella stima della sezione della cella Size a nessuno e nel ViewController è necessario disporre di un metodo delegato per l'implementazione di questo metodo: optional func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize


0

Prova a utilizzare il metodo UICollectionViewDelegateFlowLayout. In Xcode 11 o versioni successive, è necessario impostare Dimensioni stimate su nessuna dallo 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

Un modo semplice:

Se hai solo bisogno di una semplice dimensione fissa :

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

È tutto quello che c'è da fare.

Nello storyboard, cambia semplicemente la classe da UICollectionView a SizedCollectionView.

Ma !!!

Notare che la classe di base è "UI 'I' CollectionView". "I" per inizializzatore.

Non è così facile aggiungere un inizializzatore a una visualizzazione raccolta. Ecco un approccio comune:

Vista raccolta ... con inizializzatore:

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

Nella maggior parte dei progetti, è necessaria "una vista della raccolta con un inizializzatore". Quindi probabilmente avrai comunque UIICollectionView(nota la I extra per Initializer!) Nel tuo progetto.


0

Swift 5, impostazione programmatica di UICollectionView Larghezza e altezza della cella

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

Questa è la mia versione, trova il rapporto adatto per ottenere le dimensioni della cella secondo le tue esigenze.

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath 
{ 
return CGSizeMake(CGRectGetWidth(collectionView.frame)/4, CGRectGetHeight(collectionView.frame)/4); 
} 
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.