具有多个部分的 UICollectionView
UICollectionView with multiple sections
大家好,我需要在水平滚动的 collectionView
中显示 2 个部分。
在第一部分我需要 10 个单元格,在第二部分我需要 9 个单元格
我已经用这种方式实现了,但我不明白为什么当我 select 第 2 节的单元格时 indexPath.item
的值是第 1 节 [=14= 的单元格的值]
编辑
如您所见,我的 collectionView 有 2 个部分,设置单元格是这样的。我不需要像这样显示单元格,但我需要第 1 部分位于第一行并且它必须显示这样的项目都在同一行 (0,1 2 3 4 5)
和底部行的第 2 部分,并显示与顶部行相同的项目
我哪里做错了?
private func commonInit() -> Void {
backgroundColor = .clear
let cv = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
cv.backgroundColor = .clear
cv.delegate = self
cv.dataSource = self
cv.isPagingEnabled = true
cv.showsHorizontalScrollIndicator = false
addSubview(cv)
if let layout = cv.collectionViewLayout as? UICollectionViewFlowLayout {
layout.scrollDirection = .horizontal }
TimeSelectorCell.register(in: cv)
cv.anchor(top: topAnchor, leading: leadingAnchor, bottom: bottomAnchor, trailing: trailingAnchor)
}
func numberOfSections(in collectionView: UICollectionView) -> Int { 2 }
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if section == 0 { return 10 }
else { return 9 }
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TimeSelectorCell.cellIdentifier, for: indexPath) as! TimeSelectorCell
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print(indexPath.item)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
.init(width: collectionView.frame.width / 4 , height: collectionView.frame.height / 2)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { 0 }
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { 0 }
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if (indexPath.section == 0 )
{
// cell of section 1
print(indexPath.item)
}else{
// cell of section 2
print(indexPath.item)
}
}
你可以试试!
在这种情况下,您必须使用 iOS 13 的 CollectionView Compositional Layouts。这里有2个教程让你了解它 -
- https://www.zealousweb.com/how-to-use-compositional-layout-in-collection-view/
- https://medium.com/better-programming/ios-13-compositional-layouts-in-collectionview-90a574b410b8
- WWDC 视频 - https://developer.apple.com/videos/play/wwdc2019/215/
对于您的情况,我已经调整了第二个教程中的示例
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return (section == 0) ? 10 : 9
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 2
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print(indexPath)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TimeSelectorCell.cellIdentifier, for: indexPath) as! TimeSelectorCell
return cell
}
private func commonInit() {
let cv = UICollectionView(frame: view.bounds, collectionViewLayout: createLayoutDiffSection())
cv.autoresizingMask = [.flexibleWidth, .flexibleHeight]
TimeSelectorCell.register(in: cv)
cv.dataSource = self
cv.delegate = self
addSubview(cv)
}
到目前为止,它与您的代码几乎相同。现在 createLayoutDiffSection() 方法是 -
func createLayoutDiffSection() -> UICollectionViewLayout {
let layout = UICollectionViewCompositionalLayout { (sectionIndex: Int,
layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in
let seperateFlow = true
let columns = (sectionIndex == 0) ? 10 : 9
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalHeight(1.0))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
item.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 2, bottom: 0, trailing: 2)
let groupHeight = NSCollectionLayoutDimension.fractionalWidth(0.2)
let widthFraction:CGFloat = (sectionIndex == 0) ? 1 : 0.9
let groupSizeWidth:CGFloat = seperateFlow ? (widthFraction * 2) : 1
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(groupSizeWidth),
heightDimension: groupHeight)
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: item, count: columns)
let section = NSCollectionLayoutSection(group: group)
if seperateFlow {
section.orthogonalScrollingBehavior = .continuous
}
section.contentInsets = NSDirectionalEdgeInsets(top: 20, leading: 0, bottom: 20, trailing: 0)
return section
}
return layout
}
如果两个部分的滚动不是分开的,则设置 -
let seperateFlow = false
这里要理解的要点是 -
尺码类
我们可以根据需要使用四种大小选项,这样就无需计算即可获得所需的输出。让我们看看所有的尺寸 类:
- fractionalWidth():使用 fractionalWidth 我们可以设置 width/height
单元格的比例与其 parent 的宽度
- 小数高度():
使用 fractionalHeight,我们可以设置单元格的 width/height
与其 parent 的高度成比例
- absolute(): 使用绝对
值,我们可以将单元格的width/height设置为固定值
- estimate():使用估计值,我们可以设置单元格的width/height
根据内容大小。系统会决定最优
width/height 内容。
核心概念
要构建任何组合布局,需要实现以下四个 类:
- NSCollectionLayoutSize — 宽度和高度尺寸是
输入 NSCollectionLayoutDimension 可以通过设置
布局的小数 width/height(相对于它的百分比
容器),或通过设置绝对或估计大小。
- NSCollectionLayoutItem — 这是布局的单元格
基于尺寸的屏幕。
- NSCollectionLayoutGroup — 它以水平、垂直或自定义形式保存 NSCollectionLayoutItem。
- NSCollectionLayoutSection — 这用于通过传递 NSCollectionLayoutGroup 来初始化该部分。部分最终构成组合布局。
大家好,我需要在水平滚动的 collectionView
中显示 2 个部分。
在第一部分我需要 10 个单元格,在第二部分我需要 9 个单元格
我已经用这种方式实现了,但我不明白为什么当我 select 第 2 节的单元格时 indexPath.item
的值是第 1 节 [=14= 的单元格的值]
编辑
如您所见,我的 collectionView 有 2 个部分,设置单元格是这样的。我不需要像这样显示单元格,但我需要第 1 部分位于第一行并且它必须显示这样的项目都在同一行 (0,1 2 3 4 5) 和底部行的第 2 部分,并显示与顶部行相同的项目
我哪里做错了?
private func commonInit() -> Void {
backgroundColor = .clear
let cv = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
cv.backgroundColor = .clear
cv.delegate = self
cv.dataSource = self
cv.isPagingEnabled = true
cv.showsHorizontalScrollIndicator = false
addSubview(cv)
if let layout = cv.collectionViewLayout as? UICollectionViewFlowLayout {
layout.scrollDirection = .horizontal }
TimeSelectorCell.register(in: cv)
cv.anchor(top: topAnchor, leading: leadingAnchor, bottom: bottomAnchor, trailing: trailingAnchor)
}
func numberOfSections(in collectionView: UICollectionView) -> Int { 2 }
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if section == 0 { return 10 }
else { return 9 }
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TimeSelectorCell.cellIdentifier, for: indexPath) as! TimeSelectorCell
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print(indexPath.item)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
.init(width: collectionView.frame.width / 4 , height: collectionView.frame.height / 2)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { 0 }
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { 0 }
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if (indexPath.section == 0 )
{
// cell of section 1
print(indexPath.item)
}else{
// cell of section 2
print(indexPath.item)
}
}
你可以试试!
在这种情况下,您必须使用 iOS 13 的 CollectionView Compositional Layouts。这里有2个教程让你了解它 -
- https://www.zealousweb.com/how-to-use-compositional-layout-in-collection-view/
- https://medium.com/better-programming/ios-13-compositional-layouts-in-collectionview-90a574b410b8
- WWDC 视频 - https://developer.apple.com/videos/play/wwdc2019/215/
对于您的情况,我已经调整了第二个教程中的示例
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return (section == 0) ? 10 : 9
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 2
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print(indexPath)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TimeSelectorCell.cellIdentifier, for: indexPath) as! TimeSelectorCell
return cell
}
private func commonInit() {
let cv = UICollectionView(frame: view.bounds, collectionViewLayout: createLayoutDiffSection())
cv.autoresizingMask = [.flexibleWidth, .flexibleHeight]
TimeSelectorCell.register(in: cv)
cv.dataSource = self
cv.delegate = self
addSubview(cv)
}
到目前为止,它与您的代码几乎相同。现在 createLayoutDiffSection() 方法是 -
func createLayoutDiffSection() -> UICollectionViewLayout {
let layout = UICollectionViewCompositionalLayout { (sectionIndex: Int,
layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in
let seperateFlow = true
let columns = (sectionIndex == 0) ? 10 : 9
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalHeight(1.0))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
item.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 2, bottom: 0, trailing: 2)
let groupHeight = NSCollectionLayoutDimension.fractionalWidth(0.2)
let widthFraction:CGFloat = (sectionIndex == 0) ? 1 : 0.9
let groupSizeWidth:CGFloat = seperateFlow ? (widthFraction * 2) : 1
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(groupSizeWidth),
heightDimension: groupHeight)
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: item, count: columns)
let section = NSCollectionLayoutSection(group: group)
if seperateFlow {
section.orthogonalScrollingBehavior = .continuous
}
section.contentInsets = NSDirectionalEdgeInsets(top: 20, leading: 0, bottom: 20, trailing: 0)
return section
}
return layout
}
如果两个部分的滚动不是分开的,则设置 -
let seperateFlow = false
这里要理解的要点是 -
尺码类
我们可以根据需要使用四种大小选项,这样就无需计算即可获得所需的输出。让我们看看所有的尺寸 类:
- fractionalWidth():使用 fractionalWidth 我们可以设置 width/height 单元格的比例与其 parent 的宽度
- 小数高度(): 使用 fractionalHeight,我们可以设置单元格的 width/height 与其 parent 的高度成比例
- absolute(): 使用绝对 值,我们可以将单元格的width/height设置为固定值
- estimate():使用估计值,我们可以设置单元格的width/height 根据内容大小。系统会决定最优 width/height 内容。
核心概念
要构建任何组合布局,需要实现以下四个 类:
- NSCollectionLayoutSize — 宽度和高度尺寸是 输入 NSCollectionLayoutDimension 可以通过设置 布局的小数 width/height(相对于它的百分比 容器),或通过设置绝对或估计大小。
- NSCollectionLayoutItem — 这是布局的单元格 基于尺寸的屏幕。
- NSCollectionLayoutGroup — 它以水平、垂直或自定义形式保存 NSCollectionLayoutItem。
- NSCollectionLayoutSection — 这用于通过传递 NSCollectionLayoutGroup 来初始化该部分。部分最终构成组合布局。