how do we create a UICollectionViewLayout like the SnapChat's stories?
Any ideas please?
I'd like to have a solution without external library.
Larme
Based on a precedent answer adapted to your issue:
-(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];
}
}
}
I set the height of unitSize to 80, but you can use the size of the screen if needed, like _unitSize = CGSizeMake(size.width/2,size.height/4.);.
Side note: It's up to you to adapt the logic, or do changes, the cell frames calculation may not be the "best looking piece of code".
UICollectionViewLayout like the SnapChat's stories Like

Swift 3.2 Code
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]
}
}
来源:https://stackoverflow.com/questions/43186246/uicollectionview-layout-like-snapchat

