Интервал между ячейками в UICollectionView


197

Как установить интервал между ячейками в разделе UICollectionView? Я знаю, что есть свойство, которое minimumInteritemSpacingя установил на 5.0, но интервал не отображается 5.0. Я реализовал метод делегирования потока.

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{

    return 5.0;
}

до сих пор я не получаю желаемого результата. Я думаю, что минимальный интервал. Нет ли способа установить максимальный интервал?

симулятор sc


Вы проверили, входит ли он в метод делегата или нет ..? поставив
точку

да, он входит в делегат, в IB я также установил минимальный интервал между ячейками 5. Но я не думаю, что минимальное пространство - это свойство, которое мне поможет, так как оно просто гарантирует, что минимальное пространство между ячейками должно быть 5, но если в представлении коллекции есть дополнительное пространство, то оно будет использовать это дополнительное пространство. Должно быть что-то вроде максимального расстояния между ячейками
Вишал Сингх

У меня та же проблема. 5px, похоже, не работает. Интересно, что я могу сделать это с UITableView, но не с UICollectionView ...
jerik

Я исправил это, выполнив некоторые вычисления. Я опубликую это завтра. :)
Вишал Сингх,

В 2016 году это так просто: stackoverflow.com/a/28327193/294884
Толстяк

Ответы:


145

Я знаю, что тема старая, но в случае, если кому-то все еще нужен правильный ответ, здесь вам нужно:

  1. Переопределить стандартную схему потока.
  2. Добавьте реализацию следующим образом:

    - (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect {
        NSArray *answer = [super layoutAttributesForElementsInRect:rect];
    
        for(int i = 1; i < [answer count]; ++i) {
            UICollectionViewLayoutAttributes *currentLayoutAttributes = answer[i];
            UICollectionViewLayoutAttributes *prevLayoutAttributes = answer[i - 1];
            NSInteger maximumSpacing = 4;
            NSInteger origin = CGRectGetMaxX(prevLayoutAttributes.frame);
    
            if(origin + maximumSpacing + currentLayoutAttributes.frame.size.width < self.collectionViewContentSize.width) {
                CGRect frame = currentLayoutAttributes.frame;
                frame.origin.x = origin + maximumSpacing;
                currentLayoutAttributes.frame = frame;
            }
        }
        return answer;
    }

где MaximumSpacing может быть установлено любое значение, которое вы предпочитаете. Этот трюк гарантирует, что пространство между ячейками будет ТОЧНО равно MaximumSpacing!


Итак, куда мы это поместим?
Джонни

1
Привет, Джонни, унаследуй от стандартного Flow Layout и просто скопируй и вставь этот метод в свой класс.
iago849

1
Обратите внимание, что вам не нужно делать a mutableCopy: вы не изменяете содержимое массива, а изменяете объекты внутри него.
Брок Боланд

5
возможно я делаю что-то не так или эта идея не работает на 100%, потому что когда я прокручиваю до конца, я вижу, что некоторые ячейки перекрывают друг друга :(
pash3r

2
Отличный пост. Я столкнулся с ошибкой, из-за которой в некоторых обстоятельствах нарушалось форматирование последней строки макета. Чтобы решить, я изменил на ifИ дополнительное условие: if(origin + maximumSpacing + currentLayoutAttributes.frame.size.width < self.collectionViewContentSize.width && currentLayoutAttributes.frame.origin.x > prevLayoutAttributes.frame.origin.x) {
chrisoneiota

190

Поддерживая первоначальный вопрос. Я пытался получить расстояние до 5px, UICollectionViewно это не работает, а также с UIEdgeInsetsMake(0,0,0,0)...

На UITableView я могу сделать это, непосредственно указав координаты x, y в строке ...

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

Вот мой код UICollectionView:

#pragma mark collection view cell layout / size
- (CGSize)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
    return [self getCellSize:indexPath];  // will be w120xh100 or w190x100
    // if the width is higher, only one image will be shown in a line
}

#pragma mark collection view cell paddings
- (UIEdgeInsets)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
    return UIEdgeInsetsMake(0, 0, 0, 0); // top, left, bottom, right
}

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {

    return 5.0;
}

Обновление: Решил мою проблему, с помощью следующего кода.

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

ViewController.m

#import "ViewController.h"
#import "MagazineCell.h" // created just the default class. 

static NSString * const cellID = @"cellID";

@interface ViewController ()

@end

@implementation ViewController

#pragma mark - Collection view
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
    return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return 30;
}

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    MagazineCell *mCell = (MagazineCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath];

    mCell.backgroundColor = [UIColor lightGrayColor];

    return mCell;
}

