70

我有一个UIScrollView布局图标网格。如果您想象 iOS Springboard 的布局,您将非常接近正确。它有一个水平的分页滚动(就像跳板一样)。但是,布局似乎不太正确。看起来好像它正在从上到下布置项目。结果,由于要显示的项目数量,我的最后一列只有 2 行。我宁愿在最后一页的最后一行有 2 个项目,就像您在 Springboard 中看到的那样。

这如何通过UICollectionView及其相关类来完成?我必须写一个自定义UICollectionViewFlowLayout吗?

4

12 回答 12

101

您是否尝试将 UICollectionViewFlowLayout 的滚动方向设置为水平?

[yourFlowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];

如果你想让它像跳板一样分页,你需要像这样在你的集合视图上启用分页:

[yourCollectionView setPagingEnabled:YES];
于 2013-10-18T15:42:22.233 回答
79

第一种方法

UIPageViewController与数组一起使用怎么样UICollectionViewControllers?您必须在 each 中获取适当数量的项目UICollectionViewController,但这应该不难。您将获得与 Springboard 完全相同的外观。

第二种方法

我已经考虑过这一点,在我看来你必须设置:

self.collectionView.pagingEnabled = YES;

并通过子类化创建您自己的集合视图布局UICollectionViewLayout。从您可以访问的自定义布局对象中self.collectionView,您将知道集合视图的frame大小numberOfSectionsnumberOfItemsInSection:. 有了这些信息,您可以计算单元格的frames(in prepareLayout) 和collectionViewContentSize。以下是一些关于创建自定义布局的文章:

第三种方法

您可以在不创建自定义布局的情况下执行此操作(或其近似值)。在空白视图中添加UIScrollView,在其中设置分页。在滚动视图中添加一个集合视图。然后向其添加宽度约束,在代码中检查您有多少项目并将其设置constant为正确的值,例如(self.view.frame.size.width * numOfScreens). 这是它的外观(单元格上的数字显示indexPath.row):https ://www.dropbox.com/s/ss4jdbvr511azxz/collection_view.mov如果您对单元格的排序方式不满意,那么恐怕您会必须与 1. 或 2 一起使用。

于 2013-10-17T19:49:19.937 回答
53

您需要将 的高度降低UICollectionView到其单元格/项目的高度,然后从“”中选择“ Horizontal”,Scroll Direction如下面的屏幕截图所示。然后它将根据numberOfItems您在其数据源实现中返回的水平滚动。

在此处输入图像描述

于 2015-03-11T12:19:46.060 回答
19

如果您UICollectionViewFlowLayout在代码中定义,它将覆盖 Interface Builder 配置。因此,您需要重新定义scrollDirection

let layout = UICollectionViewFlowLayout()
...
layout.scrollDirection = .Horizontal
self.awesomeCollectionView.collectionViewLayout = layout
于 2016-03-15T11:44:32.370 回答
15

此代码在Swift 3.1Xcode 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()
        }

    }
于 2017-08-02T11:28:30.237 回答
11

来自@Erik Hunter,我发布了 make Horizo​​ntal 的完整代码UICollectionView

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

在斯威夫特

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

在 Swift 3.0 中

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

希望这有帮助

于 2016-04-29T08:58:10.287 回答
9

只是为了好玩,另一种方法是只保留分页和水平滚动集,添加一个方法来更改数组项的顺序以从“从上到下,从左到右”转换为视觉上的“从左到右,从上到底部'并用空的隐藏单元格填充中间单元格以使间距正确。如果 9 个网格中有 7 个项目,则如下所示:

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

应该成为

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

所以 1=1、2=4、3=7 等等,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获取相应项目相同的转换。如果您有单元格边距,则需要将它们添加到行和列计算中,因为这些必须正确才能使其起作用。

于 2015-01-15T14:03:53.460 回答
8

我们可以使用 UICollectionView 执行相同的 Springboard 行为,为此我们需要为自定义布局编写代码。

我已经通过“SMCollectionViewFillLayout”的自定义布局类实现实现了它

代码库:

https://github.com/smindia1988/SMCollectionViewFillLayout

输出如下:

1.png

第一.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 在此处输入图像描述

于 2016-11-24T06:10:47.993 回答
7

对于xcode 8,我这样做了,它起作用了:

于 2016-12-22T20:10:40.437 回答
6

我正在研究 Xcode 6.2,对于水平滚动,我在属性检查器中更改了滚动方向。

单击collectionView->属性检查器->滚动方向->更改为水平

在此处输入图像描述我希望它可以帮助某人。

于 2015-03-25T10:22:26.980 回答
3

您可以编写自定义UICollectionView布局来实现此目的,这是我的实现的演示图像:

演示图像

这是代码存储库:KSTCollectionViewPageHorizo​​ntalLayout

@iPhoneDev(这也许对你也有帮助)

于 2017-01-24T02:14:13.680 回答
1

如果您需要设置 UICollectionView 滚动方向水平并且您需要将单元格宽度和高度设置为静态。请将 collectionview 估计大小Automatic设置为None

查看屏幕截图

于 2020-09-16T06:44:42.627 回答