Як встановити інтервал між клітинками та співвідношення розмірів UICollectionView - UICollectionViewFlowLayout?


137

Я намагаюся додати UICollectionViewдо ViewController, і мені потрібно мати 3 осередки «на рядок» без порожнього простору між осередками (він повинен виглядати як сітка). Ширина комірки повинна становити третину розміру екрана, тому я вважав, що layout.itemширина повинна бути однаковою. Але тоді я отримую це:

layout.itemSize width = screenSize.width / 3

Якщо я зменшу цей розмір (на 7 або 8 пікселів, наприклад), це краще, але третя клітинка підряд не повністю видна, і у мене все ще є порожній пробіл (вгорі та внизу, і вліво, і вправо).

введіть тут опис зображення

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

Ось ваше рішення. Дякую.
січень кансагра

Ось робочий код для Swift 4 stackoverflow.com/a/54703798/10150796
Nikunj Kumbhani

Відповіді:


299

Додайте ці 2 рядки

layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0

Отже, у вас є:

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

Це видалить усі пробіли та надасть макет сітки:

введіть тут опис зображення

Якщо ви хочете, щоб перший стовпець мав ширину, рівну ширині екрана, тоді додайте наступну функцію:

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

}

Тепер буде виглядати макет сітки (я також додав синій фон до першої комірки): введіть тут опис зображення


Дякую вам велике, я очікував на щось набагато складніше, і я витратив на це багато часу. Дякую ще раз.
Марко

І ще одне, чи є можливість змінити layout.itemSize лише для першої комірки? (Я знаю, що мені потрібно змінити cell.frame.size, коли indexPath.row дорівнює 0, але не знаю, як змінити розмір макета лише для одного елемента) Ширина першого елемента повинна бути рівною ширині екрану .
Марко

1
Привіт, у мене така ж проблема, але я хочу знати подібну назву функції в Objective C.
Нада Гамаль

1
Гаразд, це працює нормально, спасибі :) Завдяки функції C: - (CGSize) collectionView: (UICollectionView ) collectionView макет: (UICollectionViewLayout ) collectionViewLayout sizeForItemAtIndexPath: (NSIndexPath *) indexPath {return CGSizeMake (screenWidth / Ширина екрана 3 3 ); }
Нада Гамаль

4
дякую за чудову відповідь @greentor. відправив щедроту. Не забудьте collectionView! .CollectionViewLayout = макет , читачі
Fattie

47

Для Swift 3 та XCode 8 це спрацювало. Виконайте нижче кроки, щоб досягти цього:

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

Розмістіть цей код у функції viewDidLoad ().


32

У деяких ситуаціях, Установка UICollectionViewFlowLayoutв viewDidLoadабоViewWillAppear не може вплинути на CollectionView.

Встановлення UICollectionViewFlowLayoutвviewDidAppear може викликати побачити зміни розмірів осередків в режимі виконання.

Ще одне рішення у 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
    }
}

Чудова відповідь! Це, безумовно, спосіб Apple зробити це. Тепер ви не знаєте, як оновити, коли пристрій змінює орієнтацію, чи не так?
jlstr

17

Якщо ви шукаєте Swift 3, виконайте кроки, щоб досягти цього:

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

}

Це підтверджено на Xcode 8.0 за допомогою Swift 3.



4

Швидкий 4

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

1

Для Swift 3 та XCode 8 це спрацювало. Виконайте нижче кроки, щоб досягти цього:

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
Як взяти до уваги той факт, якщо у вас є кілька розділів
Нікхіл Пандей

це лише для 1 стовпця (розділу)
user924

0

Для Swift 3+ та Xcode 9+ спробуйте скористатися цим

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: Для рівномірно розподілених просторів між клітинками з динамічною шириною комірок, щоб максимально використовувати контейнерний простір, ви можете використовувати фрагмент коду нижче, надавши значення мінімальної ширини ширини .

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
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.