#pragma mark Collection view layout things
// Layout: Set cell size
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {

    NSLog(@"SETTING SIZE FOR ITEM AT INDEX %d", indexPath.row);
    CGSize mElementSize = CGSizeMake(104, 104);
    return mElementSize;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
    return 2.0;
}

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
    return 2.0;
}

// Layout: Set Edges
- (UIEdgeInsets)collectionView:
(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
   // return UIEdgeInsetsMake(0,8,0,8);  // top, left, bottom, right
    return UIEdgeInsetsMake(0,0,0,0);  // top, left, bottom, right
}

@end

Это гораздо лучший ответ. Посмотрите на обратные вызовы, которые вы можете настроить в UICollectionViewDelegateFlowLayout, и вы увидите, как это можно настроить.
Cynistersix

1
Я думаю, это может работать только тогда, когда ширина элемента + интервал равна ширине uicollectionview.
xi.lin

@JayprakashDubey в настоящее время я не в состоянии быстро. Вы должны попробовать это. Удачи
Иерик

Где вы указываете ширину между ячейками 5px?
UKDataGeek

1
Гораздо лучший ответ, чем принятый, главным образом потому, что создание подкласса UICollectionViewLayout только для переопределения одного метода кажется излишним, и это не тривиальный вопрос, учитывая все другие методы, которые необходимо переопределить.
Золушка

80

Используя горизонтальный макет потока, я также получил интервал в 10 точек между ячейками. Чтобы удалить интервал мне нужно было установить minimumLineSpacingтак же как и minimumInterItemSpacingна ноль.

UICollectionViewFlowLayout *flow = [[UICollectionViewFlowLayout alloc] init];
flow.itemSize = CGSizeMake(cellWidth, cellHeight);
flow.scrollDirection = UICollectionViewScrollDirectionHorizontal;
flow.minimumInteritemSpacing = 0;
flow.minimumLineSpacing = 0;

Кроме того, если все ваши ячейки имеют одинаковый размер, проще и эффективнее установить свойство в макете потока напрямую, а не использовать методы делегата.


34
Удивительно, но минимальный размер строки влияет на горизонтальное пространство между ячейками.
Мэтт H

4
Я тоже, мне нужна горизонтальная прокрутка и нулевой интервал между ячейками, а минимумLineSpacing = 0 является ключом.
Wingzero

3
Я смог получить этот эффект без использования minimumInteritemSpacing. Просто установка minimumLineSpacing = 0на моем горизонтальном макете убрала горизонтальный интервал между элементами.
Ziewvater

1
Если вы думаете об этом, горизонтальное расстояние между элементами - это межстрочный интервал для горизонтально-плавного макета. Межстрочный интервал - это расстояние по вертикали между элементами в типичной вертикальной компоновке.
lancejabr

62

Помните, это минимальный интервал между строками, а не минимальный интервал между элементами или ячейкой. Потому что направление прокрутки вашего collectionView - ГОРИЗОНТАЛЬНОЕ .

Если он вертикальный, то вам нужно установить пространство ячеек или пространство между элементами для горизонтального пространства между ячейками и межстрочный интервал для вертикального пространства между ячейками.

Версия Objective-C

- (CGFloat)collectionView:(UICollectionView *)collectionView
                       layout:(UICollectionViewLayout*)collectionViewLayout
    minimumLineSpacingForSectionAtIndex:(NSInteger)section
    {
        return 20;
    }

Swift версия:

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

теперь нижнее пространство исчезло, когда я вернул 0; как убрать правое боковое пространство?
Бангалор

