使用动态大小时 uicollectionView 单元格时如何设置特定单元格的大小
How to set Size for a specific cell when using dynamic size uicollectionView cell
我正在学习本教程:
https://www.raywenderlich.com/4829472-uicollectionview-custom-layout-tutorial-pinterest
实现这个布局
基本上 section 1
中的水平 collectionView
和 section 2
中的垂直 collectionView
我的想法是在第一个单元格中放置一个 collectionView,其大小应为:CGSize(width: screen.width, height: 100)
但是由于我使用的是 link 中的方法,所以我不知道如何为第一个单元格指定特定大小。这是我试过的:
为了能够控制集合项的大小,您可以遵循的一种策略是让 UICollection
视图的委托派生自 UICollectionViewDelegateFlowLayout
而不是仅派生自 UICollectionViewDelegate
.通过从 UICollectionViewDelegateFlowLayout
派生,您的委托可以实现:
func collectionView(UICollectionView, layout: UICollectionViewLayout, sizeForItemAt: IndexPath) -> CGSize
并告诉系统第一项的大小。
免责声明: 由于 OP 之前曾询问 question 如何创建 Pinterest 布局,并且我在评论中建议了 Raywenderlich 教程,我相信这个问题来自 OP是
的扩展
答案:
查看您添加的设计,我相信您正在尝试添加带有水平滚动条的 CollectionView
作为跨越整个 collection 视图宽度的第一个单元格。因为您已经对 UICollectionViewFlowLayout
进行了子类化,所以您需要在 prepare
方法本身
中处理这种特殊情况
override func prepare() {
// 1
guard
cache.isEmpty,
let collectionView = collectionView
else {
return
}
// 2
let columnWidth = contentWidth / CGFloat(numberOfColumns)
var xOffset: [CGFloat] = []
for column in 0..<numberOfColumns {
xOffset.append(CGFloat(column) * columnWidth)
}
var column = 0
var yOffset: [CGFloat] = .init(repeating: 0, count: numberOfColumns)
// 3
for item in 0..<collectionView.numberOfItems(inSection: 0) {
let indexPath = IndexPath(item: item, section: 0)
let attributes: UICollectionViewLayoutAttributes
let photoHeight = delegate?.collectionView(
collectionView,
heightForPhotoAtIndexPath: indexPath) ?? 180
let height = cellPadding * 2 + photoHeight
let frame: CGRect
if item == 0 {
frame = CGRect(x: 0,
y: yOffset[column],
width: columnWidth,
height: height)
contentHeight = frame.maxY
for column in 0..<numberOfColumns {
yOffset[column] = frame.maxY
}
column = 0
}
else {
// 4
frame = CGRect(x: xOffset[column],
y: yOffset[column],
width: columnWidth,
height: height)
contentHeight = max(contentHeight, frame.maxY)
yOffset[column] = yOffset[column] + height
column = column < (numberOfColumns - 1) ? (column + 1) : 0
}
let insetFrame = frame.insetBy(dx: cellPadding, dy: cellPadding)
attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
attributes.frame = insetFrame
cache.append(attributes)
}
}
在您的 for item in 0..<collectionView.numberOfItems(inSection: 0) {
中,我添加了一个处理 if item == 0 {
的特殊条件,其中我没有使用列宽,而是使用了内容宽度(根据您的设计,您希望第一个单元格覆盖collection 视图的整个宽度)
终于在您的委托方法中
extension PhotoStreamViewController: PinterestLayoutDelegate {
func collectionView(
_ collectionView: UICollectionView,
heightForPhotoAtIndexPath indexPath:IndexPath) -> CGFloat {
if indexPath.row == 0 {
return 180 // whatever is the height of first cell
}
return photos[indexPath.item].image.size.height
}
}
忠告
在您的设计中,我可以看到您添加了两个部分 headers Header 1 和 Header 2 我想在那种情况下,您返回的部分数量至少为 2,但本教程侧重于单个部分 collection 视图,如果您注意到
for item in 0..<collectionView.numberOfItems(inSection: 0) {
第 0 部分是硬编码的,如果您想处理多个部分并且可能需要围绕 prepare
进行大量修改,您可能必须动态处理它
我正在学习本教程:
https://www.raywenderlich.com/4829472-uicollectionview-custom-layout-tutorial-pinterest
实现这个布局
基本上 section 1
中的水平 collectionView
和 section 2
collectionView
我的想法是在第一个单元格中放置一个 collectionView,其大小应为:CGSize(width: screen.width, height: 100)
但是由于我使用的是 link 中的方法,所以我不知道如何为第一个单元格指定特定大小。这是我试过的:
为了能够控制集合项的大小,您可以遵循的一种策略是让 UICollection
视图的委托派生自 UICollectionViewDelegateFlowLayout
而不是仅派生自 UICollectionViewDelegate
.通过从 UICollectionViewDelegateFlowLayout
派生,您的委托可以实现:
func collectionView(UICollectionView, layout: UICollectionViewLayout, sizeForItemAt: IndexPath) -> CGSize
并告诉系统第一项的大小。
免责声明: 由于 OP 之前曾询问 question 如何创建 Pinterest 布局,并且我在评论中建议了 Raywenderlich 教程,我相信这个问题来自 OP是
的扩展答案:
查看您添加的设计,我相信您正在尝试添加带有水平滚动条的 CollectionView
作为跨越整个 collection 视图宽度的第一个单元格。因为您已经对 UICollectionViewFlowLayout
进行了子类化,所以您需要在 prepare
方法本身
override func prepare() {
// 1
guard
cache.isEmpty,
let collectionView = collectionView
else {
return
}
// 2
let columnWidth = contentWidth / CGFloat(numberOfColumns)
var xOffset: [CGFloat] = []
for column in 0..<numberOfColumns {
xOffset.append(CGFloat(column) * columnWidth)
}
var column = 0
var yOffset: [CGFloat] = .init(repeating: 0, count: numberOfColumns)
// 3
for item in 0..<collectionView.numberOfItems(inSection: 0) {
let indexPath = IndexPath(item: item, section: 0)
let attributes: UICollectionViewLayoutAttributes
let photoHeight = delegate?.collectionView(
collectionView,
heightForPhotoAtIndexPath: indexPath) ?? 180
let height = cellPadding * 2 + photoHeight
let frame: CGRect
if item == 0 {
frame = CGRect(x: 0,
y: yOffset[column],
width: columnWidth,
height: height)
contentHeight = frame.maxY
for column in 0..<numberOfColumns {
yOffset[column] = frame.maxY
}
column = 0
}
else {
// 4
frame = CGRect(x: xOffset[column],
y: yOffset[column],
width: columnWidth,
height: height)
contentHeight = max(contentHeight, frame.maxY)
yOffset[column] = yOffset[column] + height
column = column < (numberOfColumns - 1) ? (column + 1) : 0
}
let insetFrame = frame.insetBy(dx: cellPadding, dy: cellPadding)
attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
attributes.frame = insetFrame
cache.append(attributes)
}
}
在您的 for item in 0..<collectionView.numberOfItems(inSection: 0) {
中,我添加了一个处理 if item == 0 {
的特殊条件,其中我没有使用列宽,而是使用了内容宽度(根据您的设计,您希望第一个单元格覆盖collection 视图的整个宽度)
终于在您的委托方法中
extension PhotoStreamViewController: PinterestLayoutDelegate {
func collectionView(
_ collectionView: UICollectionView,
heightForPhotoAtIndexPath indexPath:IndexPath) -> CGFloat {
if indexPath.row == 0 {
return 180 // whatever is the height of first cell
}
return photos[indexPath.item].image.size.height
}
}
忠告
在您的设计中,我可以看到您添加了两个部分 headers Header 1 和 Header 2 我想在那种情况下,您返回的部分数量至少为 2,但本教程侧重于单个部分 collection 视图,如果您注意到
for item in 0..<collectionView.numberOfItems(inSection: 0) {
第 0 部分是硬编码的,如果您想处理多个部分并且可能需要围绕 prepare