UICollectionView-горизонтальная прокрутка, горизонтальная компоновка?

У меня есть UIScrollView, который выкладывает сетку значков. Если бы вы представили макет для трамплина iOS, вы были бы довольно близки к правильному. Он имеет горизонтальный, выгружаемый свиток (как и трамплин). Тем не менее, похоже, что макет не совсем правильный. Похоже, что он раскладывает предметы сверху донизу. В результате мой последний столбец имеет только 2 строки из-за количества отображаемых элементов. Я бы предпочел, чтобы моя последняя строка на последней странице была 2 предметы, как на трамплине.

Как это можно сделать с помощью UICollectionView и связанных с ним классов? Должен ли я писать пользовательский UICollectionViewFlowLayout?

11 ответов


1-й подход

как насчет использования UIPageViewController массив UICollectionViewControllers? Вы должны были бы получить надлежащее количество элементов в каждом UICollectionViewController, но это не должно быть трудно. Ты будешь выглядеть точно так же, как трамплин.

2-й подход

я думал об этом и на мой взгляд необходимо установить:

self.collectionView.pagingEnabled = YES;

и создайте свой собственный макет представления коллекции путем подкласса UICollectionViewLayout. Из настраиваемого объекта layout можно получить доступ self.collectionView, так что вы будете знать, каков размер коллекции view's frame, numberOfSections и numberOfItemsInSection:. С этой информацией вы можете вычислить ячейки'frames (in prepareLayout) и collectionViewContentSize. Вот несколько статей о создании custom макеты:

3-й подход

вы можете сделать это (или его приближение) без создания пользовательского макета. Добавить UIScrollView в пустом представлении установите подкачку в он. В представлении прокрутки добавьте представление коллекции a. Затем добавьте к нему ограничение ширины, проверьте в коде, сколько у вас элементов и установите его constant до правильного значения, например (self.view.frame.size.width * numOfScreens). Вот как это выглядит (цифры на ячейках показывают indexPath.row): https://www.dropbox.com/s/ss4jdbvr511azxz/collection_view.mov


вы пытались установить направление прокрутки вашего UICollectionViewFlowLayout в горизонтальное положение?

[yourFlowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];

и если вы хотите, чтобы он был на странице, как springboard, вам нужно включить подкачку на вашем представлении коллекции следующим образом:

[yourCollectionView setPagingEnabled:YES];

вам нужно уменьшить высоту UICollectionView к своей высоте ячейки / элемента и выберите"Horizontal" от "Scroll Direction" как показано на скриншоте ниже. Затем он будет прокручиваться по горизонтали в зависимости от numberOfItems вы вернулись в его реализации источника данных.

enter image description here


Если вы определяете UICollectionViewFlowLayout в коде он переопределит конфигурации Interface Builder. Следовательно, вам нужно повторно определить scrollDirection снова.

let layout = UICollectionViewFlowLayout()
...
layout.scrollDirection = .Horizontal
self.awesomeCollectionView.collectionViewLayout = layout

просто для удовольствия, другим подходом было бы просто оставить набор подкачки и горизонтальной прокрутки, добавить метод, который изменяет порядок элементов массива для преобразования из "сверху вниз, слева направо" в визуально "слева направо, сверху вниз" и заполните промежуточные ячейки пустыми скрытыми ячейками, чтобы сделать интервал справа. В случае 7 элементов в сетке из 9 это будет выглядеть так:

[1][4][7]
[2][5][ ]
[3][6][ ]

должны стать

[1][2][3]
[4][5][6]
[7][ ][ ]

Итак 1=1, 2=4, 3=7 etc. и 6=пусто. Вы можете изменить их порядок, вычисляя общее количество строк и столбцов, затем вычислить номер строки и столбца для каждой ячейки, изменить строку для столбца и наоборот, а затем у вас есть новые индексы. Когда ячейка не имеет значения, соответствующего изображению, вы можете вернуть пустую ячейку и установить cell.hidden = YES; к нему.

он отлично работает в приложении деки, которое я построил, поэтому, если кто-то хочет рабочий код, я добавлю его. Для этого требуется только небольшой код трюк, это звучит сложнее, чем есть!

обновление

Я сомневаюсь, что это лучшее решение, но по запросу рабочий код здесь:

- (void)viewDidLoad {
    // Fill an `NSArray` with items in normal order
    items = [NSMutableArray arrayWithObjects:
             [NSDictionary dictionaryWithObjectsAndKeys:@"Some label 1", @"label", @"Some value 1", @"value", nil],
             [NSDictionary dictionaryWithObjectsAndKeys:@"Some label 2", @"label", @"Some value 2", @"value", nil],
             [NSDictionary dictionaryWithObjectsAndKeys:@"Some label 3", @"label", @"Some value 3", @"value", nil],
             [NSDictionary dictionaryWithObjectsAndKeys:@"Some label 4", @"label", @"Some value 4", @"value", nil],
             [NSDictionary dictionaryWithObjectsAndKeys:@"Some label 5", @"label", @"Some value 5", @"value", nil],
              nil
              ];

    // Calculate number of rows and columns based on width and height of the `UICollectionView` and individual cells (you might have to add margins to the equation based on your setup!)
    CGFloat w = myCollectionView.frame.size.width;
    CGFloat h = myCollectionView.frame.size.height;
    rows = floor(h / cellHeight);
    columns = floor(w / cellWidth);
}

// Calculate number of sections
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    return ceil((float)items.count / (float)(rows * columns));
}

// Every section has to have every cell filled, as we need to add empty cells as well to correct the spacing
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return rows*columns;
}

// And now the most important one
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier@"myIdentifier" forIndexPath:indexPath];

    // Convert rows and columns
    int row = indexPath.row % rows;
    int col = floor(indexPath.row / rows);
    // Calculate the new index in the `NSArray`
    int newIndex = ((int)indexPath.section * rows * columns) + col + row * columns;

    // If the newIndex is within the range of the items array we show the cell, if not we hide it
    if(newIndex < items.count) {
        NSDictionary *item = [items objectAtIndex:newIndex];
        cell.label.text = [item objectForKey:@"label"];
        cell.hidden = NO;
    } else {
        cell.hidden = YES;
    }

    return cell;
}

если вы хотите использовать didSelectItemAtIndexPath метод вы должны использовать то же преобразование, которое используется в cellForItemAtIndexPath чтобы получить соответствующий пункт. Если у вас есть поля ячеек, вам нужно добавить их в расчет строк и столбцов, так как они должны быть правильными, чтобы это работало.


этот код хорошо работает в Swift 3.1 и Xcode 8.3.2

override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal
        self.collectionView.collectionViewLayout = layout
        self.collectionView!.contentInset = UIEdgeInsets(top: -10, left: 0, bottom:0, right: 0)

        if let layout = self.collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
            layout.minimumInteritemSpacing = 0
            layout.minimumLineSpacing = 0
            layout.itemSize = CGSize(width: self.view.frame.size.width-40, height: self.collectionView.frame.size.height-10)
            layout.invalidateLayout()
        }

    }

Я работаю в Xcode 6.2 и для горизонтальной прокрутки, я изменил направление прокрутки в инспекторе атрибутов.

нажмите на collectionView - >инспектор атрибутов - >направление прокрутки - >изменить на горизонтальный

enter image description here надеюсь, это кому-то поможет.


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

Я достиг этого с помощью моей пользовательской реализации класса макета с "SMCollectionViewFillLayout"

репозиторий код:

https://github.com/smindia1988/SMCollectionViewFillLayout

выход ниже:

1.формат PNG

First.png

2_Code_H-Scroll_V-заполнить.формат PNG

enter image description here

3_Output_H-Scroll_V-заполнить.формат PNG enter image description here

4_Code_H-Scroll_H-заполнить.формат PNG enter image description here

5_Output_H-Scroll_H-заполнить.формат PNG enter image description here


от @Erik Hunter, я размещаю полный код для горизонтального UICollectionView

UICollectionViewFlowLayout *collectionViewFlowLayout = [[UICollectionViewFlowLayout alloc] init];
[collectionViewFlowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
self.myCollectionView.collectionViewLayout = collectionViewFlowLayout;

В Swift

let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .Horizontal
self.myCollectionView.collectionViewLayout = layout

В Swift 3.0

let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
self.myCollectionView.collectionViewLayout = layout

надеюсь, что это поможет


для xcode 8 я сделал это, и это сработало:


вы можете написать собственное UICollectionView макет для достижения этой цели, вот демо-изображение моей реализации:

demo image

вот код: KSTCollectionViewPageHorizontalLayout

@iPhoneDev (это может помочь вам тоже)