Эй, я не очень хорошо понял ваш вопрос. Но я думаю, что insetForSectionAtIndex - это то, что вы ищете. - (UIEdgeInsets) collectionView: (UICollectionView *) collectionView макет: (UICollectionViewLayout *) collectionViewLayout insetForSectionAtIndex: (NSInteger) section {return UIEdgeInsetsMake (5, 10, 5, 10); }
Винсент Джой

Это минимальный межстрочный интервал как по горизонтали, так и по вертикали.
Свати

Вы спасли мой день (Y).
Umair_UAS

О, мое слово! Я не могу в это поверить. Спасибо
Магу

36

Попробуйте этот код, чтобы убедиться, что у вас есть интервал 5 пикселей между каждым элементом:

- (UIEdgeInsets)collectionView:(UICollectionView *) collectionView 
                        layout:(UICollectionViewLayout *) collectionViewLayout 
        insetForSectionAtIndex:(NSInteger) section {

    return UIEdgeInsetsMake(0, 0, 0, 5); // top, left, bottom, right
}

- (CGFloat)collectionView:(UICollectionView *) collectionView
                   layout:(UICollectionViewLayout *) collectionViewLayout
  minimumInteritemSpacingForSectionAtIndex:(NSInteger) section {    
    return 5.0;
}

Пожалуйста, отформатируйте ваш код как блок кода, чтобы он хорошо отображался на SO.
Проводник

33

Свифт версия самого популярного ответа. Пространство между клетками будет равно cellSpacing.

class CustomViewFlowLayout : UICollectionViewFlowLayout {

    let cellSpacing:CGFloat = 4

    override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        if let attributes = super.layoutAttributesForElementsInRect(rect) {
        for (index, attribute) in attributes.enumerate() {
                if index == 0 { continue }
                let prevLayoutAttributes = attributes[index - 1]
                let origin = CGRectGetMaxX(prevLayoutAttributes.frame)
                if(origin + cellSpacing + attribute.frame.size.width < self.collectionViewContentSize().width) {
                    attribute.frame.origin.x = origin + cellSpacing
                }
            }
            return attributes
        }
        return nil
    }
}

super.layoutAttributesForElements (in: rect) возвращает ноль, есть идеи?
Ашок Р

Как и все другие методы, которые используют это, это не работает должным образом для нескольких строк. Прерывистые промежутки в стиле ошибок округления останутся между строками, даже если для соответствующих методов и свойств делегата установлено значение 0. Это может быть проблемой рендеринга UICollectionView.
Womble

30

Я нашел очень простой способ настроить расстояние между ячейками или строками с помощью IB.

Просто выберите UICollectionView из раскадровки / Xib-файла и щелкните в инспекторе размеров, как показано на рисунке ниже.

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

Для настройки пространства программно используйте следующие свойства.

1) Для установки пространства между рядами.

[self.collectionView setMinimumLineSpacing:5];

2) Для установки пространства между элементами / ячейками.

[self.collectionView setMinimumInteritemSpacing:5];

1
Это минимальное пространство, которое будет больше указанного значения и не всегда указанного значения.
Вишал Сингх

21

Пожалуйста, обратите внимание на имя свойства MinilInterItemSpacing . Это будет минимальный интервал между элементами, а не точный интервал. Если вы установите в качестве значения MaximumInterItemSpacing какое-то значение, вы можете быть уверены, что интервал не будет меньше этого значения. Но есть шанс получить более высокое значение.

На самом деле расстояние между элементами зависит от нескольких факторов itemSize и sectionInset . Представление коллекции динамически размещает содержимое на основе этих значений. Таким образом, вы не можете гарантировать точное расстояние. Вы должны сделать некоторые пробы и ошибки с sectionInset и minimumInterItemSpacing .


1
@ Аниловые насекомые? : D
NightFury

10
Там могут быть ошибки в вашем разделе насекомых.
Нестор

24
насекомое == ошибка && насекомое! = вставка :)
Нестор

16

Ответ для Swift 3.0, Xcode 8

1. Убедитесь, что вы установили делегат представления коллекции

class DashboardViewController: UIViewController {
    @IBOutlet weak var dashboardCollectionView: UICollectionView!

    override func viewDidLoad() {
        super.viewDidLoad()
        dashboardCollectionView.delegate = self
    }
}

