ios UICollectionView - 水平滚动,水平布局?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19301762/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 02:16:15  来源:igfitidea点击:

UICollectionView - Horizontal scroll, horizontal layout?

ioslayoutuicollectionviewuicollectionviewlayout

提问by Shadowman

I have a UIScrollViewthat lays out a grid of icons. If you were to imagine the layout for the iOS Springboard, you'd be pretty close to correct. It has a horizontal, paged scroll (just like Springboard). However, it appears that the layout is not quite right. It appears as though it is laying out the items from top to bottom. As a result, my last column only has 2 rows in it, due to the number of items to be displayed. I'd rather have my last row on the last page have 2 items, like you would see in the Springboard.

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

How can this be accomplished with UICollectionViewand its related classes? Do I have to write a custom UICollectionViewFlowLayout?

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

回答by Erik Hunter

Have you tried setting the scroll direction of your UICollectionViewFlowLayout to horizontal?

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

[yourFlowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];

And if you want it to page like springboard does, you'll need to enable paging on your collection view like so:

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

[yourCollectionView setPagingEnabled:YES];

回答by Arek Holko

1st approach

第一种方法

What about using UIPageViewControllerwith an array of UICollectionViewControllers? You'd have to fetch proper number of items in each UICollectionViewController, but it shouldn't be hard. You'd get exactly the same look as the Springboard has.

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

2nd approach

第二种方法

I've thought about this and in my opinion you have to set:

我已经考虑过这个,我认为你必须设置:

self.collectionView.pagingEnabled = YES;

and create your own collection view layout by subclassing UICollectionViewLayout. From the custom layout object you can access self.collectionView, so you'll know what is the size of the collection view's frame, numberOfSectionsand numberOfItemsInSection:. With that information you can calculate cells' frames(in prepareLayout) and collectionViewContentSize. Here're some articles about creating custom layouts:

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

3rd approach

第三种方法

You can do this (or an approximation of it) without creating the custom layout. Add UIScrollViewin the blank view, set paging enabled in it. In the scroll view add the a collection view. Then add to it a width constraint, check in code how many items you have and set its constantto the correct value, e.g. (self.view.frame.size.width * numOfScreens). Here's how it looks (numbers on cells show the indexPath.row): https://www.dropbox.com/s/ss4jdbvr511azxz/collection_view.movIf you're not satisfied with the way cells are ordered, then I'm afraid you'd have to go with 1. or 2.

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

回答by Deepak Thakur

You need to reduce the height of UICollectionViewto its cell / item height and select "Horizontal" from the "Scroll Direction" as seen in the screenshot below. Then it will scroll horizontally depending on the numberOfItemsyou have returned in its datasource implementation.

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

enter image description here

在此处输入图片说明

回答by DazChong

If you are defining UICollectionViewFlowLayoutin code, it will override Interface Builder configs. Hence you need to re-define the scrollDirectionagain.

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

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

回答by Prashant Gaikwad

This code works well in Swift 3.1and Xcode 8.3.2

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

    }

回答by Tum

Just for fun, another approach would be to just leave the paging and horizontal scrolling set, add a method that changes the order of the array items to convert from 'top to bottom, left to right' to visually'left to right, top to bottom' and fill the in-between cells with empty hidden cells to make the spacing right. In case of 7 items in a grid of 9, this would go like this:

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

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

should become

应该成为

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

so 1=1, 2=4, 3=7 etc. and 6=empty. You can reorder them by calculating the total number of rows and columns, then calculate the row and column number for each cell, change the row for the column and vice versa and then you have the new indexes. When the cell doesn't have a value corresponding to the image you can return an empty cell and set cell.hidden = YES;to it.

所以 1=1, 2=4, 3=7 等等,6=空。您可以通过计算总行数和列数来重新排序它们,然后计算每个单元格的行数和列数,更改列的行,反之亦然,然后您就有了新的索引。当单元格没有与图像对应的值时,您可以返回一个空单元格并设置cell.hidden = YES;为它。

It works quite well in a soundboard app I built, so if anyone would like working code I'll add it. Only little code is required to make this trick work, it sounds harder than it is!

它在我构建的音板应用程序中运行良好,所以如果有人想要工作代码,我会添加它。只需要很少的代码就可以使这个技巧发挥作用,听起来比实际更难!

Update

更新

I doubt this is the best solution, but by request here's working code:

我怀疑这是最好的解决方案,但应请求这里的工作代码:

- (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;
}

If you'd like to use the didSelectItemAtIndexPathmethod you have to use the same conversion that is used in cellForItemAtIndexPathto get the corresponding item. If you have cell margins you need to add them to the rows and columns calculation, as those have to be correct in order for this to work.

如果您想使用该didSelectItemAtIndexPath方法,您必须使用用于cellForItemAtIndexPath获取相应项目的相同转换。如果您有单元格边距,则需要将它们添加到行和列计算中,因为这些必须正确才能使其正常工作。

回答by Sandip Patel - SM

We can do same Springboard behavior using UICollectionView and for that we need to write code for custom layout.

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

I have achieved it with my custom layout class implementation with "SMCollectionViewFillLayout"

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

Code repository:

代码库:

https://github.com/smindia1988/SMCollectionViewFillLayout

https://github.com/smindia1988/SMCollectionViewFillLayout

Output as below:

输出如下:

1.png

1.png

First.png

第一.png

2_Code_H-Scroll_V-Fill.png

2_Code_H-Scroll_V-Fill.png

enter image description here

在此处输入图片说明

3_Output_H-Scroll_V-Fill.pngenter image description here

3_Output_H-Scroll_V-Fill.png在此处输入图片说明

4_Code_H-Scroll_H-Fill.pngenter image description here

4_Code_H-Scroll_H-Fill.png在此处输入图片说明

5_Output_H-Scroll_H-Fill.pngenter image description here

5_Output_H-Scroll_H-Fill.png在此处输入图片说明

回答by Gulz

for xcode 8 i did this and it worked:

对于 xcode 8,我做了这个并且它有效:

回答by Phan Van Linh

From @Erik Hunter, I post full code for make horizontal UICollectionView

来自@Erik Hunter,我发布了用于制作水平的完整代码 UICollectionView

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

In Swift

在斯威夫特

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

In Swift 3.0

在 Swift 3.0 中

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

Hope this help

希望这有帮助

回答by Narasimha Nallamsetty

I am working on Xcode 6.2 and for horizontal scrolling I have changed scroll direction in attribute inspector.

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

click on collectionView->attribute inspector->scroll Direction->change to horizontal

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

enter image description hereI hope it helps someone.

在此处输入图片说明我希望它可以帮助某人。