请有人指导我如何创建一个“瀑布”布局。到目前为止,我所创造的是下面。但正如你所看到的,我想要去掉间隔。
func createTwoColumnsLayout() -> UICollectionViewLayout {
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(250))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(250))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: item, count: 2)
let spacing = CGFloat(10)
group.interItemSpacing = .fixed(spacing)
let section = NSCollectionLayoutSection(group: group)
section.interGroupSpacing = spacing
section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10)
let layout = UICollectionViewCompositionalLayout(section: section)
return layout
}

发布于 2022-10-31 12:56:18
经过大量的研究,我发现了一个实用的布局。https://github.com/eeshishko/WaterfallTrueCompositionalLayout
要创建瀑布/兴趣布局,可以创建单个自定义组,并按其框架和索引插入每个项,而不是提供布局大小。
可以将外部边框视为组,将每一列视为项:

若要创建必须使用NSCollectionLayoutGroup.custom的组,请执行以下操作。自定义组需要一个layoutSize和一个itemProvider。布局的大小将是整个collectionView。
layoutSize:
let groupLayoutSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1),
heightDimension: .absolute(itemProvider.maxColumnHeight()) // the height calculation of the whole collectionView
)itemProvider的类型是:NSCollectionLayoutGroupCustomItemProvider,它是一个包含NSCollectionLayoutEnvironment并返回NSCollectionLayoutGroupCustomItem数组的闭包的类型别名。
let group = NSCollectionLayoutGroup.custom(layoutSize: groupLayoutSize) { _ in
// here we need to return an array of NSCollectionLayoutGroupCustomItem
}现在,对每个项目的框架的计算将决定组中每个项目的排列。
var items = [NSCollectionLayoutGroupCustomItem]()
let itemProvider = LayoutBuilder( // responsible for the calculations of the watefall layout
configuration: config,
collectionWidth: enviroment.container.contentSize.width
)
for i in 0..<config.itemCountProvider() {
let item = itemProvider.makeLayoutItem(for: i)
items.append(item)
}makeLayoutItem:
func makeLayoutItem(for row: Int) -> NSCollectionLayoutGroupCustomItem {
let frame = frame(for: row)
columnHeights[columnIndex()] = frame.maxY + interItemSpacing
return NSCollectionLayoutGroupCustomItem(frame: frame)
}框架:
func frame(for row: Int) -> CGRect {
let width = columnWidth
let height = itemHeightProvider(row, width)
let size = CGSize(width: width, height: height)
let origin = itemOrigin(width: size.width)
return CGRect(origin: origin, size: size)
}配置:
struct Configuration {
public let columnCount: Int
public let interItemSpacing: CGFloat
public let sectionHorizontalSpacing: CGFloat
public let contentInsetsReference: UIContentInsetsReference
public let itemHeightProvider: ItemHeightProvider
public let itemCountProvider: ItemCountProvider
public init(
columnCount: Int = 2,
interItemSpacing: CGFloat = 8,
sectionHorizontalSpacing: CGFloat = 0,
contentInsetsReference: UIContentInsetsReference = .automatic,
itemCountProvider: @escaping ItemCountProvider,
itemHeightProvider: @escaping ItemHeightProvider
) {
self.columnCount = columnCount
self.interItemSpacing = interItemSpacing
self.sectionHorizontalSpacing = sectionHorizontalSpacing * 2
self.contentInsetsReference = contentInsetsReference
self.itemCountProvider = itemCountProvider
self.itemHeightProvider = itemHeightProvider
}
}现在唯一缺少的是,我们事先不知道每个项目的大小。LayoutBuilder必须知道每个项目的高度来计算框架。这可以通过像https://www.kodeco.com/4829472-uicollectionview-custom-layout-tutorial-pinterest这样的委托来实现,也可以通过像本例中那样的闭包来实现:
typealias ItemHeightProvider = (_ index: Int, _ itemWidth: CGFloat) -> CGFloat
现在,我可以在创建布局时将图像的高度返回到闭包:
let layout = WaterfallTrueCompositionalLayout.makeLayoutSection(
config: .init(
columnCount: 2,
interItemSpacing: 10,
sectionHorizontalSpacing: sectionHorizontalSpacing,
itemCountProvider: {
return items.count
},
itemHeightProvider: { index, _ in
return items[index].image.size.height
}),
enviroment: env, sectionIndex: 1
)由于还有很多需要讨论的内容,所以我在github:https://github.com/vebbis321/WaterfallCompostionalLayout上创建了一个完全工作的演示项目。
https://stackoverflow.com/questions/66244562
复制相似问题