Last active
April 9, 2018 09:06
-
-
Save wuyongrui/42e21ac286b9464dd95fc6e32cd4718d to your computer and use it in GitHub Desktop.
通过layout的方式实现首行首列浮效果
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 源设计: https://www.brightec.co.uk/ideas/uicollectionview-using-horizontal-and-vertical-scrolling-sticky-rows-and-columns | |
| 通过layout的方式实现首行首列浮效果 | |
| usage: | |
| UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:frame layout:pendingLayout]; | |
| 也可以通过左右两个tableView/collectionView组合的方式,通过同步contentOffset。这种方式实现多个pending的效果可能更简便一点; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // PendingLayout.h | |
| // Brightec | |
| // | |
| // Created by JOSE MARTINEZ on 03/09/2014. | |
| // Copyright (c) 2014 Brightec. All rights reserved. | |
| // | |
| #import <UIKit/UIKit.h> | |
| @protocol PendingLayoutDelegate; | |
| @interface PendingLayout : UICollectionViewFlowLayout | |
| @property (nonatomic, weak) id<PendingLayoutDelegate> delegate; | |
| /** | |
| 重置当前的布局数据 | |
| */ | |
| - (void)clearAttributes; | |
| @end | |
| @protocol PendingLayoutDelegate <NSObject> | |
| - (CGSize)selectTimeLayout:(PendingLayout *)layout sizeForCellAtSection:(NSInteger)section row:(NSInteger)row; | |
| @end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // PendingLayout.m | |
| // Brightec | |
| // | |
| // Created by JOSE MARTINEZ on 03/09/2014. | |
| // Copyright (c) 2014 Brightec. All rights reserved. | |
| // | |
| #import "PendingLayout.h" | |
| @interface PendingLayout () | |
| @property (strong, nonatomic) NSMutableArray *itemAttributes; | |
| @property (nonatomic, assign) CGSize contentSize; | |
| @end | |
| @implementation PendingLayout | |
| - (void)clearAttributes { | |
| self.itemAttributes = @[].mutableCopy; | |
| } | |
| - (void)prepareLayout | |
| { | |
| if ([self.collectionView numberOfSections] == 0) { | |
| return; | |
| } | |
| if (self.itemAttributes.count > 0) { // We don't enter in this if statement the first time, we enter the following times | |
| for (int section = 0; section < [self.collectionView numberOfSections]; section++) { | |
| NSUInteger numberOfItems = [self.collectionView numberOfItemsInSection:section]; | |
| for (NSUInteger index = 0; index < numberOfItems; index++) { | |
| if (section != 0 && index != 0) { // This is a content cell that shouldn't be sticked | |
| continue; | |
| } | |
| UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:section]]; | |
| if (section == 0) { // We stick the first row | |
| CGRect frame = attributes.frame; | |
| frame.origin.y = self.collectionView.contentOffset.y; | |
| attributes.frame = frame; | |
| } | |
| if (index == 0) { // We stick the first column | |
| CGRect frame = attributes.frame; | |
| frame.origin.x = self.collectionView.contentOffset.x; | |
| attributes.frame = frame; | |
| } | |
| } | |
| } | |
| return; | |
| } | |
| // The following code is only executed the first time we prepare the layout | |
| self.itemAttributes = [@[] mutableCopy]; | |
| NSUInteger columnIndex = 0; // 当前列所以 | |
| CGFloat xOffset = 0.0; | |
| CGFloat yOffset = 0.0; | |
| CGFloat contentWidth = 0.0; // To determine the contentSize | |
| CGFloat contentHeight = 0.0; // To determine the contentSize | |
| // We loop through all items | |
| NSInteger numberOfSection = [self.collectionView numberOfSections]; | |
| for (int section = 0; section < numberOfSection; section++) { | |
| NSInteger numberOfColumns = [self.collectionView numberOfItemsInSection:section]; | |
| NSMutableArray *sectionAttributes = [@[] mutableCopy]; | |
| for (NSUInteger index = 0; index < numberOfColumns; index++) { | |
| CGSize itemSize = [self.delegate selectTimeLayout:self sizeForCellAtSection:section row:index]; | |
| // We create the UICollectionViewLayoutAttributes object for each item and add it to our array. | |
| // We will use this later in layoutAttributesForItemAtIndexPath: | |
| NSIndexPath *indexPath = [NSIndexPath indexPathForItem:index inSection:section]; | |
| UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; | |
| attributes.frame = CGRectIntegral(CGRectMake(xOffset, yOffset, itemSize.width, itemSize.height)); | |
| if (section == 0 && index == 0) { | |
| attributes.zIndex = 1024; // Set this value for the first item (Sec0Row0) in order to make it visible over first column and first row | |
| } else if (section == 0 || index == 0) { | |
| attributes.zIndex = 1023; // Set this value for the first row or section in order to set visible over the rest of the items | |
| } | |
| /* | |
| 第一行和第一列修正坐标,达到悬浮效果 | |
| */ | |
| if (section == 0) { | |
| CGRect frame = attributes.frame; | |
| frame.origin.y = self.collectionView.contentOffset.y; | |
| attributes.frame = frame; // Stick to the top | |
| } | |
| if (index == 0) { | |
| CGRect frame = attributes.frame; | |
| frame.origin.x = self.collectionView.contentOffset.x; | |
| attributes.frame = frame; // Stick to the left | |
| } | |
| [sectionAttributes addObject:attributes]; | |
| xOffset = xOffset+itemSize.width; | |
| columnIndex++; | |
| // Create a new row if this was the last column | |
| if (columnIndex == numberOfColumns) { | |
| if (xOffset > contentWidth) { | |
| contentWidth = xOffset; | |
| } | |
| // Reset values | |
| columnIndex = 0; | |
| xOffset = 0; | |
| yOffset += itemSize.height; | |
| } | |
| } | |
| [self.itemAttributes addObject:sectionAttributes]; | |
| } | |
| // Get the last item to calculate the total height of the content | |
| UICollectionViewLayoutAttributes *attributes = [[self.itemAttributes lastObject] lastObject]; | |
| contentHeight = attributes.frame.origin.y+attributes.frame.size.height; | |
| self.contentSize = CGSizeMake(contentWidth, contentHeight); | |
| } | |
| - (CGSize)collectionViewContentSize | |
| { | |
| return self.contentSize; | |
| } | |
| - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath | |
| { | |
| return self.itemAttributes[indexPath.section][indexPath.row]; | |
| } | |
| - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect | |
| { | |
| NSMutableArray *attributes = [@[] mutableCopy]; | |
| for (NSArray *section in self.itemAttributes) { | |
| [attributes addObjectsFromArray:[section filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(UICollectionViewLayoutAttributes *evaluatedObject, NSDictionary *bindings) { | |
| return CGRectIntersectsRect(rect, [evaluatedObject frame]); | |
| }]]]; | |
| } | |
| return attributes; | |
| } | |
| - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds | |
| { | |
| return YES; // Set this to YES to call prepareLayout on every scroll | |
| } | |
| //- (CGSize)sizeForItemWithColumnIndex:(NSUInteger)columnIndex | |
| //{ | |
| // NSString *text; | |
| // switch (columnIndex) { // This only makes sense if the size of the items should be different | |
| // case 0: | |
| // text = @"Col 0"; | |
| // break; | |
| // case 1: | |
| // text = @"Col 1"; | |
| // break; | |
| // case 2: | |
| // text = @"Col 2"; | |
| // break; | |
| // case 3: | |
| // text = @"Col 3"; | |
| // break; | |
| // case 4: | |
| // text = @"Col 4"; | |
| // break; | |
| // case 5: | |
| // text = @"Col 5"; | |
| // break; | |
| // case 6: | |
| // text = @"Col 6"; | |
| // break; | |
| // case 7: | |
| // text = @"Col 7"; | |
| // break; | |
| // | |
| // default: | |
| // break; | |
| // } | |
| // CGSize size = [text sizeWithAttributes: @{NSFontAttributeName:[UIFont fontWithName:@"HelveticaNeue" size:15]}]; | |
| // if (columnIndex == 0) { | |
| // size.width += 12; // In our design the first column should be the widest one | |
| // } | |
| // return CGSizeMake([@(size.width + 9) floatValue], 30); // Extra space of 9px for all the items | |
| //} | |
| //- (void)calculateItemsSize | |
| //{ | |
| // for (NSUInteger index = 0; index < NUMBEROFCOLUMNS; index++) { | |
| // if (self.itemsSize.count <= index) { | |
| // CGSize itemSize = [self sizeForItemWithColumnIndex:index]; | |
| // NSValue *itemSizeValue = [NSValue valueWithCGSize:itemSize]; | |
| // [self.itemsSize addObject:itemSizeValue]; | |
| // } | |
| // } | |
| //} | |
| @end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment