Come impostare la spaziatura delle celle e UICollectionView - UICollectionViewFlowLayout ratio size?


137

Sto provando ad aggiungere UICollectionViewa ViewController, e ho bisogno di avere 3 celle 'per riga' senza spazio vuoto tra le celle (dovrebbe apparire come una griglia). La larghezza della cella dovrebbe essere un terzo della dimensione dello schermo, quindi ho pensato che la layout.itemlarghezza dovrebbe essere la stessa. Ma poi ottengo questo:

layout.itemSize larghezza = screenSize.width / 3

Se riduco quella dimensione (ad esempio di 7 o 8 pixel ), è meglio, ma la terza cella in riga non è completamente visibile e ho ancora quello spazio vuoto (in alto e in basso, e a sinistra e a destra).

inserisci qui la descrizione dell'immagine

class ViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
    var collectionView: UICollectionView?
    var screenSize: CGRect!
    var screenWidth: CGFloat!
    var screenHeight: CGFloat!

    override func viewDidLoad() {
        super.viewDidLoad()

        screenSize = UIScreen.mainScreen().bounds
        screenWidth = screenSize.width
        screenHeight = screenSize.height

        // Do any additional setup after loading the view, typically from a nib
        let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
        layout.sectionInset = UIEdgeInsets(top: 20, left: 0, bottom: 10, right: 0)
        layout.itemSize = CGSize(width: screenWidth / 3, height: screenWidth / 3)
        collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
        collectionView!.dataSource = self
        collectionView!.delegate = self
        collectionView!.registerClass(CollectionViewCell.self, forCellWithReuseIdentifier: "CollectionViewCell")
        collectionView!.backgroundColor = UIColor.greenColor()
        self.view.addSubview(collectionView!)
    }

    func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
        return 1
    }

    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 20
    }

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("CollectionViewCell", forIndexPath: indexPath) as CollectionViewCell
        cell.backgroundColor = UIColor.whiteColor()
        cell.layer.borderColor = UIColor.blackColor().CGColor
        cell.layer.borderWidth = 0.5
        cell.frame.size.width = screenWidth / 3
        cell.frame.size.height = screenWidth / 3

        cell.textLabel?.text = "\(indexPath.section):\(indexPath.row)"
        return cell
    }
}

Ecco la tua soluzione Grazie.
janu kansagra,

Ecco codice di lavoro per Swift 4 stackoverflow.com/a/54703798/10150796
Nikunj Kumbhani

Risposte:


299

Aggiungi queste 2 righe

layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0

Quindi hai:

   // Do any additional setup after loading the view, typically from a nib.
        let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
        layout.sectionInset = UIEdgeInsets(top: 20, left: 0, bottom: 10, right: 0)
        layout.itemSize = CGSize(width: screenWidth/3, height: screenWidth/3)
        layout.minimumInteritemSpacing = 0
        layout.minimumLineSpacing = 0
        collectionView!.collectionViewLayout = layout

Ciò rimuoverà tutti gli spazi e ti darà un layout a griglia:

inserisci qui la descrizione dell'immagine

Se si desidera che la prima colonna abbia una larghezza uguale alla larghezza dello schermo, aggiungere la seguente funzione:

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
    if indexPath.row == 0
    {
        return CGSize(width: screenWidth, height: screenWidth/3)
    }
    return CGSize(width: screenWidth/3, height: screenWidth/3);

}

Il layout della griglia ora apparirà (ho anche aggiunto uno sfondo blu alla prima cella): inserisci qui la descrizione dell'immagine


Grazie mille, mi aspettavo qualcosa di molto più complicato e ci ho dedicato molto tempo. Grazie ancora una volta
Marko,

E solo un'altra cosa, c'è qualche possibilità di cambiare layout.itemSize solo per la prima cella? (So ​​che devo cambiare cell.frame.size quando indexPath.row è 0, ma non so come modificare la dimensione del layout solo per un elemento) La larghezza del primo elemento dovrebbe essere uguale a screenWidth .
Marko,

1
Salve, ho lo stesso problema ma voglio conoscere il titolo della funzione simile nell'Obiettivo C.
Nada Gamal,

1
Ok, funziona benissimo ora, Grazie mille :) funzione di Objective C: - (CGSize) CollectionView: (UICollectionView layout) CollectionView: (UICollectionViewLayout ) collectionViewLayout sizeForItemAtIndexPath: (NSIndexPath *) {return indexPath CGSizeMake (screenwidth / 3, screenwidth / 3 ); }
Nada Gamal,

4
grazie per l'ottima risposta @greentor. ha inviato una taglia. Non dimenticare la collezioneView! .CollectionViewLayout = layout , lettori
Fattie,

47

Per Swift 3 e XCode 8 , ha funzionato. Seguire i passaggi seguenti per raggiungere questo obiettivo: -

