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 макеты:
- https://developer.apple.com/library/content/documentation/WindowsViews/Conceptual/CollectionViewPGforIOS/CreatingCustomLayouts/CreatingCustomLayouts.html
- http://www.objc.io/issue-3/collection-view-layouts.html
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
вы вернулись в его реализации источника данных.
Если вы определяете 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 - >инспектор атрибутов - >направление прокрутки - >изменить на горизонтальный
надеюсь, это кому-то поможет.
мы можем сделать то же самое поведение трамплина с помощью UICollectionView, и для этого нам нужно написать код для пользовательского макета.
Я достиг этого с помощью моей пользовательской реализации класса макета с "SMCollectionViewFillLayout"
репозиторий код:
https://github.com/smindia1988/SMCollectionViewFillLayout
выход ниже:
1.формат PNG
2_Code_H-Scroll_V-заполнить.формат PNG
3_Output_H-Scroll_V-заполнить.формат PNG
от @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
надеюсь, что это поможет
вы можете написать собственное UICollectionView
макет для достижения этой цели, вот демо-изображение моей реализации:
@iPhoneDev (это может помочь вам тоже)