Comment définir la largeur et la hauteur UICollectionViewCell par programmation

103

J'essaye d'implémenter un CollectionView. Lorsque j'utilise Autolayout, mes cellules ne changeront pas la taille, mais leur alignement.

Maintenant, je préfère changer leurs tailles par exemple

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

J'ai essayé de mettre dans mon CellForItemAtIndexPath

collectionCell.size = size

cela n'a pas fonctionné cependant.

Y a-t-il un moyen d'y parvenir?

modifier :

Il semble que les réponses ne changeront que la largeur et la hauteur de ma CollectionView. Y a-t-il des conflits possibles dans les contraintes? Des idées là-dessus?

JVS
la source

Réponses:

267

Utilisez cette méthode pour définir la largeur de hauteur de cellule personnalisée.

Assurez-vous d'ajouter ces protocoles

UICollectionViewDelegate

UICollectionViewDataSource

UICollectionViewDelegateFlowLayout

Si vous utilisez rapide 5 ou Xcode 11 et plus tard , vous devez définir Estimate Sizeà l' noneaide de story - board pour le faire fonctionner correctement. Si vous ne le définissez pas, le code ci-dessous ne fonctionnera pas comme prévu.

entrez la description de l'image ici

Swift 4 ou version ultérieure

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

Objectif 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
la source
1
@RamyAlZuhouri a modifié ma réponse, veuillez vérifier et laissez-moi savoir si nous devons encore clarifier les
choses
8
J'ai tellement l'habitude de tout faire par programmation que cela me semble si étranger maintenant. Dans Storyboard, définir la taille estimée sur None et ajouter le UICollectionViewDelegateFlowLayout est ce qui fait l'affaire
Lance Samaria
5
Définir la taille estimée à aucun a fonctionné pour moi. Merci @PinkeshGjr
Mohan
5
Je suis content d'avoir trouvé ça, j'ai perdu 2 heures à courir après ça pour apprendre la magie `` Estimer la taille à aucune ''
Klajd Deda le
3
définir la taille estimée sur aucun a sauvé mes jours.
tounaobun le
73

Assurez-vous d'ajouter le protocole UICollectionViewDelegateFlowLayoutdans votre classdéclaration

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
la source
N'oubliez pas d'utiliser la disposition de flux et non personnalisée. Alors le vôtre est le seul qui a fonctionné pour moi. Merci!
Sean
comment pouvons-nous donner une hauteur dynamique ici donnant une hauteur statique de 100,0
sangavi
65

Si vous utilisez un storyboard et remplacez UICollectionViewDelegateFlowLayout, dans swift 5 et Xcode 11, définissez également la taille d'estimation sur Aucune entrez la description de l'image ici

Spydy
la source
2
Cela a été utile. Merci!!
Naval Hasan
C'était définitivement ce que j'allais devenir fou. Sauf si vous le définissez sur aucun, vous ne pouvez pas voir la taille correcte que vous avez indiquée dans la méthode sizeForItem.
Yusuf Kamil AK
2
La définition de la taille de l'estimation sur aucun a tout corrigé
MMK
2
Thnx définissant la taille estimée à aucune corrigée par problème
Salman500
2
Bonne solution. Voici mon diagnostic de cette question selon la documentation d'Apple : UICollectionViewFlowLayoutsemble par défaut estimatedItemSizeà UICollectionViewFlowLayout.automaticSizel'utilisation de IB , même si la documentation indique qu'il devrait par défaut CGSizeZero. Comme le déclare Apple, automaticSize«active les cellules auto-dimensionnées pour votre vue de collection». C'est pourquoi les autres changements de taille dans IB ne font rien.
Andrew Kirna
20

J'ai enfin la réponse. Vous devriez étendre UICollectionViewDelegateFlowLayout
Cela devrait fonctionner avec les réponses ci-dessus.

saburo
la source
Pouvez-vous écrire un exemple?
Mamdouh El Nakeeb
En fait, j'ai fait une extension avec les protocoles datasource et delegateFlowLayout et cela n'a pas fonctionné. Ce qui fonctionnait, c'était de séparer la partie FlowLayout en une extension qui lui était propre. Je ne sais pas pourquoi, mais cela a fonctionné dans Swift 3.
Skywalker
15

rapide 4.1

Vous avez 2 façons de changer la taille de CollectionView.
Première façon -> ajouter ce protocole UICollectionViewDelegateFlowLayout
pour Dans mon cas, je veux diviser la cellule en 3 parties sur une ligne. J'ai fait ce code ci-dessous

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

