水平滚动,水平布局?

我有一个 UIScrollView,布局了一个网格的图标。如果你想象一下 iOSSpringboard 的布局,你会发现它已经非常接近正确了。它有一个水平的、分页的滚动条(就像 Springboard 一样)。但是,布局似乎并不完全正确。它看起来好像是从上到下的排列项目。因此,由于要显示的项目数,我的上一列只有2行。我更希望最后一页的最后一行有两个项目,就像你在 Springboard 中看到的那样。

如何能做到这一点与 UICollectionView及其相关的类? 我必须写一个自定义的 UICollectionViewFlowLayout

206035 次浏览

第一次进场

如何对 UICollectionViewControllers数组使用 UIPageViewController?您必须在每个 UICollectionViewController中获取适当数量的项目,但这并不困难。你会得到和 Springboard 一模一样的表情。

第二次进场

我已经考虑过了,在我看来,你必须设定:

self.collectionView.pagingEnabled = YES;

并通过子类化 UICollectionViewLayout创建您自己的集合视图布局。通过自定义布局对象,可以访问 self.collectionView,这样就可以知道集合视图的 framenumberOfSectionsnumberOfItemsInSection:的大小。有了这些信息,你就可以计算细胞的 frames(在 prepareLayout中)和 collectionViewContentSize。下面是一些关于创建自定义布局的文章:

第三次进场

您可以在不创建自定义布局的情况下做到这一点(或者近似地做到这一点)。在空白视图中添加 UIScrollView,在其中设置启用的分页。在滚动视图中添加集合视图。然后给它添加一个宽度约束,检查代码中有多少条目,并将其 constant设置为正确的值,例如 (self.view.frame.size.width * numOfScreens)。它看起来是这样的(细胞上的数字显示的是 indexPath.row) : https://www.dropbox.com/s/ss4jdbvr511azxz/collection_view.mov如果你对细胞的排列方式不满意,那么恐怕你只能选择1。或2。

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

[yourFlowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];

如果你想让它像 Springboard 那样进行分页,你需要在你的集合视图上启用分页,如下所示:

[yourCollectionView setPagingEnabled:YES];

为了好玩,另一种方法是离开分页和水平滚动设置,添加一个方法,改变数组项目的顺序,从“从上到下,从左到右”转换为 视觉上“从左到右,从上到下”,填充中间的单元格与空的隐藏单元格,使间距正确。如果在一个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中相同的转换来获得相应的项。如果有单元格边距,则需要将它们添加到行和列计算中,因为这些行和列必须是正确的才能正常工作。

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

enter image description here

我工作在 Xcode 6.2和水平滚动,我已经改变了滚动方向的属性检查器。

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

enter image description here我希望能帮到别人。

如果你在代码中定义 UICollectionViewFlowLayout,它会覆盖 Interface Builder 配置。因此,您需要重新定义 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;

在斯威夫特

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

First.png

2 _ Code _ H-Scroll _ V-fill. png

enter image description here

3 _ Output _ H-Scroll _ V-fill. png enter image description here

4 _ Code _ H-Scroll _ H-fill. png enter image description here

5 _ Output _ H-Scroll _ H-fill. png enter image description here

对于 xcode 8,我这样做了,并且成功了:

你可以编写一个自定义的 UICollectionView布局来实现这一点,这里是我的实现演示图片:

demo image

这是代码存储库: KSTCollectionViewPageHorizontalLayout

@ iPhoneDev (这也许也能帮到你)

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


}

如果您需要设置 UICollectionView 滚动方向水平和您需要设置单元格的宽度和高度静态。 请将集合视图估计大小 自动的设置为 没有

查看屏幕截图

创建 UICollectionView 并使其水平滚动

lazy var collectionView: UICollectionView = {
    

let layout = UICollectionViewFlowLayout()
// horizontal scroll
layout.scrollDirection = .horizontal
    

//CollectionCellView width autoSize
layout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
    

let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.translatesAutoresizingMaskIntoConstraints = false
    

collectionView.register(CustomCollectionViewCell.self, forCellWithReuseIdentifier: cellId)
    

collectionView.delegate = self
collectionView.dataSource = self
collectionView.alwaysBounceHorizontal = true
    

return collectionView
}()

对于 iOS13及以上版本,请尝试 UICollectionViewCompostionalLayout。

下面只是一个理解的例子。

collectionView.collectionViewLayout = createCompositionalLayout()


private func createCompositionalLayout() -> UICollectionViewLayout {
let layouts = UICollectionViewCompositionalLayout.init { sectionIndex, environment in
self.horizontalSection()
}
return layouts
}
    

private func horizontalSection() -> NSCollectionLayoutSection {
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1),
heightDimension: .fractionalHeight(1))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(200))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize,
subitems: [item])
let section = NSCollectionLayoutSection(group: group)
section.interGroupSpacing = 16
section.orthogonalScrollingBehavior = .paging
return section
}