2. Реализация протокола UICollectionViewDelegateFlowLayout , а не UICollectionViewDelegate.

extension DashboardViewController: UICollectionViewDelegateFlowLayout {
    fileprivate var sectionInsets: UIEdgeInsets {
        return .zero
    }

    fileprivate var itemsPerRow: CGFloat {
        return 2
    }

    fileprivate var interitemSpace: CGFloat {
        return 5.0
    }

    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        sizeForItemAt indexPath: IndexPath) -> CGSize {
        let sectionPadding = sectionInsets.left * (itemsPerRow + 1)
        let interitemPadding = max(0.0, itemsPerRow - 1) * interitemSpace
        let availableWidth = collectionView.bounds.width - sectionPadding - interitemPadding
        let widthPerItem = availableWidth / itemsPerRow

        return CGSize(width: widthPerItem, height: widthPerItem)
    }

    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        insetForSectionAt section: Int) -> UIEdgeInsets {
        return sectionInsets
    }

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

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

1
Думаю, вы можете удалить публику там. Должно работать нормально и соответствовать всем другим функциям.
Эдвард Поттер

Будет ли это работать для представления коллекции вертикальной прокрутки? У меня есть представление коллекции, где оно должно показывать 2 ячейки по горизонтали на устройствах, таких как iPhone 6s и 6s Plus, но должно показывать только одну ячейку для чего-то ниже, чем 5s, 5 и SE. Мой текущий код работает, но в устройстве 6s Plus разрыв между ячейками слишком велик и выглядит некрасиво, и я пытаюсь уменьшить этот разрыв, и это единственное требование, поскольку все другие устройства работают в соответствии с моим дизайном.
AnBisw

11

Простой код для пробелов

let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
layout.minimumInteritemSpacing = 10 // Some float value

3
Для расстояния по горизонтали ячейки следует использовать: minimumLineSpacing
Альфи

9

Проголосовали ответ (а также версия скор ) есть небольшой вопрос: будет большой интервал справа.

Это связано с тем, что компоновка потока настроена так, чтобы сделать интервал между ячейками точным, а поведение с плавающей точкой осталось .

Мое решение состоит в том, чтобы манипулировать вставкой сечения, так чтобы сечение было выровнено по центру, но расстояние точно соответствовало указанному.

На скриншоте ниже, расстояние между предметами и линиями составляет ровно 8pt, в то время как сечение слева и справа будет больше, чем 8pt (чтобы выровнять его по центру):

равномерно расположенные клетки

Swift код как таковой:

private let minItemSpacing: CGFloat = 8
private let itemWidth: CGFloat      = 100
private let headerHeight: CGFloat   = 32

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    // Create our custom flow layout that evenly space out the items, and have them in the center
    let layout = UICollectionViewFlowLayout()
    layout.itemSize = CGSize(width: itemWidth, height: itemWidth)
    layout.minimumInteritemSpacing = minItemSpacing
    layout.minimumLineSpacing = minItemSpacing
    layout.headerReferenceSize = CGSize(width: 0, height: headerHeight)

    // Find n, where n is the number of item that can fit into the collection view
    var n: CGFloat = 1
    let containerWidth = collectionView.bounds.width
    while true {
        let nextN = n + 1
        let totalWidth = (nextN*itemWidth) + (nextN-1)*minItemSpacing
        if totalWidth > containerWidth {
            break
        } else {
            n = nextN
        }
    }

    // Calculate the section inset for left and right. 
    // Setting this section inset will manipulate the items such that they will all be aligned horizontally center.
    let inset = max(minItemSpacing, floor( (containerWidth - (n*itemWidth) - (n-1)*minItemSpacing) / 2 ) )
    layout.sectionInset = UIEdgeInsets(top: minItemSpacing, left: inset, bottom: minItemSpacing, right: inset)

    collectionView.collectionViewLayout = layout
}

1
Я получаю 'NSInvalidArgumentException', причина: '*** setObjectForKey: объект не может быть nil (ключ: <NSIndexPath: 0xc000000000000016> {length = 2, path = 0 - 0})' uncaught исключение.
DaftWooly

