mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00

git-subtree-dir: submodules/AsyncDisplayKit git-subtree-mainline: d06f423e0ed3df1fed9bd10d79ee312a9179b632 git-subtree-split: 02bedc12816e251ad71777f9d2578329b6d2bef6
232 lines
8.1 KiB
Objective-C
232 lines
8.1 KiB
Objective-C
//
|
|
// MosaicCollectionViewLayout.m
|
|
// Texture
|
|
//
|
|
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
|
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
|
|
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
|
|
#import "MosaicCollectionViewLayout.h"
|
|
|
|
@implementation MosaicCollectionViewLayout {
|
|
NSMutableArray *_columnHeights;
|
|
NSMutableArray *_itemAttributes;
|
|
NSMutableDictionary *_headerAttributes;
|
|
NSMutableArray *_allAttributes;
|
|
}
|
|
|
|
- (instancetype)init
|
|
{
|
|
self = [super init];
|
|
if (self != nil) {
|
|
self.numberOfColumns = 3;
|
|
self.columnSpacing = 10.0;
|
|
self.sectionInset = UIEdgeInsetsMake(10.0, 10.0, 10.0, 10.0);
|
|
self.interItemSpacing = UIEdgeInsetsMake(10.0, 0, 10.0, 0);
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)prepareLayout
|
|
{
|
|
_itemAttributes = [NSMutableArray array];
|
|
_columnHeights = [NSMutableArray array];
|
|
_allAttributes = [NSMutableArray array];
|
|
_headerAttributes = [NSMutableDictionary dictionary];
|
|
|
|
CGFloat top = 0;
|
|
|
|
NSInteger numberOfSections = [self.collectionView numberOfSections];
|
|
for (NSUInteger section = 0; section < numberOfSections; section++) {
|
|
NSInteger numberOfItems = [self.collectionView numberOfItemsInSection:section];
|
|
|
|
top += _sectionInset.top;
|
|
|
|
if (_headerHeight > 0) {
|
|
CGSize headerSize = [self _headerSizeForSection:section];
|
|
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes
|
|
layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader
|
|
withIndexPath:[NSIndexPath indexPathForItem:0 inSection:section]];
|
|
attributes.frame = CGRectMake(_sectionInset.left, top, headerSize.width, headerSize.height);
|
|
_headerAttributes[@(section)] = attributes;
|
|
[_allAttributes addObject:attributes];
|
|
top = CGRectGetMaxY(attributes.frame);
|
|
}
|
|
|
|
[_columnHeights addObject:[NSMutableArray array]];
|
|
for (NSUInteger idx = 0; idx < self.numberOfColumns; idx++) {
|
|
[_columnHeights[section] addObject:@(top)];
|
|
}
|
|
|
|
CGFloat columnWidth = [self _columnWidthForSection:section];
|
|
[_itemAttributes addObject:[NSMutableArray array]];
|
|
for (NSUInteger idx = 0; idx < numberOfItems; idx++) {
|
|
NSUInteger columnIndex = [self _shortestColumnIndexInSection:section];
|
|
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:idx inSection:section];
|
|
|
|
CGSize itemSize = [self _itemSizeAtIndexPath:indexPath];
|
|
CGFloat xOffset = _sectionInset.left + (columnWidth + _columnSpacing) * columnIndex;
|
|
CGFloat yOffset = [_columnHeights[section][columnIndex] floatValue];
|
|
|
|
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes
|
|
layoutAttributesForCellWithIndexPath:indexPath];
|
|
attributes.frame = CGRectMake(xOffset, yOffset, itemSize.width, itemSize.height);
|
|
|
|
_columnHeights[section][columnIndex] = @(CGRectGetMaxY(attributes.frame) + _interItemSpacing.bottom);
|
|
|
|
[_itemAttributes[section] addObject:attributes];
|
|
[_allAttributes addObject:attributes];
|
|
}
|
|
|
|
NSUInteger columnIndex = [self _tallestColumnIndexInSection:section];
|
|
top = [_columnHeights[section][columnIndex] floatValue] - _interItemSpacing.bottom + _sectionInset.bottom;
|
|
|
|
for (NSUInteger idx = 0; idx < [_columnHeights[section] count]; idx++) {
|
|
_columnHeights[section][idx] = @(top);
|
|
}
|
|
}
|
|
}
|
|
|
|
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
|
|
{
|
|
NSMutableArray *includedAttributes = [NSMutableArray array];
|
|
// Slow search for small batches
|
|
for (UICollectionViewLayoutAttributes *attributes in _allAttributes) {
|
|
if (CGRectIntersectsRect(attributes.frame, rect)) {
|
|
[includedAttributes addObject:attributes];
|
|
}
|
|
}
|
|
return includedAttributes;
|
|
}
|
|
|
|
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
if (indexPath.section >= _itemAttributes.count) {
|
|
return nil;
|
|
} else if (indexPath.item >= [_itemAttributes[indexPath.section] count]) {
|
|
return nil;
|
|
}
|
|
return _itemAttributes[indexPath.section][indexPath.item];
|
|
}
|
|
|
|
- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
if ([elementKind isEqualToString:UICollectionElementKindSectionHeader]) {
|
|
return _headerAttributes[@(indexPath.section)];
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
|
|
{
|
|
if (!CGRectEqualToRect(self.collectionView.bounds, newBounds)) {
|
|
return YES;
|
|
}
|
|
return NO;
|
|
}
|
|
|
|
- (CGFloat)_widthForSection:(NSUInteger)section
|
|
{
|
|
return self.collectionView.bounds.size.width - _sectionInset.left - _sectionInset.right;
|
|
}
|
|
|
|
- (CGFloat)_columnWidthForSection:(NSUInteger)section
|
|
{
|
|
return ([self _widthForSection:section] - ((_numberOfColumns - 1) * _columnSpacing)) / _numberOfColumns;
|
|
}
|
|
|
|
- (CGSize)_itemSizeAtIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
CGSize size = CGSizeMake([self _columnWidthForSection:indexPath.section], 0);
|
|
CGSize originalSize = [[self _delegate] collectionView:self.collectionView layout:self originalItemSizeAtIndexPath:indexPath];
|
|
if (originalSize.height > 0 && originalSize.width > 0) {
|
|
size.height = originalSize.height / originalSize.width * size.width;
|
|
}
|
|
return size;
|
|
}
|
|
|
|
- (CGSize)_headerSizeForSection:(NSUInteger)section
|
|
{
|
|
return CGSizeMake([self _widthForSection:section], _headerHeight);
|
|
}
|
|
|
|
- (CGSize)collectionViewContentSize
|
|
{
|
|
CGFloat height = [[[_columnHeights lastObject] firstObject] floatValue];
|
|
return CGSizeMake(self.collectionView.bounds.size.width, height);
|
|
}
|
|
|
|
- (NSUInteger)_tallestColumnIndexInSection:(NSUInteger)section
|
|
{
|
|
__block NSUInteger index = 0;
|
|
__block CGFloat tallestHeight = 0;
|
|
[_columnHeights[section] enumerateObjectsUsingBlock:^(NSNumber *height, NSUInteger idx, BOOL *stop) {
|
|
if (height.floatValue > tallestHeight) {
|
|
index = idx;
|
|
tallestHeight = height.floatValue;
|
|
}
|
|
}];
|
|
return index;
|
|
}
|
|
|
|
- (NSUInteger)_shortestColumnIndexInSection:(NSUInteger)section
|
|
{
|
|
__block NSUInteger index = 0;
|
|
__block CGFloat shortestHeight = CGFLOAT_MAX;
|
|
[_columnHeights[section] enumerateObjectsUsingBlock:^(NSNumber *height, NSUInteger idx, BOOL *stop) {
|
|
if (height.floatValue < shortestHeight) {
|
|
index = idx;
|
|
shortestHeight = height.floatValue;
|
|
}
|
|
}];
|
|
return index;
|
|
}
|
|
|
|
- (id<MosaicCollectionViewLayoutDelegate>)_delegate
|
|
{
|
|
return (id<MosaicCollectionViewLayoutDelegate>)self.collectionView.delegate;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation MosaicCollectionViewLayoutInspector
|
|
|
|
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
MosaicCollectionViewLayout *layout = (MosaicCollectionViewLayout *)[collectionView collectionViewLayout];
|
|
return ASSizeRangeMake(CGSizeZero, [layout _itemSizeAtIndexPath:indexPath]);
|
|
}
|
|
|
|
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForSupplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
MosaicCollectionViewLayout *layout = (MosaicCollectionViewLayout *)[collectionView collectionViewLayout];
|
|
return ASSizeRangeMake(CGSizeZero, [layout _headerSizeForSection:indexPath.section]);
|
|
}
|
|
|
|
/**
|
|
* Asks the inspector for the number of supplementary sections in the collection view for the given kind.
|
|
*/
|
|
- (NSUInteger)collectionView:(ASCollectionView *)collectionView numberOfSectionsForSupplementaryNodeOfKind:(NSString *)kind
|
|
{
|
|
if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
|
|
return [[collectionView asyncDataSource] numberOfSectionsInCollectionView:collectionView];
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Asks the inspector for the number of supplementary views for the given kind in the specified section.
|
|
*/
|
|
- (NSUInteger)collectionView:(ASCollectionView *)collectionView supplementaryNodesOfKind:(NSString *)kind inSection:(NSUInteger)section
|
|
{
|
|
if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
@end
|