因此,我尝试使用UICollectionView实现标记列表。我遵循本教程:http://www.cocoanetics.com/2013/08/variable-sized-items-in-uicollectionview/
问题是UICollectionView中的流布局尝试均匀地分隔同一行上的项目。
作为开发人员,我只能指定minimumInteritemSpacingForSectionAtIndex,它确实取决于UICollectionView以确定实际的项目间距。
但我真正想要实现的是:
有什么想法吗?
答案 0 :(得分:8)
我已将Milo的解决方案转换为Swift: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
// 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
}
}
答案 1 :(得分:0)
Apple为我们的开发人员提供了UICollectionViewFlowLayout类,这应该足以解决集合视图的“典型用例”。但是,我相信您的评估是正确的,默认布局不允许您创建此标签云效果。如果您需要与普通流布局不同的东西,则必须编写自己的UICollectionViewLayout子类。
Apple在2012年WWDC会议中介绍了这个主题,题为“高级集合视图和构建自定义布局”
冒着看似有偏见的风险,我还写了一篇快速的博客文章,贯穿基本步骤:http://bradbambara.wordpress.com/2014/05/24/getting-started-with-custom-uicollectionview-layouts/
希望有所帮助。