首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >UICollectionViewCompositionalLayout瀑布

UICollectionViewCompositionalLayout瀑布
EN

Stack Overflow用户
提问于 2021-02-17 15:01:55
回答 1查看 190关注 0票数 2

请有人指导我如何创建一个“瀑布”布局。到目前为止,我所创造的是下面。但正如你所看到的,我想要去掉间隔。

代码语言:javascript
复制
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
}

EN

回答 1

Stack Overflow用户

发布于 2022-10-31 12:56:18

经过大量的研究,我发现了一个实用的布局。https://github.com/eeshishko/WaterfallTrueCompositionalLayout

要创建瀑布/兴趣布局,可以创建单个自定义组,并按其框架和索引插入每个项,而不是提供布局大小。

可以将外部边框视为组,将每一列视为项:

若要创建必须使用NSCollectionLayoutGroup.custom的组,请执行以下操作。自定义组需要一个layoutSize和一个itemProvider。布局的大小将是整个collectionView。

layoutSize:

代码语言:javascript
复制
let groupLayoutSize = NSCollectionLayoutSize(
            widthDimension: .fractionalWidth(1),
            heightDimension: .absolute(itemProvider.maxColumnHeight()) // the height calculation of the whole collectionView
        )

itemProvider的类型是:NSCollectionLayoutGroupCustomItemProvider,它是一个包含NSCollectionLayoutEnvironment并返回NSCollectionLayoutGroupCustomItem数组的闭包的类型别名。

代码语言:javascript
复制
let group = NSCollectionLayoutGroup.custom(layoutSize: groupLayoutSize) { _ in
    // here we need to return an array of NSCollectionLayoutGroupCustomItem
}

现在,对每个项目的框架的计算将决定组中每个项目的排列。

代码语言:javascript
复制
        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:

代码语言:javascript
复制
func makeLayoutItem(for row: Int) -> NSCollectionLayoutGroupCustomItem {
            let frame = frame(for: row)
            columnHeights[columnIndex()] = frame.maxY + interItemSpacing
            return NSCollectionLayoutGroupCustomItem(frame: frame)
        }

框架:

代码语言:javascript
复制
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)
    }

配置:

代码语言:javascript
复制
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

现在,我可以在创建布局时将图像的高度返回到闭包:

代码语言:javascript
复制
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上创建了一个完全工作的演示项目。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66244562

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档