... если я не ошибаюсь, ваш цикл while эквивалентен: let n = Int((containerWidth + minItemSpacing)/((itemWidth+minItemSpacing)))
DaftWooly

Не использовал код как есть, но это дало мне лучший справочник для реализации моего макета потока вывода для представления коллекции. ура
Дима Гимбург

8

Определите UICollectionViewDelegateFlowLayoutпротокол в вашем заголовочном файле.

Реализуйте следующий метод UICollectionViewDelegateFlowLayoutпротокола следующим образом:

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
    return UIEdgeInsetsMake(5, 5, 5, 5);
}

Нажмите здесь, чтобы увидеть документацию Apple о UIEdgeInsetMakeметоде.


4

Подход раскадровки

Выберите CollectionView в вашей раскадровке и перейдите к инспектору размера и установите минимальный интервал для ячеек и линий равным 5

Swift 5 программно

lazy var collectionView: UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal

        //Provide Width and Height According to your need
        let width = UIScreen.main.bounds.width / 4
        let height = UIScreen.main.bounds.height / 10
        layout.itemSize = CGSize(width: width, height: height)

        //For Adjusting the cells spacing
        layout.minimumInteritemSpacing = 5
        layout.minimumLineSpacing = 5

        return UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
    }()

3

Если вы хотите изменить интервал, не затрагивая фактический размер ячейки, это решение подойдет мне лучше всего. #xcode 9 # tvOS11 # iOS11 #swift

Таким образом, в UICollectionViewDelegateFlowLayout , изменения реализуют следующие методы, хитрость заключается в том, что нужно использовать оба из них, и документация на самом деле не указывала мне думать в этом направлении. : D

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

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

2

Я использую monotouch, поэтому имена и код будут немного отличаться, но вы можете сделать это, убедившись, что ширина представления коллекции равна (x * ширина ячейки) + (x-1) * MinimumSpacing с x = amount ячеек в ряду.

Просто выполните следующие шаги на основе вашего MinimumInteritemSpacing и ширины ячейки

1) Мы рассчитываем количество элементов в строке на основе размера ячейки + текущие вставки + минимальный интервал

float currentTotalWidth = CollectionView.Frame.Width - Layout.SectionInset.Left - Layout.SectionInset.Right (Layout = flowlayout)
int amountOfCellsPerRow = (currentTotalWidth + MinimumSpacing) / (cell width + MinimumSpacing)

2) Теперь у вас есть вся информация, чтобы рассчитать ожидаемую ширину для представления коллекции

float totalWidth =(amountOfCellsPerRow * cell width) + (amountOfCellsPerRow-1) * MinimumSpacing

3) Таким образом, разница между текущей шириной и ожидаемой шириной

float difference = currentTotalWidth - totalWidth;

4) Теперь отрегулируйте вставки (в этом примере мы добавляем их справа, чтобы левая позиция представления коллекции осталась прежней

Layout.SectionInset.Right = Layout.SectionInset.Right + difference;

2

У меня горизонтальный UICollectionViewи подкласс UICollectionViewFlowLayout. Представление коллекции имеет большие ячейки и отображает только одну строку за раз, а представление коллекции соответствует ширине экрана.

Я попробовал ответ iago849, и он сработал, но потом я узнал, что мне даже не нужен его ответ. По какой-то причине установка minimumInterItemSpacingничего не делает. Расстояние между моими предметами / ячейками может полностью контролироваться minimumLineSpacing.

Не уверен, почему это работает таким образом, но это работает.


1
это кажется правдой - как ни странно, значение «линии» фактически является разделителем между элементами в случае горизонтальной разметки.
Толстяк

Эй, @ user3344977 - хорошая находка. Я решил разделить эту проблему на отдельный вопрос, который напрямую касается представлений коллекции горизонтальной прокрутки, чтобы ее было легче найти для некоторых людей. Я ссылаюсь на ваш ответ там. Мой вопрос здесь: stackoverflow.com/q/61774415/826946
Энди Вайнштейн

1

Я наткнулся на аналогичную проблему, как OP. К сожалению, принятый ответ не сработал для меня, так как содержание collectionViewне будет правильно центрировано. Поэтому я пришел к другому решению, которое требует, чтобы все элементы collectionViewбыли одинаковой ширины , что, как представляется, имеет место в вопросе:

#define cellSize 90

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
    float width = collectionView.frame.size.width;
    float spacing = [self collectionView:collectionView layout:collectionViewLayout minimumInteritemSpacingForSectionAtIndex:section];
    int numberOfCells = (width + spacing) / (cellSize + spacing);
    int inset = (width + spacing - numberOfCells * (cellSize + spacing) ) / 2;

    return UIEdgeInsetsMake(0, inset, 0, inset);
}

