UICollectionView – 水平滚动,水平布局?
我有一个UIScrollView,列出了一个图标的网格。 如果你想象iOS跳板的布局,你会非常接近正确的。 它有一个水平的页面滚动(就像跳板)。 但是,看起来布局不太正确。 看起来好像是从上到下布置项目。 因此,由于要显示的项目数量,我的最后一列只有2行。 我宁愿让最后一页的最后一行有两个项目,就像你在Springboard中看到的一样。
这怎么可以用UICollectionView和它的相关类来完成? 我必须编写一个自定义的UICollectionViewFlowLayout吗?
第一种方法
使用UIPageViewController
和UICollectionViewControllers
数组UICollectionViewControllers
样? 您必须在每个UICollectionViewController
获取适当数量的项目,但不应该很难。 你会得到与Springboard完全一样的外观。
第二种方法
我想过这个,在我看来你必须设定:
self.collectionView.pagingEnabled = YES;
并通过UICollectionViewLayout
创build自己的集合视图布局。 从自定义布局对象中,你可以访问self.collectionView
,所以你会知道集合视图的frame
的大小是什么, numberOfSections
和numberOfItemsInSection:
有了这些信息,你可以计算单元格的frames
(在prepareLayout
)和collectionViewContentSize
。 这里有一些关于创build自定义布局的文章:
- http://skeuo.com/uicollectionview-custom-layout-tutorial
- https://developer.apple.com/library/content/documentation/WindowsViews/Conceptual/CollectionViewPGforIOS/CreatingCustomLayouts/CreatingCustomLayouts.html
- http://www.objc.io/issue-3/collection-view-layouts.html
第三种方法
您可以在不创build自定义布局的情况下(或近似)执行此操作。 在空白视图中添加UIScrollView
在其中设置分页。 在滚动视图中添加一个集合视图。 然后添加一个宽度约束,检查代码中有多less项,并将其constant
设置为正确的值,例如(self.view.frame.size.width * numOfScreens)
。 以下是它的外观(单元格中的数字显示indexPath.row
): https : indexPath.row
如果您对单元格的排列方式不满意,那么恐怕你必须去1或2。
你有没有尝试将UICollectionViewFlowLayout的滚动方向设置为水平?
[yourFlowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
如果你想要像跳板这样的页面,你需要在你的集合视图上启用分页,如下所示:
[yourCollectionView setPagingEnabled:YES];
您需要将UICollectionView
的高度降低到其单元格/项目高度,并从“ Scroll Direction
”中select“ Horizontal
”,如下面的截图所示。 然后它将水平滚动,取决于您在其数据源实现中返回的numberOfItems
。
只是为了好玩,另一种方法是只保留分页和水平滚动设置,添加一个方法,改变数组项目的顺序,从“从上到下,从左到右”转换为视觉上的从左到右,从上到下底部“,并用空的隐藏单元填充中间单元格,以使间距正确。 如果9个网格中的7个项目,这将是这样的:
[1][4][7] [2][5][ ] [3][6][ ]
应该成为
[1][2][3] [4][5][6] [7][ ][ ]
所以1 = 1,2 = 4,3 = 7等,6 =空。 您可以通过计算行和列的总数来对它们重新sorting,然后计算每个单元格的行和列号,更改列的行,反之亦然,然后获得新的索引。 当单元格没有与图像对应的值时,可以返回空单元格并设置cell.hidden = YES;
到它。
它在我创build的音板应用程序中工作得很好,所以如果有人想要工作代码,我会添加它。 只需要很less的代码来使这个技巧工作,这听起来比它更难!
更新
我怀疑这是最好的解决scheme,但通过请求这里的工作代码:
- (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
使用的转换相同的转换来获取相应的项目。 如果您有单元格边距,则需要将它们添加到行和列计算中,因为这些必须是正确的才能使其工作。
我正在使用Xcode 6.2和水平滚动我已经改变属性检查器中的滚动方向。
点击collectionView->属性inspector->滚动Direction->改变为水平
我希望它可以帮助别人。
如果在代码中定义了UICollectionViewFlowLayout
,它将覆盖Interface Builder的configuration。 因此你需要重新定义scrollDirection
。
let layout = UICollectionViewFlowLayout() ... layout.scrollDirection = .Horizontal self.awesomeCollectionView.collectionViewLayout = layout
从@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做同样的Springboard行为,为此我们需要编写自定义布局的代码。
我已经实现了与我的自定义布局类实现“SMCollectionViewFillLayout”
代码库:
https://github.com/smindia1988/SMCollectionViewFillLayout
输出如下:
1.png
2_Code_H-Scroll_V-Fill.png
3_Output_H-Scroll_V-Fill.png
4_Code_H-Scroll_H-Fill.png
5_Output_H-Scroll_H-Fill.png
这段代码在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 8我做到了这一点,它的工作原理:
你可以写一个自定义的UICollectionView
布局来实现这一点,这里是我的实现的演示图像:
这是代码库: KSTCollectionViewPageHorizontalLayout
@iPhoneDev(这也许可以帮助你)