类似SnapChat的UICollectionView布局?

3
如何创建类似SnapChat故事的UICollectionViewLayout?
请问有什么想法吗?

enter image description here

我希望能有一个不需要外部库的解决方案。


1
对于那些不使用Snapchat的人来说,单元格排列背后的逻辑是什么?我在这里提供了一些想法:http://stackoverflow.com/questions/42364859/cells-order-in-uicollectionview/42365978#42365978,告诉你如何实现它。您可能需要调整框架计算以适应您的需求。 - Larme
同样的顺序会重复吗?例如,在第三行中再次出现两个项目,在第四行中再次出现3个项目? - Punit
@Larme 我发现我的截图有误,导致你们产生了困惑。非常抱歉。我已经更新了截图。 - JayVDiyk
你可以尝试使用https://github.com/iwheelbuy/SquareMosaicLayout。 - iWheelBuy
https://medium.com/@cp-satish-v/mosaic-layout-with-uicollectionview-uicollectionviewcompositionallayout-6e4b668503bf - SPatel
显示剩余2条评论
2个回答

3

根据一个先前的回答适应您的问题:

-(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.);
这将呈现出以下效果: enter image description here 另外注意:适应逻辑或进行更改取决于您,单元格框架计算可能不是“最好看的代码片段”。

你好,因为我不熟悉 Obj C,所以我还没有查看它们。如果你能发布一些 Swift 版本的话,那就太棒了,但无论如何还是感谢你! - JayVDiyk
@Larme,真的非常有帮助。再次感谢。+1 投票 - Jekil Patel

2

类似SnapChat故事的UICollectionViewLayout

enter image description here


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]
    }

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接