Этот код гарантирует, что возвращаемое значение ...minimumInteritemSpacing...будет точным интервалом между каждым collectionViewCellи, кроме того, гарантирует, что все ячейки будут сосредоточены вcollectionView


Это круто. Но мне было интересно, можно ли применить подобное решение к вертикальному расстоянию между элементами
p0lAris

Вертикальный интервал в случае горизонтальной прокрутки?
luk2302

1

Приведенное выше решение от vojtech-vrbka является правильным, но оно выдает предупреждение:

предупреждение: UICollectionViewFlowLayout имеет несовпадение кэшированных кадров для пути индекса - кэшированное значение: это, вероятно, происходит потому, что подкласс макета потока Layout изменяет атрибуты, возвращаемые UICollectionViewFlowLayout, не копируя их

Следующий код должен это исправить:

class CustomViewFlowLayout : UICollectionViewFlowLayout {

   let cellSpacing:CGFloat = 4

   override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
       let original = super.layoutAttributesForElementsInRect(rect)

       if let original = original {
           let attributes = NSArray.init(array: original, copyItems: true) as! [UICollectionViewLayoutAttributes]

           for (index, attribute) in attributes.enumerate() {
                if index == 0 { continue }
                let prevLayoutAttributes = attributes[index - 1]
                let origin = CGRectGetMaxX(prevLayoutAttributes.frame)
                if(origin + cellSpacing + attribute.frame.size.width < self.collectionViewContentSize().width) {
                    attribute.frame.origin.x = origin + cellSpacing
                }
            }
            return attributes
       }
       return nil
   }
}

2
Как и другие ответы на SO, использующие этот подход, это работает для подгонки ячеек по ширине collectionView, но прерывистые промежутки переменной высоты все еще остаются между строками. Это может быть ограничением способа визуализации CollectionView.
Womble

1

Версия Swift 3

Просто создайте подкласс UICollectionViewFlowLayout и вставьте этот метод.

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        guard let answer = super.layoutAttributesForElements(in: rect) else { return nil }

        for i in 1..<answer.count {
            let currentAttributes = answer[i]
            let previousAttributes = answer[i - 1]

            let maximumSpacing: CGFloat = 8
            let origin = previousAttributes.frame.maxX

            if (origin + maximumSpacing + currentAttributes.frame.size.width < self.collectionViewContentSize.width && currentAttributes.frame.origin.x > previousAttributes.frame.origin.x) {
                var frame = currentAttributes.frame
                frame.origin.x = origin + maximumSpacing
                currentAttributes.frame = frame
            }
        }

        return answer
}

Это работает для горизонтальной подгонки, но промежутки между строками останутся, даже если для minLineSpacingForSectionAt установлено значение 0, а для layout.minimumLineSpacing установлено значение 0. Кроме того, касание в collectionView приведет к сбою приложения из-за отсутствия первого цикла диапазона.
Womble

1

Я попробовал ответ iago849, и это сработало.

Swift 4

open override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    guard let answer = super.layoutAttributesForElements(in: rect) else {
        return nil
    }
    let count = answer.count
    for i in 1..<count {
        let currentLayoutAttributes = answer[i]
        let prevLayoutAttributes = answer[i-1]
        let origin = prevLayoutAttributes.frame.maxX
        if (origin + CGFloat(spacing) + currentLayoutAttributes.frame.size.width) < self.collectionViewContentSize.width && currentLayoutAttributes.frame.origin.x > prevLayoutAttributes.frame.origin.x {
            var frame = currentLayoutAttributes.frame
            frame.origin.x = origin + CGFloat(spacing)
            currentLayoutAttributes.frame = frame
        }
    }
    return answer
}

