2014-07-07 69 views
4

所以,我试图用UICollectionView实现一个标签列表。我正在学习本教程:http://www.cocoanetics.com/2013/08/variable-sized-items-in-uicollectionview/UICollectionView中的项目与流布局之间的固定间距

问题是UICollectionView中的流布局尝试均匀地在同一行上放置项目。

enter image description here

作为一个开发者,我只能指定minimumInteritemSpacingForSectionAtIndex,这真的到UICollectionView来确定实际的项目间距。

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

enter image description here

任何想法?

回答

0

Apple为我们的开发人员提供了UICollectionViewFlowLayout类,它应该足以解决集合视图的“典型用例”。但是,我相信您的评估中您的默认布局不允许您创建此标签云效果是正确的。如果你需要与普通流布局不同的东西,你必须编写你自己的UICollectionViewLayout的子类。

苹果涵盖在他们的2012 WWDC会议这个主题名为“高级收集意见和构建自定义布局”

一些额外的苹果文档:https://developer.apple.com/library/ios/documentation/WindowsViews/Conceptual/CollectionViewPGforIOS/CreatingCustomLayouts/CreatingCustomLayouts.html

在看似偏颇的风险,我也写了一个快速博客文章贯穿基本步骤:http://bradbambara.wordpress.com/2014/05/24/getting-started-with-custom-uicollectionview-layouts/

希望有所帮助。

3

我已经转换米洛的解决方案,斯威夫特:https://github.com/Coeur/UICollectionViewLeftAlignedLayout/

它只是子类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 
     // widht 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 
    } 
}