带有粘性标题的 UICollectionView [英] UICollectionView with a sticky header
问题描述
@implementation StickyHeaderFlowLayout- (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect {NSMutableArray *answer = [[super layoutAttributesForElementsInRect:rect] mutableCopy];NSMutableIndexSet *missingSections = [NSMutableIndexSet indexSet];for (NSUInteger idx=0; idx<[答案数]; idx++) {UICollectionViewLayoutAttributes *layoutAttributes = answer[idx];如果(layoutAttributes.representedElementCategory == UICollectionElementCategoryCell){[missingSections addIndex:layoutAttributes.indexPath.section];//请记住,我们需要为此部分布局标题}if ([layoutAttributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) {[回答 removeObjectAtIndex:idx];//删除我们的 super 完成的标题布局,我们稍后会做idx--;}}//使用 self 代码布局 rect 所需的所有标题[missingSections enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:idx];UICollectionViewLayoutAttributes *layoutAttributes = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:indexPath];if (layoutAttributes != nil) {[回答 addObject:layoutAttributes];}}];返回答案;}- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {UICollectionViewLayoutAttributes *attributes = [super layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:indexPath];if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {UICollectionView * const cv = self.collectionView;CGPoint const contentOffset = cv.contentOffset;CGPoint nextHeaderOrigin = CGPointMake(INFINITY, INFINITY);if (indexPath.section+1 < [cv numberOfSections]) {UICollectionViewLayoutAttributes *nextHeaderAttributes = [super layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:[NSIndexPath indexPathForItem:0 inSection:indexPath.section+1]];nextHeaderOrigin = nextHeaderAttributes.frame.origin;}CGRect frame = attributes.frame;if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {frame.origin.y = MIN(MAX(contentOffset.y, frame.origin.y), nextHeaderOrigin.y - CGRectGetHeight(frame));}else {//UICollectionViewScrollDirectionHorizontalframe.origin.x = MIN(MAX(contentOffset.x, frame.origin.x), nextHeaderOrigin.x - CGRectGetWidth(frame));}属性.zIndex = 1024;属性.frame = 框架;}返回属性;}- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:indexPath];返回属性;}- (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:indexPath];返回属性;}- (BOOL) shouldInvalidateLayoutForBoundsChange:(CGRect)newBound {返回是;}@结尾
I found a blog on how to make sticky headers and it works great. Only thing is I don't think it takes into account the sectionInserts.
This is how its intended to look:
I have my inserts:
collectionViewFlowLayout.sectionInset = UIEdgeInsetsMake(16, 16, 16, 16);
With the sticky header, it is moved down by 16 pixles:
I tried tinking with the original code and I think the issue is with the last part:
layoutAttributes.frame = (CGRect){
.origin = CGPointMake(origin.x, origin.y),
.size = layoutAttributes.frame.size
If i change it to origin.y - 16
, the header will start in the right location but when pushed up, 16 pixels of the head go off screen:
I'm not sure how to get it to take into account sectionInsects. Can anybody help?
Here is the code in full from the blog:
- (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect {
NSMutableArray *answer = [[super layoutAttributesForElementsInRect:rect] mutableCopy];
UICollectionView * const cv = self.collectionView;
CGPoint const contentOffset = cv.contentOffset;
NSMutableIndexSet *missingSections = [NSMutableIndexSet indexSet];
for (UICollectionViewLayoutAttributes *layoutAttributes in answer) {
if (layoutAttributes.representedElementCategory == UICollectionElementCategoryCell) {
[missingSections addIndex:layoutAttributes.indexPath.section];
}
}
for (UICollectionViewLayoutAttributes *layoutAttributes in answer) {
if ([layoutAttributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) {
[missingSections removeIndex:layoutAttributes.indexPath.section];
}
}
[missingSections enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:idx];
UICollectionViewLayoutAttributes *layoutAttributes = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:indexPath];
[answer addObject:layoutAttributes];
}];
for (UICollectionViewLayoutAttributes *layoutAttributes in answer) {
if ([layoutAttributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) {
NSInteger section = layoutAttributes.indexPath.section;
NSInteger numberOfItemsInSection = [cv numberOfItemsInSection:section];
NSIndexPath *firstCellIndexPath = [NSIndexPath indexPathForItem:0 inSection:section];
NSIndexPath *lastCellIndexPath = [NSIndexPath indexPathForItem:MAX(0, (numberOfItemsInSection - 1)) inSection:section];
UICollectionViewLayoutAttributes *firstCellAttrs = [self layoutAttributesForItemAtIndexPath:firstCellIndexPath];
UICollectionViewLayoutAttributes *lastCellAttrs = [self layoutAttributesForItemAtIndexPath:lastCellIndexPath];
CGFloat headerHeight = CGRectGetHeight(layoutAttributes.frame);
CGPoint origin = layoutAttributes.frame.origin;
origin.y = MIN(
MAX(
contentOffset.y,
(CGRectGetMinY(firstCellAttrs.frame) - headerHeight)
),
(CGRectGetMaxY(lastCellAttrs.frame) - headerHeight)
);
layoutAttributes.zIndex = 1024;
layoutAttributes.frame = (CGRect){
.origin = origin,
.size = layoutAttributes.frame.size
};
}
}
return answer;
}
Fix by Todd Laney to handle Horizontal and Vertical scrolling and to take into account the sectionInsets:
https://gist.github.com/evadne/4544569
@implementation StickyHeaderFlowLayout
- (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect {
NSMutableArray *answer = [[super layoutAttributesForElementsInRect:rect] mutableCopy];
NSMutableIndexSet *missingSections = [NSMutableIndexSet indexSet];
for (NSUInteger idx=0; idx<[answer count]; idx++) {
UICollectionViewLayoutAttributes *layoutAttributes = answer[idx];
if (layoutAttributes.representedElementCategory == UICollectionElementCategoryCell) {
[missingSections addIndex:layoutAttributes.indexPath.section]; // remember that we need to layout header for this section
}
if ([layoutAttributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) {
[answer removeObjectAtIndex:idx]; // remove layout of header done by our super, we will do it right later
idx--;
}
}
// layout all headers needed for the rect using self code
[missingSections enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:idx];
UICollectionViewLayoutAttributes *layoutAttributes = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:indexPath];
if (layoutAttributes != nil) {
[answer addObject:layoutAttributes];
}
}];
return answer;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
UICollectionViewLayoutAttributes *attributes = [super layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:indexPath];
if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
UICollectionView * const cv = self.collectionView;
CGPoint const contentOffset = cv.contentOffset;
CGPoint nextHeaderOrigin = CGPointMake(INFINITY, INFINITY);
if (indexPath.section+1 < [cv numberOfSections]) {
UICollectionViewLayoutAttributes *nextHeaderAttributes = [super layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:[NSIndexPath indexPathForItem:0 inSection:indexPath.section+1]];
nextHeaderOrigin = nextHeaderAttributes.frame.origin;
}
CGRect frame = attributes.frame;
if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
frame.origin.y = MIN(MAX(contentOffset.y, frame.origin.y), nextHeaderOrigin.y - CGRectGetHeight(frame));
}
else { // UICollectionViewScrollDirectionHorizontal
frame.origin.x = MIN(MAX(contentOffset.x, frame.origin.x), nextHeaderOrigin.x - CGRectGetWidth(frame));
}
attributes.zIndex = 1024;
attributes.frame = frame;
}
return attributes;
}
- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:indexPath];
return attributes;
}
- (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:indexPath];
return attributes;
}
- (BOOL) shouldInvalidateLayoutForBoundsChange:(CGRect)newBound {
return YES;
}
@end
这篇关于带有粘性标题的 UICollectionView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!