Вот ссылка на проект GitHub. https://github.com/vishalwaka/MultiTags


0

Предыдущие версии не работали с разделами> 1. Поэтому мое решение было найдено здесь https://codentrick.com/create-a-tag-flow-layout-with-uicollectionview/ . Для ленивых:

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    let attributesForElementsInRect = super.layoutAttributesForElements(in: rect)
    var newAttributesForElementsInRect = [UICollectionViewLayoutAttributes]()
    // use a value to keep track of left margin
    var leftMargin: CGFloat = 0.0;
    for attributes in attributesForElementsInRect! {
        let refAttributes = attributes 
        // assign value if next row
        if (refAttributes.frame.origin.x == self.sectionInset.left) {
            leftMargin = self.sectionInset.left
        } else {
            // set x position of attributes to current margin
            var newLeftAlignedFrame = refAttributes.frame
            newLeftAlignedFrame.origin.x = leftMargin
            refAttributes.frame = newLeftAlignedFrame
        }
        // calculate new value for current margin
        leftMargin += refAttributes.frame.size.width + 10
        newAttributesForElementsInRect.append(refAttributes)
    }

    return newAttributesForElementsInRect
}

0

У меня проблема с принятым ответом, поэтому я обновил его, это работает для меня:

.час

@interface MaxSpacingCollectionViewFlowLayout : UICollectionViewFlowLayout
@property (nonatomic,assign) CGFloat maxCellSpacing;
@end

.m

@implementation MaxSpacingCollectionViewFlowLayout

- (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect {
    NSArray *attributes = [super layoutAttributesForElementsInRect:rect];

    if (attributes.count <= 0) return attributes;

    CGFloat firstCellOriginX = ((UICollectionViewLayoutAttributes *)attributes[0]).frame.origin.x;

    for(int i = 1; i < attributes.count; i++) {
        UICollectionViewLayoutAttributes *currentLayoutAttributes = attributes[i];
        if (currentLayoutAttributes.frame.origin.x == firstCellOriginX) { // The first cell of a new row
            continue;
        }

        UICollectionViewLayoutAttributes *prevLayoutAttributes = attributes[i - 1];
        CGFloat prevOriginMaxX = CGRectGetMaxX(prevLayoutAttributes.frame);
        if ((currentLayoutAttributes.frame.origin.x - prevOriginMaxX) > self.maxCellSpacing) {
            CGRect frame = currentLayoutAttributes.frame;
            frame.origin.x = prevOriginMaxX + self.maxCellSpacing;
            currentLayoutAttributes.frame = frame;
        }
    }
    return attributes;
}

@end

0

Мое решение в Swift 3межстрочных интервалах, как в Instagram:

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

lazy var collectionView: UICollectionView = {
    let layout = UICollectionViewFlowLayout()
    let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
    cv.backgroundColor = UIColor.rgb(red: 227, green: 227, blue: 227)
    cv.showsVerticalScrollIndicator = false
    layout.scrollDirection = .vertical
    layout.minimumLineSpacing = 1
    layout.minimumInteritemSpacing = 1
    return cv
}()

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

    switch UIDevice.current.modelName {
    case "iPhone 4":
        return CGSize(width: 106, height: 106)
    case "iPhone 5":
        return CGSize(width: 106, height: 106)
    case "iPhone 6,7":
        return CGSize(width: 124, height: 124)
    case "iPhone Plus":
        return CGSize(width: 137, height: 137)
    default:
        return CGSize(width: frame.width / 3, height: frame.width / 3)
    }
}

Как обнаружить устройство программно: https://stackoverflow.com/a/26962452/6013170


0

Что ж, если вы создаете горизонтальный вид коллекции, чтобы оставить пространство между ячейками, вам нужно установить свойство minimumLineSpacing.


-1

Попробуйте поиграть с этим методом:

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView
                    layout:(UICollectionViewLayout*)collectionViewLayout
    insetForSectionAtIndex:(NSInteger)section {

    UIEdgeInsets insets = UIEdgeInsetsMake(?, ?, ?, ?);

    return insets;
}

2
Это работает только для промежутков между секциями, а не ячейками
Диего А. Ринкон
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.