UICollectionView 布局像 SnapChat?
Posted
技术标签:
【中文标题】UICollectionView 布局像 SnapChat?【英文标题】:UICollectionView Layout like SnapChat? 【发布时间】:2017-04-03 13:42:33 【问题描述】:我们如何像 SnapChat 的故事一样创建 UICollectionViewLayout?
有什么想法吗?
我想要一个没有外部库的解决方案。
【问题讨论】:
对于不使用Snapshat的人来说,单元格排列背后的逻辑是什么?我给了那里:***.com/questions/42364859/… 一些想法,关于如何做到这一点。您可能只需要安排框架的计算以满足您的需要。 相同的序列将在 exa 中重复。在第三行又是两个项目,在第四行又是 3 个项目? @Larme 我意识到我的截图是错误的,最终让你们感到困惑。对不起。我已经更新了截图。 我意识到我的截图是错误的,最终让你们感到困惑。对不起。我已经更新了截图。 @Swift_Guru @JayVDiyk 感谢您提供更好的解释。我发布了一些你可以使用的东西。 【参考方案1】:基于a precedent answer 适应您的问题:
-(id)initWithSize:(CGSize)size
self = [super init];
if (self)
_unitSize = CGSizeMake(size.width/2,80);
_cellLayouts = [[NSMutableDictionary alloc] init];
return self;
-(void)prepareLayout
for (NSInteger aSection = 0; aSection < [[self collectionView] numberOfSections]; aSection++)
//Create Cells Frames
for (NSInteger aRow = 0; aRow < [[self collectionView] numberOfItemsInSection:aSection]; aRow++)
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:aRow inSection:aSection];
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
NSUInteger i = aRow%3;
NSUInteger j = aRow/3;
CGFloat offsetY = _unitSize.height*2*j;
CGPoint xPoint;
CGFloat height = 0;
BOOL invert = NO;
if (aRow%6 >= 3) //We need to invert Big cell and small cells => xPoint.x
invert = YES;
switch (i)
case 0:
xPoint = CGPointMake((invert?_unitSize.width:0), offsetY);
height = _unitSize.height;
break;
case 1:
xPoint = CGPointMake((invert?_unitSize.width:0), offsetY+_unitSize.height);
height = _unitSize.height;
break;
case 2:
xPoint = CGPointMake((invert?0:_unitSize.width), offsetY);
height = _unitSize.height*2;
break;
default:
break;
CGRect frame = CGRectMake(xPoint.x, xPoint.y, _unitSize.width, height);
[attributes setFrame:frame];
[_cellLayouts setObject:attributes forKey:indexPath];
我将unitSize的高度设置为80,但是如果需要,你可以使用屏幕的大小,比如_unitSize = CGSizeMake(size.width/2,size.height/4.);
。
那个渲染:
旁注:调整逻辑或进行更改取决于您,单元格框架计算可能不是“最好看的代码”。
【讨论】:
您好,由于我对 Obj C 不熟悉,所以我没有检查过它们。如果您能发布一些 swift 版本,那就太好了,不过还是谢谢! @Larme,真的很有帮助。再次感谢。 +1 投票【参考方案2】:UICollectionViewLayout 喜欢 SnapChat 的故事 Like
Swift 3.2 代码
import Foundation
import UIKit
class StoryTwoColumnsLayout : UICollectionViewLayout
fileprivate var cache = [IndexPath: UICollectionViewLayoutAttributes]()
fileprivate var cellPadding: CGFloat = 4
fileprivate var contentHeight: CGFloat = 0
var oldBound: CGRect!
let numberOfColumns:Int = 2
var cellHeight:CGFloat = 255
fileprivate var contentWidth: CGFloat
guard let collectionView = collectionView else
return 0
let insets = collectionView.contentInset
return collectionView.bounds.width - (insets.left + insets.right)
override var collectionViewContentSize: CGSize
return CGSize(width: contentWidth, height: contentHeight)
override func prepare()
super.prepare()
contentHeight = 0
cache.removeAll(keepingCapacity: true)
guard cache.isEmpty == true, let collectionView = collectionView else
return
if collectionView.numberOfSections == 0
return
let cellWidth = contentWidth / CGFloat(numberOfColumns)
cellHeight = cellWidth / 720 * 1220
var xOffset = [CGFloat]()
for column in 0 ..< numberOfColumns
xOffset.append(CGFloat(column) * cellWidth)
var column = 0
var yOffset = [CGFloat](repeating: 0, count: numberOfColumns)
for item in 0 ..< collectionView.numberOfItems(inSection: 0)
let indexPath = IndexPath(item: item, section: 0)
var newheight = cellHeight
if column == 0
newheight = ((yOffset[column + 1] - yOffset[column]) > cellHeight * 0.3) ? cellHeight : (cellHeight * 0.90)
let frame = CGRect(x: xOffset[column], y: yOffset[column], width: cellWidth, height: newheight)
let insetFrame = frame.insetBy(dx: cellPadding, dy: cellPadding)
let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
attributes.frame = insetFrame
cache[indexPath] = (attributes)
contentHeight = max(contentHeight, frame.maxY)
yOffset[column] = yOffset[column] + newheight
if column >= (numberOfColumns - 1)
column = 0
else
column = column + 1
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]?
var visibleLayoutAttributes = [UICollectionViewLayoutAttributes]()
// Loop through the cache and look for items in the rect
visibleLayoutAttributes = cache.values.filter( (attributes) -> Bool in
return attributes.frame.intersects(rect)
)
print(visibleLayoutAttributes)
return visibleLayoutAttributes
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes?
// print(cache[indexPath.item])
return cache[indexPath]
【讨论】:
以上是关于UICollectionView 布局像 SnapChat?的主要内容,如果未能解决你的问题,请参考以下文章
Swift 中的 UICollectionView 自定义布局
UICollectionView中删除一个单元格后刷新单元格布局
如何以编程方式在 UICollectionView 上添加自动布局?