使用流布局固定 UICollectionView 中项目之间的间距 [英] Fixed spacing between item in UICollectionView with flow layout

查看:29
本文介绍了使用流布局固定 UICollectionView 中项目之间的间距的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以,我正在尝试使用 UICollectionView 实现一个标签列表.我正在关注本教程:,实际上由 UICollectionView 决定实际的项目间距.

但我真正想要实现的是这样的:

有什么想法吗?

解决方案

我已将 Milo 的解决方案转换为 Swift:https://github.com/Coeur/UICollectionViewLeftAlignedLayout/

它只是对 UICollectionViewFlowLayout 进行子类化.

导入 UIKit/*** 简单的 UICollectionViewFlowLayout 将单元格向左对齐而不是对齐它们** 基于 https://stackoverflow.com/questions/13017257/how-do-you-determine-spacing-between-cells-in-uicollectionview-flowlayout*/打开类 UICollectionViewLeftAlignedLayout: UICollectionViewFlowLayout {打开覆盖 func layoutAttributesForElements(in rect: CGRect) ->[UICollectionViewLayoutAttributes]?{return super.layoutAttributesForElements(in: rect)?.map { $0.representedElementKind == nil ?layoutAttributesForItem(at: $0.indexPath)!: $0 }}打开覆盖 func layoutAttributesForItem(at indexPath: IndexPath) ->UICollectionViewLayoutAttributes?{守卫让 currentItemAttributes = super.layoutAttributesForItem(at: indexPath)?.copy() as?UICollectionViewLayoutAttributes,让 collectionView = self.collectionView else {//不应该发生返回零}让 sectionInset =evaluateSectionInsetForSection(at: indexPath.section)守卫 indexPath.item != 0 else {currentItemAttributes.leftAlignFrame(withSectionInset: sectionInset)返回 currentItemAttributes}guard let previousFrame = layoutAttributesForItem(at: IndexPath(item: indexPath.item - 1, section: indexPath.section))?.frame else {//不应该发生返回零}//如果当前帧,一旦左对齐到左边并拉伸到完整的集合视图//宽度与前一帧相交,然后它们在同一条线上守卫previousFrame.intersects(CGRect(x:sectionInset.left,y:currentItemAttributes.frame.origin.y,宽度:collectionView.frame.width - sectionInset.left - sectionInset.right,高度:currentItemAttributes.frame.size.height))别的 {//确保一行中的第一项左对齐currentItemAttributes.leftAlignFrame(withSectionInset: sectionInset)返回 currentItemAttributes}currentItemAttributes.frame.origin.x = previousFrame.origin.x + previousFrame.size.width +evaluateMinimumInteritemSpacingForSection(at: indexPath.section)返回 currentItemAttributes}func评估MinimumInteritemSpacingForSection(在部分:NSInteger)->CGFloat {return (collectionView?.delegate as? UICollectionViewDelegateFlowLayout)?.collectionView?(collectionView!, layout: self, minimumInteritemSpacingForSectionAt: section) ??最小项间间距}函数评估部分InsetForSection(在索引处:NSInteger)->UIEdgeInsets {return (collectionView?.delegate as? UICollectionViewDelegateFlowLayout)?.collectionView?(collectionView!, layout: self, insetForSectionAt: index) ??部分插入}}扩展 UICollectionViewLayoutAttributes {func leftAlignFrame(withSectionInset sectionInset: UIEdgeInsets) {frame.origin.x = sectionInset.left}}

So, I'm trying to implement a tag list with UICollectionView. I'm following this tutorial: http://www.cocoanetics.com/2013/08/variable-sized-items-in-uicollectionview/

The issue is flow layout in UICollectionView tries to space items on the same row evenly.

As a developer, I can only specify minimumInteritemSpacingForSectionAtIndex, it's really up to the UICollectionView to determine the actual item spacing.

But what I really want to achieve is like this:

Any ideas?

解决方案

I've converted Milo's solution to Swift: https://github.com/Coeur/UICollectionViewLeftAlignedLayout/

It simply subclasses UICollectionViewFlowLayout.

import UIKit

/**
 *  Simple UICollectionViewFlowLayout that aligns the cells to the left rather than justify them
 *
 *  Based on https://stackoverflow.com/questions/13017257/how-do-you-determine-spacing-between-cells-in-uicollectionview-flowlayout
 */
open class UICollectionViewLeftAlignedLayout: UICollectionViewFlowLayout {
    open override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        return super.layoutAttributesForElements(in: rect)?.map { $0.representedElementKind == nil ? layoutAttributesForItem(at: $0.indexPath)! : $0 }
    }

    open override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        guard let currentItemAttributes = super.layoutAttributesForItem(at: indexPath)?.copy() as? UICollectionViewLayoutAttributes,
            let collectionView = self.collectionView else {
            // should never happen
            return nil
        }

        let sectionInset = evaluatedSectionInsetForSection(at: indexPath.section)

        guard indexPath.item != 0 else {
            currentItemAttributes.leftAlignFrame(withSectionInset: sectionInset)
            return currentItemAttributes
        }

        guard let previousFrame = layoutAttributesForItem(at: IndexPath(item: indexPath.item - 1, section: indexPath.section))?.frame else {
            // should never happen
            return nil
        }

        // if the current frame, once left aligned to the left and stretched to the full collection view
        // width intersects the previous frame then they are on the same line
        guard previousFrame.intersects(CGRect(x: sectionInset.left, y: currentItemAttributes.frame.origin.y, width: collectionView.frame.width - sectionInset.left - sectionInset.right, height: currentItemAttributes.frame.size.height)) else {
            // make sure the first item on a line is left aligned
            currentItemAttributes.leftAlignFrame(withSectionInset: sectionInset)
            return currentItemAttributes
        }

        currentItemAttributes.frame.origin.x = previousFrame.origin.x + previousFrame.size.width + evaluatedMinimumInteritemSpacingForSection(at: indexPath.section)
        return currentItemAttributes
    }

    func evaluatedMinimumInteritemSpacingForSection(at section: NSInteger) -> CGFloat {
        return (collectionView?.delegate as? UICollectionViewDelegateFlowLayout)?.collectionView?(collectionView!, layout: self, minimumInteritemSpacingForSectionAt: section) ?? minimumInteritemSpacing
    }

    func evaluatedSectionInsetForSection(at index: NSInteger) -> UIEdgeInsets {
        return (collectionView?.delegate as? UICollectionViewDelegateFlowLayout)?.collectionView?(collectionView!, layout: self, insetForSectionAt: index) ?? sectionInset
    }
}

extension UICollectionViewLayoutAttributes {
    func leftAlignFrame(withSectionInset sectionInset: UIEdgeInsets) {
        frame.origin.x = sectionInset.left
    }
}

这篇关于使用流布局固定 UICollectionView 中项目之间的间距的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