Как установить интервал между ячейками и 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
    }
}
Marko
источник
Вот ваше решение. Спасибо.
Джану Кансагра
Вот рабочий код для 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, но не знаю, как изменить размер макета только для одного элемента). Ширина первого элемента должна быть равна screenWidth .
Марко
1
Привет, у меня та же проблема, но я хочу знать аналогичное название функции в Objective C.
Нада Гамаль
1
Хорошо, теперь работает нормально, спасибо большое :) Функция C:: (CGSize) collectionView: (UICollectionView ) collectionView макет: (UICollectionViewLayout ) collectionViewLayout sizeForItemAtIndexPath: (NSIndexPath *) indexPath {вернуть CGSizeMake (screenWidth / 3, screenWidth / 3) ); }
Нада Гамаль
4
спасибо за отличный ответ @greentor. отправил награду. Не забудьте коллекцию ViewView! .CollectionViewLayout = layout , читатели
Толстяк
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.

Установка UICollectionViewFlowLayoutin 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
    }
}
Maor
источник
Отличный ответ! Это определенно 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.

Дхармендра Качхадия
источник
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

Для 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
Как принять во внимание тот факт, что у вас есть несколько разделов
Nikhil Pandey
это только для 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: Для равномерно распределенных пространств между ячейками с динамической шириной ячеек, чтобы максимально использовать пространство контейнера, вы можете использовать фрагмент кода ниже, предоставив значение minimalCellWidth .

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
}
Дениз Ялцин
источник