{
    let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
    let width = UIScreen.main.bounds.width
    layout.sectionInset = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
    layout.itemSize = CGSize(width: width / 2, height: width / 2)
    layout.minimumInteritemSpacing = 0
    layout.minimumLineSpacing = 0
    collectionView!.collectionViewLayout = layout
}

Inserire questo codice nella funzione viewDidLoad ().


32

In alcune situazioni, l'impostazione di UICollectionViewFlowLayoutin viewDidLoado ViewWillAppearpotrebbe non avere effetto su collectionView.

L'impostazione di UICollectionViewFlowLayoutin viewDidAppearpuò causare le modifiche delle dimensioni delle celle in fase di esecuzione.

Un'altra soluzione, in Swift 3:

extension YourViewController : UICollectionViewDelegateFlowLayout{

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsets(top: 20, left: 0, bottom: 10, right: 0)
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let collectionViewWidth = collectionView.bounds.width
        return CGSize(width: collectionViewWidth/3, height: collectionViewWidth/3)
    }

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

Bella risposta! Questo è sicuramente il modo Apple per farlo. Ora, non ti capita di sapere come aggiornare quando il dispositivo cambia orientamento, vero?
jlstr,

17

Se stai cercando Swift 3, segui i passaggi per raggiungere questo obiettivo:

func viewDidLoad() {

    //Define Layout here
    let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()

    //Get device width
    let width = UIScreen.main.bounds.width

    //set section inset as per your requirement.
    layout.sectionInset = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)

    //set cell item size here 
    layout.itemSize = CGSize(width: width / 2, height: width / 2)

    //set Minimum spacing between 2 items
    layout.minimumInteritemSpacing = 0

    //set minimum vertical line spacing here between two lines in collectionview
    layout.minimumLineSpacing = 0

    //apply defined layout to collectionview
    collectionView!.collectionViewLayout = layout

}

Questo è verificato su Xcode 8.0 con Swift 3.


8
let layout = myCollectionView.collectionViewLayout as? UICollectionViewFlowLayout
layout?.minimumLineSpacing = 8

4

Swift 4

let collectionViewLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout
collectionViewLayout?.sectionInset = UIEdgeInsetsMake(0, 20, 0, 40) 
collectionViewLayout?.invalidateLayout()

1

Per Swift 3 e XCode 8, ha funzionato. Seguire i passaggi seguenti per raggiungere questo obiettivo: -

viewDidLoad()
    {
        let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
        var width = UIScreen.main.bounds.width
        layout.sectionInset = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
    width = width - 10
    layout.itemSize = CGSize(width: width / 2, height: width / 2)
        layout.minimumInteritemSpacing = 0
        layout.minimumLineSpacing = 0
        collectionView!.collectionViewLayout = layout
    }

3
Come tenere conto del fatto se hai più sezioni
Nikhil Pandey,

è solo per 1 colonna (sezione)
user924

0

Per Swift 3+ e Xcode 9+ Prova a utilizzare questo

extension ViewController: UICollectionViewDelegateFlowLayout {

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

    let collectionWidth = collectionView.bounds.width
    return CGSize(width: collectionWidth/3, height: collectionWidth/3)

}

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

}

0

Swift 5: per spazi distribuiti uniformemente tra celle con larghezza di cella dinamica per sfruttare al meglio lo spazio contenitore, è possibile utilizzare lo snippet di codice riportato di seguito fornendo un valore minimoCellWidth .

private func collectionViewLayout() -> UICollectionViewLayout {
    
    let layout = UICollectionViewFlowLayout()
    layout.sectionHeadersPinToVisibleBounds = true
    // Important: if direction is horizontal use minimumItemSpacing instead. 
    layout.scrollDirection = .vertical
    
    let itemHeight: CGFloat = 240
    let minCellWidth :CGFloat = 130.0
    let minItemSpacing: CGFloat = 10
    let containerWidth: CGFloat = self.view.bounds.width
    let maxCellCountPerRow: CGFloat =  floor((containerWidth - minItemSpacing) / (minCellWidth+minItemSpacing ))
    
    let itemWidth: CGFloat = floor( ((containerWidth - (2 * minItemSpacing) - (maxCellCountPerRow-1) * minItemSpacing) / maxCellCountPerRow  ) )
    // Calculate the remaining space after substracting calculating cellWidth (Divide by 2 because of left and right insets)
    let inset = max(minItemSpacing, floor( (containerWidth - (maxCellCountPerRow*itemWidth) - (maxCellCountPerRow-1)*minItemSpacing) / 2 ) )

    
    layout.itemSize = CGSize(width: itemWidth, height: itemHeight)
    layout.minimumInteritemSpacing = min(minItemSpacing,inset)
    layout.minimumLineSpacing = minItemSpacing
    layout.sectionInset = UIEdgeInsets(top: minItemSpacing, left: inset, bottom: minItemSpacing, right: inset)

    
    return layout
}
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.