Deuxième manière -> vous n'avez pas besoin d'ajouter UICollectionViewDelegateFlowLayout mais vous devez écrire du code dans la fonction viewDidload à la place comme code ci-dessous

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

Quoi que vous écriviez un code comme première ou seconde façon, vous obtiendrez le même résultat que ci-dessus. Je l'ai écrit. Ça a marché pour moi

entrez la description de l'image ici

Sup.Ia
la source
2
Directement de raywenderlich.com 😂
Andrew Kirna
12

Rapport de taille selon la taille de l'iPhone:

Voici ce que vous pouvez faire pour avoir une largeur et une hauteur différentes pour les cellules en fonction de la taille de l'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)
}

Et peut-être que vous devriez également désactiver vos contraintes de mise en page automatique sur la cellule pour que cette réponse fonctionne.

AnthoPak
la source
J'ai essayé ceci et toutes les solutions ci-dessus mais le contenu d'une cellule ne se redimensionnait pas automatiquement, comment puis-je résoudre ce problème
Biasi Wiga
7

La vue de collection a un objet de mise en page . Dans votre cas, il s'agit probablement d'une disposition de flux ( UICollectionViewFlowLayout ). Définissez la itemSizepropriété de la disposition du flux .

mat
la source
J'ai essayé ça. me donne le même problème qu'avant. en quelque sorte ma CollectionView change sa taille plutôt que mes cellules.
JVS
2
Eh bien, tout dépend du moment où vous le faites. Vous n'avez pas montré votre vrai code, alors qui sait ce que vous faites? Je vous assure que cela fonctionne.
mat
7

dans Swift3 et Swift4, vous pouvez modifier la taille de cellule en ajoutant UICollectionViewDelegateFlowLayout et en implémentant c'est comme ceci:

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

ou si vous créez UICollectionView par programme, vous pouvez le faire comme ceci:

    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
la source
4

swift4 swift 4 ios collection vue collectionview exemple xcode dernier code de travail échantillon

Ajoutez ceci dans la section Délégué du haut

UICollectionViewDelegateFlowLayout

et utilisez cette fonction

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

///// exemple de code complet

create on collection view et collectionview cell dans storyboard donnent la référence à la collection comme
@IBOutlet faible var cvContent: UICollectionView!

collez ceci dans le contrôleur de vue

 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
la source
2

Essayez la méthode ci-dessous

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

Swift 5 par programmation

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
la source
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
la source
1

2020, manière absolument simple:

class YourCollection: UIViewController,
     UICollectionViewDelegate,
     UICollectionViewDataSource {

Vous devez ajouter "UICollectionViewDelegateFlowLayout" ou, il n'y a pas de saisie semi-automatique:

class YourCollection: UIViewController,
     UICollectionViewDelegate,
     UICollectionViewDataSource,
     UICollectionViewDelegateFlowLayout {

Tapez "sizeForItemAt ...". Vous avez terminé!

class YourCollection: UIViewController,
     UICollectionViewDelegate,
     UICollectionViewDataSource,
     UICollectionViewDelegateFlowLayout {

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

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

C'est tout.

Exemple, si vous voulez "chaque cellule remplit toute la vue de collection":

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

Une autre méthode consiste à définir la valeur directement dans la disposition du flux

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

Vous devez donc définir à partir du storyboard pour l'attribut pour la collectionView dans l'estimation de la section de cellule Size sur none, et dans votre ViewController, vous devez avoir une méthode déléguée pour implémenter cette méthode: optional func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize

dgalluccio
la source
0

Essayez d'utiliser la méthode UICollectionViewDelegateFlowLayout. Dans Xcode 11 ou version ultérieure, vous devez définir la taille estimée sur aucune à partir du 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
la source
0

Une manière simple:

Si vous avez juste besoin d'une taille fixe simple :

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

C'est tout ce qu'on peut en dire.

Dans le storyboard, changez simplement la classe de UICollectionView à SizedCollectionView.

Mais !!!

Notez que la classe de base est "UI 'I' CollectionView". «I» pour Initializer.

Il n'est pas si simple d'ajouter un initialiseur à une vue de collection. Voici une approche courante:

Vue de collection ... avec initialiseur:

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

Dans la plupart des projets, vous avez besoin d'une "vue de collection avec un initialiseur". Donc, vous aurez probablement de toute façon UIICollectionView(notez le I supplémentaire pour Initializer!) Dans votre projet.

Fattie
la source
0

Swift 5, paramètre UICollectionView programmatique Largeur et hauteur de cellule

// 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
la source
-4

Ceci est ma version, trouvez votre ratio approprié pour obtenir la taille de la cellule selon vos besoins.

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