2017-02-11 01:58:52 +00:00
|
|
|
/**
|
2018-11-01 17:56:41 +00:00
|
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
2017-02-11 01:58:52 +00:00
|
|
|
*
|
2018-05-01 21:33:50 +00:00
|
|
|
* This source code is licensed under the MIT license found in the
|
|
|
|
|
* LICENSE file in the root directory of this source tree.
|
2017-02-11 01:58:52 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#import "IGListCollectionViewLayout.h"
|
2017-03-17 19:26:08 +00:00
|
|
|
#import "IGListCollectionViewLayoutInternal.h"
|
2017-12-18 16:33:24 +00:00
|
|
|
#import "UIScrollView+IGListKit.h"
|
2017-02-11 01:58:52 +00:00
|
|
|
|
|
|
|
|
#import <vector>
|
|
|
|
|
|
|
|
|
|
#import <IGListKit/IGListAssert.h>
|
2018-01-29 18:54:42 +00:00
|
|
|
#import <IGListKit/IGListCollectionViewDelegateLayout.h>
|
2017-02-11 01:58:52 +00:00
|
|
|
|
Add horizontal scrolling support to IGListCollectionViewLayout
Summary:
Issue fixed: #752
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
This PR generalizes the layout logic in `IGListCollectionViewLayout.mm` to handle horizontally scrolling layouts, mainly by generalizing references to `width`, `height`, `x` and `y` to take scrolling direction into account. This changes the signature of `IGListCollectionViewLayout.init` as well as the names of a few properties, so it would be a breaking change.
I added a couple of unit tests specifically for horizontal layouts -- but held off from adding a horizontal version of *every* unit test for this class, as it would basically double the number of tests. But if you want that, just let me know and I'm happy to do it.
Also let me know if you want me to add a demo VC to the Examples project that uses this new horizontal flow layout -- I have some demo code handy (I used it for testing), but didn't want to clutter up the PR if you didn't want/need it.
Closes https://github.com/Instagram/IGListKit/pull/857
Reviewed By: ryanolsonk
Differential Revision: D5547266
Pulled By: rnystrom
fbshipit-source-id: 6094c45069fc265273d0f95c296fa78e47470384
2017-08-07 16:22:40 +00:00
|
|
|
static CGFloat UIEdgeInsetsLeadingInsetInDirection(UIEdgeInsets insets, UICollectionViewScrollDirection direction) {
|
|
|
|
|
switch (direction) {
|
|
|
|
|
case UICollectionViewScrollDirectionVertical: return insets.top;
|
|
|
|
|
case UICollectionViewScrollDirectionHorizontal: return insets.left;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static CGFloat UIEdgeInsetsTrailingInsetInDirection(UIEdgeInsets insets, UICollectionViewScrollDirection direction) {
|
|
|
|
|
switch (direction) {
|
|
|
|
|
case UICollectionViewScrollDirectionVertical: return insets.bottom;
|
|
|
|
|
case UICollectionViewScrollDirectionHorizontal: return insets.right;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static CGFloat CGPointGetCoordinateInDirection(CGPoint point, UICollectionViewScrollDirection direction) {
|
|
|
|
|
switch (direction) {
|
|
|
|
|
case UICollectionViewScrollDirectionVertical: return point.y;
|
|
|
|
|
case UICollectionViewScrollDirectionHorizontal: return point.x;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static CGFloat CGRectGetLengthInDirection(CGRect rect, UICollectionViewScrollDirection direction) {
|
|
|
|
|
switch (direction) {
|
|
|
|
|
case UICollectionViewScrollDirectionVertical: return rect.size.height;
|
|
|
|
|
case UICollectionViewScrollDirectionHorizontal: return rect.size.width;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static CGFloat CGRectGetMaxInDirection(CGRect rect, UICollectionViewScrollDirection direction) {
|
|
|
|
|
switch (direction) {
|
|
|
|
|
case UICollectionViewScrollDirectionVertical: return CGRectGetMaxY(rect);
|
|
|
|
|
case UICollectionViewScrollDirectionHorizontal: return CGRectGetMaxX(rect);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static CGFloat CGRectGetMinInDirection(CGRect rect, UICollectionViewScrollDirection direction) {
|
|
|
|
|
switch (direction) {
|
|
|
|
|
case UICollectionViewScrollDirectionVertical: return CGRectGetMinY(rect);
|
|
|
|
|
case UICollectionViewScrollDirectionHorizontal: return CGRectGetMinX(rect);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static CGFloat CGSizeGetLengthInDirection(CGSize size, UICollectionViewScrollDirection direction) {
|
|
|
|
|
switch (direction) {
|
|
|
|
|
case UICollectionViewScrollDirectionVertical: return size.height;
|
|
|
|
|
case UICollectionViewScrollDirectionHorizontal: return size.width;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-21 20:39:09 +00:00
|
|
|
static NSIndexPath *indexPathForSection(NSInteger section) {
|
2017-02-11 01:58:52 +00:00
|
|
|
return [NSIndexPath indexPathForItem:0 inSection:section];
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-15 17:19:22 +00:00
|
|
|
static NSInteger IGListMergeMinimumInvalidatedSection(NSInteger section, NSInteger otherSection) {
|
|
|
|
|
if (section == NSNotFound && otherSection == NSNotFound) {
|
|
|
|
|
return NSNotFound;
|
|
|
|
|
} else if (section == NSNotFound) {
|
|
|
|
|
return otherSection;
|
|
|
|
|
} else if (otherSection == NSNotFound) {
|
|
|
|
|
return section;
|
|
|
|
|
}
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-12-15 17:19:22 +00:00
|
|
|
return MIN(section, otherSection);
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
struct IGListSectionEntry {
|
|
|
|
|
/**
|
|
|
|
|
Represents the minimum-bounding box of every element in the section. This includes all item frames as well as the
|
|
|
|
|
header bounds. It is made simply by unioning all item and header frames. Use this to find section intersections
|
|
|
|
|
to build layout attributes given a rect.
|
|
|
|
|
*/
|
|
|
|
|
CGRect bounds;
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
// The insets for the section. Used to find total content size of the section.
|
|
|
|
|
UIEdgeInsets insets;
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
// The RESTING frame of the header view (e.g. when the header is not sticking to the top of the scroll view).
|
|
|
|
|
CGRect headerBounds;
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-11-21 20:39:09 +00:00
|
|
|
// The RESTING frame of the footer view
|
|
|
|
|
CGRect footerBounds;
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
// An array of frames for each cell in the section.
|
|
|
|
|
std::vector<CGRect> itemBounds;
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-12-15 17:19:20 +00:00
|
|
|
// last item distance in scroll direction, used for partial invalidation
|
|
|
|
|
CGFloat lastItemCoordInScrollDirection;
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-12-15 17:19:20 +00:00
|
|
|
// last item distance in fixed direction, used for partial invalidation
|
|
|
|
|
CGFloat lastItemCoordInFixedDirection;
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-12-15 17:19:20 +00:00
|
|
|
// last next row distance in scroll direction, used for partial invalidation
|
|
|
|
|
CGFloat lastNextRowCoordInScrollDirection;
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
// Returns YES when the section has visible content (header and/or items).
|
|
|
|
|
BOOL isValid() {
|
|
|
|
|
return !CGSizeEqualToSize(bounds.size, CGSizeZero);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Each section has a base zIndex of section * maxZIndexPerSection;
|
|
|
|
|
// section header adds (maxZIndexPerSection - 1) to the base zIndex;
|
|
|
|
|
// other cells adds (item) to the base zIndex.
|
|
|
|
|
// This allows us to present tooltips that can grow from the cell to its top.
|
|
|
|
|
static void adjustZIndexForAttributes(UICollectionViewLayoutAttributes *attributes) {
|
|
|
|
|
const NSInteger maxZIndexPerSection = 1000;
|
|
|
|
|
const NSInteger baseZIndex = attributes.indexPath.section * maxZIndexPerSection;
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
switch (attributes.representedElementCategory) {
|
|
|
|
|
case UICollectionElementCategoryCell:
|
|
|
|
|
attributes.zIndex = baseZIndex + attributes.indexPath.item;
|
|
|
|
|
break;
|
|
|
|
|
case UICollectionElementCategorySupplementaryView:
|
|
|
|
|
attributes.zIndex = baseZIndex + maxZIndexPerSection - 1;
|
|
|
|
|
break;
|
|
|
|
|
case UICollectionElementCategoryDecorationView:
|
|
|
|
|
attributes.zIndex = baseZIndex - 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@interface IGListCollectionViewLayoutInvalidationContext : UICollectionViewLayoutInvalidationContext
|
|
|
|
|
@property (nonatomic, assign) BOOL ig_invalidateSupplementaryAttributes;
|
|
|
|
|
@property (nonatomic, assign) BOOL ig_invalidateAllAttributes;
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation IGListCollectionViewLayoutInvalidationContext
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@interface IGListCollectionViewLayout ()
|
|
|
|
|
|
|
|
|
|
@property (nonatomic, assign, readonly) BOOL stickyHeaders;
|
|
|
|
|
@property (nonatomic, assign, readonly) CGFloat topContentInset;
|
2017-03-17 19:26:10 +00:00
|
|
|
@property (nonatomic, assign, readonly) BOOL stretchToEdge;
|
2017-02-11 01:58:52 +00:00
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation IGListCollectionViewLayout {
|
|
|
|
|
std::vector<IGListSectionEntry> _sectionData;
|
|
|
|
|
NSMutableDictionary<NSIndexPath *, UICollectionViewLayoutAttributes *> *_attributesCache;
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-12-15 17:19:20 +00:00
|
|
|
// invalidate starting at this section
|
|
|
|
|
NSInteger _minimumInvalidatedSection;
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
/**
|
|
|
|
|
The workflow for getting sticky headers working:
|
|
|
|
|
1. Use a custom invalidation context to mark supplementary attributes invalid.
|
|
|
|
|
2. Return YES from -shouldInvalidateLayoutForBoundsChange:
|
|
|
|
|
3. In -invalidationContextForBoundsChange: mark supplementary attributes invalid on the custom context.
|
|
|
|
|
4. Purge supplementary caches in -invalidateLayoutWithContext: if context says they are invalid
|
|
|
|
|
5. Use cached attributes in -layoutAttributesForSupplementaryViewOfKind:atIndexPath: if they exist, else rebuild
|
|
|
|
|
6. Make sure -layoutAttributesForElementsInRect: always uses the attributes returned from
|
|
|
|
|
-layoutAttributesForSupplementaryViewOfKind:atIndexPath:.
|
|
|
|
|
*/
|
2017-11-21 20:39:09 +00:00
|
|
|
NSMutableDictionary<NSString *, NSMutableDictionary <NSIndexPath *, UICollectionViewLayoutAttributes *> *> *_supplementaryAttributesCache;
|
2017-02-11 01:58:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (instancetype)initWithStickyHeaders:(BOOL)stickyHeaders
|
2017-03-17 19:26:10 +00:00
|
|
|
topContentInset:(CGFloat)topContentInset
|
|
|
|
|
stretchToEdge:(BOOL)stretchToEdge {
|
Add horizontal scrolling support to IGListCollectionViewLayout
Summary:
Issue fixed: #752
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
This PR generalizes the layout logic in `IGListCollectionViewLayout.mm` to handle horizontally scrolling layouts, mainly by generalizing references to `width`, `height`, `x` and `y` to take scrolling direction into account. This changes the signature of `IGListCollectionViewLayout.init` as well as the names of a few properties, so it would be a breaking change.
I added a couple of unit tests specifically for horizontal layouts -- but held off from adding a horizontal version of *every* unit test for this class, as it would basically double the number of tests. But if you want that, just let me know and I'm happy to do it.
Also let me know if you want me to add a demo VC to the Examples project that uses this new horizontal flow layout -- I have some demo code handy (I used it for testing), but didn't want to clutter up the PR if you didn't want/need it.
Closes https://github.com/Instagram/IGListKit/pull/857
Reviewed By: ryanolsonk
Differential Revision: D5547266
Pulled By: rnystrom
fbshipit-source-id: 6094c45069fc265273d0f95c296fa78e47470384
2017-08-07 16:22:40 +00:00
|
|
|
return [self initWithStickyHeaders:stickyHeaders
|
|
|
|
|
scrollDirection:UICollectionViewScrollDirectionVertical
|
|
|
|
|
topContentInset:topContentInset
|
|
|
|
|
stretchToEdge:stretchToEdge];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (instancetype)initWithStickyHeaders:(BOOL)stickyHeaders
|
|
|
|
|
scrollDirection:(UICollectionViewScrollDirection)scrollDirection
|
|
|
|
|
topContentInset:(CGFloat)topContentInset
|
|
|
|
|
stretchToEdge:(BOOL)stretchToEdge {
|
2017-02-11 01:58:52 +00:00
|
|
|
if (self = [super init]) {
|
Add horizontal scrolling support to IGListCollectionViewLayout
Summary:
Issue fixed: #752
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
This PR generalizes the layout logic in `IGListCollectionViewLayout.mm` to handle horizontally scrolling layouts, mainly by generalizing references to `width`, `height`, `x` and `y` to take scrolling direction into account. This changes the signature of `IGListCollectionViewLayout.init` as well as the names of a few properties, so it would be a breaking change.
I added a couple of unit tests specifically for horizontal layouts -- but held off from adding a horizontal version of *every* unit test for this class, as it would basically double the number of tests. But if you want that, just let me know and I'm happy to do it.
Also let me know if you want me to add a demo VC to the Examples project that uses this new horizontal flow layout -- I have some demo code handy (I used it for testing), but didn't want to clutter up the PR if you didn't want/need it.
Closes https://github.com/Instagram/IGListKit/pull/857
Reviewed By: ryanolsonk
Differential Revision: D5547266
Pulled By: rnystrom
fbshipit-source-id: 6094c45069fc265273d0f95c296fa78e47470384
2017-08-07 16:22:40 +00:00
|
|
|
_scrollDirection = scrollDirection;
|
2017-02-11 01:58:52 +00:00
|
|
|
_stickyHeaders = stickyHeaders;
|
|
|
|
|
_topContentInset = topContentInset;
|
2017-03-17 19:26:10 +00:00
|
|
|
_stretchToEdge = stretchToEdge;
|
2017-02-11 01:58:52 +00:00
|
|
|
_attributesCache = [NSMutableDictionary new];
|
2017-11-21 20:39:09 +00:00
|
|
|
_supplementaryAttributesCache = [NSMutableDictionary dictionaryWithDictionary:@{
|
|
|
|
|
UICollectionElementKindSectionHeader: [NSMutableDictionary new],
|
|
|
|
|
UICollectionElementKindSectionFooter: [NSMutableDictionary new],
|
|
|
|
|
}];
|
2017-12-15 17:19:20 +00:00
|
|
|
_minimumInvalidatedSection = NSNotFound;
|
2017-02-11 01:58:52 +00:00
|
|
|
}
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
2017-03-17 19:26:10 +00:00
|
|
|
return [self initWithStickyHeaders:NO topContentInset:0 stretchToEdge:NO];
|
2017-02-11 01:58:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark - UICollectionViewLayout
|
|
|
|
|
|
2018-01-29 18:54:42 +00:00
|
|
|
- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath {
|
|
|
|
|
UICollectionViewLayoutAttributes *attributes = [super initialLayoutAttributesForAppearingItemAtIndexPath:itemIndexPath];
|
|
|
|
|
id<IGListCollectionViewDelegateLayout> delegate = (id<IGListCollectionViewDelegateLayout>)self.collectionView.delegate;
|
|
|
|
|
if ([delegate respondsToSelector:@selector(collectionView:layout:customizedInitialLayoutAttributes:atIndexPath:)]) {
|
|
|
|
|
return [delegate collectionView:self.collectionView
|
|
|
|
|
layout:self
|
|
|
|
|
customizedInitialLayoutAttributes:attributes
|
|
|
|
|
atIndexPath:itemIndexPath];
|
|
|
|
|
}
|
|
|
|
|
return attributes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath{
|
|
|
|
|
UICollectionViewLayoutAttributes *attributes = [super finalLayoutAttributesForDisappearingItemAtIndexPath:itemIndexPath];
|
|
|
|
|
id<IGListCollectionViewDelegateLayout> delegate = (id<IGListCollectionViewDelegateLayout>)self.collectionView.delegate;
|
|
|
|
|
if ([delegate respondsToSelector:@selector(collectionView:layout:customizedFinalLayoutAttributes:atIndexPath:)]) {
|
|
|
|
|
return [delegate collectionView:self.collectionView
|
|
|
|
|
layout:self
|
|
|
|
|
customizedFinalLayoutAttributes:attributes
|
|
|
|
|
atIndexPath:itemIndexPath];
|
|
|
|
|
}
|
|
|
|
|
return attributes;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
|
|
|
|
|
IGAssertMainThread();
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
NSMutableArray *result = [NSMutableArray new];
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2018-04-02 22:06:52 +00:00
|
|
|
const NSRange range = [self _rangeOfSectionsInRect:rect];
|
2017-02-11 01:58:52 +00:00
|
|
|
if (range.location == NSNotFound) {
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
for (NSInteger section = range.location; section < NSMaxRange(range); section++) {
|
|
|
|
|
const NSInteger itemCount = _sectionData[section].itemBounds.size();
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
// do not add headers if there are no items
|
Show header when section item is empty
Summary:
Issue fixed: #1117
I adding a new constructor for making a `IGListCollectionViewLayout` instance that can always show sticky header although section data is empty.
It's working well and [this is demo project](https://github.com/marcuswu0814/IGListKit_ShowStickyHeaderWhenDataEmpty).
Bug I'm not sure is any good way to let this much more readability. Is there any good advice?
```objc
const CGRect headerBounds = (self.scrollDirection == UICollectionViewScrollDirectionVertical) ?
CGRectMake(insets.left,
(itemCount == 0) ? CGRectGetMaxY(rollingSectionBounds) : CGRectGetMinY(rollingSectionBounds) - headerSize.height,
paddedLengthInFixedDirection,
headerSize.height) :
CGRectMake((itemCount == 0) ? CGRectGetMaxX(rollingSectionBounds) : CGRectGetMinX(rollingSectionBounds) - headerSize.width,
insets.top,
headerSize.width,
paddedLengthInFixedDirection);
```
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
Closes https://github.com/Instagram/IGListKit/pull/1129
Differential Revision: D7551628
Pulled By: rnystrom
fbshipit-source-id: a60b65a92efcea5175c86aaed1de02686ea6d20a
2018-04-09 15:28:05 +00:00
|
|
|
if (itemCount > 0 || self.showHeaderWhenEmpty) {
|
2017-11-21 20:39:09 +00:00
|
|
|
for (NSString *elementKind in _supplementaryAttributesCache.allKeys) {
|
|
|
|
|
NSIndexPath *indexPath = indexPathForSection(section);
|
|
|
|
|
UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForSupplementaryViewOfKind:elementKind
|
|
|
|
|
atIndexPath:indexPath];
|
|
|
|
|
// do not add zero height headers/footers or headers/footers that are outside the rect
|
|
|
|
|
const CGRect frame = attributes.frame;
|
|
|
|
|
const CGRect intersection = CGRectIntersection(frame, rect);
|
|
|
|
|
if (!CGRectIsEmpty(intersection) && CGRectGetLengthInDirection(frame, self.scrollDirection) > 0.0) {
|
|
|
|
|
[result addObject:attributes];
|
|
|
|
|
}
|
2017-02-11 01:58:52 +00:00
|
|
|
}
|
|
|
|
|
}
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
// add all cells within the rect, return early if it starts iterating outside
|
|
|
|
|
for (NSInteger item = 0; item < itemCount; item++) {
|
|
|
|
|
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:item inSection:section];
|
|
|
|
|
UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexPath];
|
2017-04-21 15:11:44 +00:00
|
|
|
if (CGRectIntersectsRect(attributes.frame, rect)) {
|
2017-02-11 01:58:52 +00:00
|
|
|
[result addObject:attributes];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
|
|
|
|
|
IGAssertMainThread();
|
|
|
|
|
IGParameterAssert(indexPath != nil);
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
UICollectionViewLayoutAttributes *attributes = _attributesCache[indexPath];
|
|
|
|
|
if (attributes != nil) {
|
|
|
|
|
return attributes;
|
|
|
|
|
}
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-04-19 15:12:29 +00:00
|
|
|
// avoid OOB errors
|
|
|
|
|
const NSInteger section = indexPath.section;
|
|
|
|
|
const NSInteger item = indexPath.item;
|
|
|
|
|
if (section >= _sectionData.size()
|
|
|
|
|
|| item >= _sectionData[section].itemBounds.size()) {
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2018-04-09 14:29:23 +00:00
|
|
|
attributes = [[[self class] layoutAttributesClass] layoutAttributesForCellWithIndexPath:indexPath];
|
2017-02-11 01:58:52 +00:00
|
|
|
attributes.frame = _sectionData[indexPath.section].itemBounds[indexPath.item];
|
|
|
|
|
adjustZIndexForAttributes(attributes);
|
|
|
|
|
_attributesCache[indexPath] = attributes;
|
|
|
|
|
return attributes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath {
|
|
|
|
|
IGAssertMainThread();
|
|
|
|
|
IGParameterAssert(indexPath != nil);
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-11-21 20:39:09 +00:00
|
|
|
UICollectionViewLayoutAttributes *attributes = _supplementaryAttributesCache[elementKind][indexPath];
|
2017-02-11 01:58:52 +00:00
|
|
|
if (attributes != nil) {
|
|
|
|
|
return attributes;
|
|
|
|
|
}
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-04-19 15:12:29 +00:00
|
|
|
// avoid OOB errors
|
2017-02-11 01:58:52 +00:00
|
|
|
const NSInteger section = indexPath.section;
|
2017-04-19 15:12:29 +00:00
|
|
|
if (section >= _sectionData.size()) {
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-04-19 15:12:29 +00:00
|
|
|
UICollectionView *collectionView = self.collectionView;
|
2017-02-11 01:58:52 +00:00
|
|
|
const IGListSectionEntry entry = _sectionData[section];
|
Add horizontal scrolling support to IGListCollectionViewLayout
Summary:
Issue fixed: #752
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
This PR generalizes the layout logic in `IGListCollectionViewLayout.mm` to handle horizontally scrolling layouts, mainly by generalizing references to `width`, `height`, `x` and `y` to take scrolling direction into account. This changes the signature of `IGListCollectionViewLayout.init` as well as the names of a few properties, so it would be a breaking change.
I added a couple of unit tests specifically for horizontal layouts -- but held off from adding a horizontal version of *every* unit test for this class, as it would basically double the number of tests. But if you want that, just let me know and I'm happy to do it.
Also let me know if you want me to add a demo VC to the Examples project that uses this new horizontal flow layout -- I have some demo code handy (I used it for testing), but didn't want to clutter up the PR if you didn't want/need it.
Closes https://github.com/Instagram/IGListKit/pull/857
Reviewed By: ryanolsonk
Differential Revision: D5547266
Pulled By: rnystrom
fbshipit-source-id: 6094c45069fc265273d0f95c296fa78e47470384
2017-08-07 16:22:40 +00:00
|
|
|
const CGFloat minOffset = CGRectGetMinInDirection(entry.bounds, self.scrollDirection);
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-11-21 20:39:09 +00:00
|
|
|
CGRect frame = CGRectZero;
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-11-21 20:39:09 +00:00
|
|
|
if ([elementKind isEqualToString:UICollectionElementKindSectionHeader]) {
|
|
|
|
|
frame = entry.headerBounds;
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2018-03-12 22:27:37 +00:00
|
|
|
if (self.stickyHeaders) {
|
|
|
|
|
CGFloat offset = CGPointGetCoordinateInDirection(collectionView.contentOffset, self.scrollDirection) + self.topContentInset + self.stickyHeaderYOffset;
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2018-03-12 22:27:37 +00:00
|
|
|
if (section + 1 == _sectionData.size()) {
|
|
|
|
|
offset = MAX(minOffset, offset);
|
|
|
|
|
} else {
|
|
|
|
|
const CGFloat maxOffset = CGRectGetMinInDirection(_sectionData[section + 1].bounds, self.scrollDirection) - CGRectGetLengthInDirection(frame, self.scrollDirection);
|
|
|
|
|
offset = MIN(MAX(minOffset, offset), maxOffset);
|
|
|
|
|
}
|
|
|
|
|
switch (self.scrollDirection) {
|
|
|
|
|
case UICollectionViewScrollDirectionVertical:
|
|
|
|
|
frame.origin.y = offset;
|
|
|
|
|
break;
|
|
|
|
|
case UICollectionViewScrollDirectionHorizontal:
|
|
|
|
|
frame.origin.x = offset;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-02-11 01:58:52 +00:00
|
|
|
}
|
2018-03-12 22:27:37 +00:00
|
|
|
} else if ([elementKind isEqualToString:UICollectionElementKindSectionFooter]) {
|
|
|
|
|
frame = entry.footerBounds;
|
2017-02-11 01:58:52 +00:00
|
|
|
}
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
attributes = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:elementKind withIndexPath:indexPath];
|
|
|
|
|
attributes.frame = frame;
|
|
|
|
|
adjustZIndexForAttributes(attributes);
|
2017-11-21 20:39:09 +00:00
|
|
|
_supplementaryAttributesCache[elementKind][indexPath] = attributes;
|
|
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
return attributes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (CGSize)collectionViewContentSize {
|
|
|
|
|
IGAssertMainThread();
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
const NSInteger sectionCount = _sectionData.size();
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
if (sectionCount == 0) {
|
|
|
|
|
return CGSizeZero;
|
|
|
|
|
}
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
const IGListSectionEntry section = _sectionData[sectionCount - 1];
|
|
|
|
|
UICollectionView *collectionView = self.collectionView;
|
2017-12-18 16:33:24 +00:00
|
|
|
const UIEdgeInsets contentInset = collectionView.ig_contentInset;
|
Add horizontal scrolling support to IGListCollectionViewLayout
Summary:
Issue fixed: #752
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
This PR generalizes the layout logic in `IGListCollectionViewLayout.mm` to handle horizontally scrolling layouts, mainly by generalizing references to `width`, `height`, `x` and `y` to take scrolling direction into account. This changes the signature of `IGListCollectionViewLayout.init` as well as the names of a few properties, so it would be a breaking change.
I added a couple of unit tests specifically for horizontal layouts -- but held off from adding a horizontal version of *every* unit test for this class, as it would basically double the number of tests. But if you want that, just let me know and I'm happy to do it.
Also let me know if you want me to add a demo VC to the Examples project that uses this new horizontal flow layout -- I have some demo code handy (I used it for testing), but didn't want to clutter up the PR if you didn't want/need it.
Closes https://github.com/Instagram/IGListKit/pull/857
Reviewed By: ryanolsonk
Differential Revision: D5547266
Pulled By: rnystrom
fbshipit-source-id: 6094c45069fc265273d0f95c296fa78e47470384
2017-08-07 16:22:40 +00:00
|
|
|
switch (self.scrollDirection) {
|
|
|
|
|
case UICollectionViewScrollDirectionVertical: {
|
|
|
|
|
const CGFloat height = CGRectGetMaxY(section.bounds) + section.insets.bottom;
|
|
|
|
|
return CGSizeMake(CGRectGetWidth(collectionView.bounds) - contentInset.left - contentInset.right, height);
|
|
|
|
|
}
|
|
|
|
|
case UICollectionViewScrollDirectionHorizontal: {
|
|
|
|
|
const CGFloat width = CGRectGetMaxX(section.bounds) + section.insets.right;
|
|
|
|
|
return CGSizeMake(width, CGRectGetHeight(collectionView.bounds) - contentInset.top - contentInset.bottom);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)invalidateLayoutWithContext:(IGListCollectionViewLayoutInvalidationContext *)context {
|
|
|
|
|
BOOL hasInvalidatedItemIndexPaths = NO;
|
|
|
|
|
if ([context respondsToSelector:@selector(invalidatedItemIndexPaths)]) {
|
|
|
|
|
hasInvalidatedItemIndexPaths = [context invalidatedItemIndexPaths].count > 0;
|
|
|
|
|
}
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
if (hasInvalidatedItemIndexPaths
|
|
|
|
|
|| [context invalidateEverything]
|
|
|
|
|
|| context.ig_invalidateAllAttributes) {
|
2017-12-15 17:19:22 +00:00
|
|
|
// invalidates all
|
|
|
|
|
_minimumInvalidatedSection = 0;
|
|
|
|
|
} else if ([context invalidateDataSourceCounts] && _minimumInvalidatedSection == NSNotFound) {
|
|
|
|
|
// invalidate all if count changed and we don't have information on the minimum invalidated section
|
|
|
|
|
_minimumInvalidatedSection = 0;
|
2017-02-11 01:58:52 +00:00
|
|
|
}
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
if (context.ig_invalidateSupplementaryAttributes) {
|
2018-04-02 22:06:52 +00:00
|
|
|
[self _resetSupplementaryAttributesCache];
|
2017-02-11 01:58:52 +00:00
|
|
|
}
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
[super invalidateLayoutWithContext:context];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (Class)invalidationContextClass {
|
|
|
|
|
return [IGListCollectionViewLayoutInvalidationContext class];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (UICollectionViewLayoutInvalidationContext *)invalidationContextForBoundsChange:(CGRect)newBounds {
|
|
|
|
|
const CGRect oldBounds = self.collectionView.bounds;
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
IGListCollectionViewLayoutInvalidationContext *context =
|
2019-06-14 23:19:38 +00:00
|
|
|
(IGListCollectionViewLayoutInvalidationContext *)[super invalidationContextForBoundsChange:newBounds];
|
2017-02-11 01:58:52 +00:00
|
|
|
context.ig_invalidateSupplementaryAttributes = YES;
|
|
|
|
|
if (!CGSizeEqualToSize(oldBounds.size, newBounds.size)) {
|
|
|
|
|
context.ig_invalidateAllAttributes = YES;
|
|
|
|
|
}
|
|
|
|
|
return context;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
|
|
|
|
|
const CGRect oldBounds = self.collectionView.bounds;
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2018-11-01 21:53:16 +00:00
|
|
|
// always invalidate for size changes
|
|
|
|
|
if (!CGSizeEqualToSize(oldBounds.size, newBounds.size)) {
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
// if the y origin has changed, only invalidate when using sticky headers
|
Add horizontal scrolling support to IGListCollectionViewLayout
Summary:
Issue fixed: #752
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
This PR generalizes the layout logic in `IGListCollectionViewLayout.mm` to handle horizontally scrolling layouts, mainly by generalizing references to `width`, `height`, `x` and `y` to take scrolling direction into account. This changes the signature of `IGListCollectionViewLayout.init` as well as the names of a few properties, so it would be a breaking change.
I added a couple of unit tests specifically for horizontal layouts -- but held off from adding a horizontal version of *every* unit test for this class, as it would basically double the number of tests. But if you want that, just let me know and I'm happy to do it.
Also let me know if you want me to add a demo VC to the Examples project that uses this new horizontal flow layout -- I have some demo code handy (I used it for testing), but didn't want to clutter up the PR if you didn't want/need it.
Closes https://github.com/Instagram/IGListKit/pull/857
Reviewed By: ryanolsonk
Differential Revision: D5547266
Pulled By: rnystrom
fbshipit-source-id: 6094c45069fc265273d0f95c296fa78e47470384
2017-08-07 16:22:40 +00:00
|
|
|
if (CGRectGetMinInDirection(newBounds, self.scrollDirection) != CGRectGetMinInDirection(oldBounds, self.scrollDirection)) {
|
2017-02-11 01:58:52 +00:00
|
|
|
return self.stickyHeaders;
|
|
|
|
|
}
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2018-11-01 21:53:16 +00:00
|
|
|
return NO;
|
2017-02-11 01:58:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)prepareLayout {
|
2018-04-02 22:06:52 +00:00
|
|
|
[self _calculateLayoutIfNeeded];
|
2017-02-11 01:58:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark - Public API
|
|
|
|
|
|
Add horizontal scrolling support to IGListCollectionViewLayout
Summary:
Issue fixed: #752
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
This PR generalizes the layout logic in `IGListCollectionViewLayout.mm` to handle horizontally scrolling layouts, mainly by generalizing references to `width`, `height`, `x` and `y` to take scrolling direction into account. This changes the signature of `IGListCollectionViewLayout.init` as well as the names of a few properties, so it would be a breaking change.
I added a couple of unit tests specifically for horizontal layouts -- but held off from adding a horizontal version of *every* unit test for this class, as it would basically double the number of tests. But if you want that, just let me know and I'm happy to do it.
Also let me know if you want me to add a demo VC to the Examples project that uses this new horizontal flow layout -- I have some demo code handy (I used it for testing), but didn't want to clutter up the PR if you didn't want/need it.
Closes https://github.com/Instagram/IGListKit/pull/857
Reviewed By: ryanolsonk
Differential Revision: D5547266
Pulled By: rnystrom
fbshipit-source-id: 6094c45069fc265273d0f95c296fa78e47470384
2017-08-07 16:22:40 +00:00
|
|
|
- (void)setStickyHeaderYOffset:(CGFloat)stickyHeaderYOffset {
|
2017-02-11 01:58:52 +00:00
|
|
|
IGAssertMainThread();
|
2019-06-14 23:19:38 +00:00
|
|
|
|
Add horizontal scrolling support to IGListCollectionViewLayout
Summary:
Issue fixed: #752
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
This PR generalizes the layout logic in `IGListCollectionViewLayout.mm` to handle horizontally scrolling layouts, mainly by generalizing references to `width`, `height`, `x` and `y` to take scrolling direction into account. This changes the signature of `IGListCollectionViewLayout.init` as well as the names of a few properties, so it would be a breaking change.
I added a couple of unit tests specifically for horizontal layouts -- but held off from adding a horizontal version of *every* unit test for this class, as it would basically double the number of tests. But if you want that, just let me know and I'm happy to do it.
Also let me know if you want me to add a demo VC to the Examples project that uses this new horizontal flow layout -- I have some demo code handy (I used it for testing), but didn't want to clutter up the PR if you didn't want/need it.
Closes https://github.com/Instagram/IGListKit/pull/857
Reviewed By: ryanolsonk
Differential Revision: D5547266
Pulled By: rnystrom
fbshipit-source-id: 6094c45069fc265273d0f95c296fa78e47470384
2017-08-07 16:22:40 +00:00
|
|
|
if (_stickyHeaderYOffset != stickyHeaderYOffset) {
|
|
|
|
|
_stickyHeaderYOffset = stickyHeaderYOffset;
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-06-22 16:21:50 +00:00
|
|
|
IGListCollectionViewLayoutInvalidationContext *invalidationContext = [IGListCollectionViewLayoutInvalidationContext new];
|
2017-02-11 01:58:52 +00:00
|
|
|
invalidationContext.ig_invalidateSupplementaryAttributes = YES;
|
|
|
|
|
[self invalidateLayoutWithContext:invalidationContext];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark - Private API
|
|
|
|
|
|
2018-04-02 22:06:52 +00:00
|
|
|
- (void)_calculateLayoutIfNeeded {
|
2017-12-15 17:19:20 +00:00
|
|
|
if (_minimumInvalidatedSection == NSNotFound) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
// purge attribute caches so they are rebuilt
|
|
|
|
|
[_attributesCache removeAllObjects];
|
2018-04-02 22:06:52 +00:00
|
|
|
[self _resetSupplementaryAttributesCache];
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
UICollectionView *collectionView = self.collectionView;
|
|
|
|
|
id<UICollectionViewDataSource> dataSource = collectionView.dataSource;
|
|
|
|
|
id<UICollectionViewDelegateFlowLayout> delegate = (id<UICollectionViewDelegateFlowLayout>)collectionView.delegate;
|
2019-06-14 23:19:38 +00:00
|
|
|
|
|
|
|
|
const NSInteger sectionCount = (IGListExperimentEnabled(_experiments, IGListExperimentUseCollectionViewInsteadOfDataSourceInLayout)
|
|
|
|
|
? [collectionView numberOfSections]
|
|
|
|
|
: [dataSource numberOfSectionsInCollectionView:collectionView]);
|
2017-12-18 16:33:24 +00:00
|
|
|
const UIEdgeInsets contentInset = collectionView.ig_contentInset;
|
Add horizontal scrolling support to IGListCollectionViewLayout
Summary:
Issue fixed: #752
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
This PR generalizes the layout logic in `IGListCollectionViewLayout.mm` to handle horizontally scrolling layouts, mainly by generalizing references to `width`, `height`, `x` and `y` to take scrolling direction into account. This changes the signature of `IGListCollectionViewLayout.init` as well as the names of a few properties, so it would be a breaking change.
I added a couple of unit tests specifically for horizontal layouts -- but held off from adding a horizontal version of *every* unit test for this class, as it would basically double the number of tests. But if you want that, just let me know and I'm happy to do it.
Also let me know if you want me to add a demo VC to the Examples project that uses this new horizontal flow layout -- I have some demo code handy (I used it for testing), but didn't want to clutter up the PR if you didn't want/need it.
Closes https://github.com/Instagram/IGListKit/pull/857
Reviewed By: ryanolsonk
Differential Revision: D5547266
Pulled By: rnystrom
fbshipit-source-id: 6094c45069fc265273d0f95c296fa78e47470384
2017-08-07 16:22:40 +00:00
|
|
|
const CGRect contentInsetAdjustedCollectionViewBounds = UIEdgeInsetsInsetRect(collectionView.bounds, contentInset);
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-12-15 17:19:20 +00:00
|
|
|
_sectionData.resize(sectionCount);
|
2019-06-14 23:19:38 +00:00
|
|
|
|
Add horizontal scrolling support to IGListCollectionViewLayout
Summary:
Issue fixed: #752
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
This PR generalizes the layout logic in `IGListCollectionViewLayout.mm` to handle horizontally scrolling layouts, mainly by generalizing references to `width`, `height`, `x` and `y` to take scrolling direction into account. This changes the signature of `IGListCollectionViewLayout.init` as well as the names of a few properties, so it would be a breaking change.
I added a couple of unit tests specifically for horizontal layouts -- but held off from adding a horizontal version of *every* unit test for this class, as it would basically double the number of tests. But if you want that, just let me know and I'm happy to do it.
Also let me know if you want me to add a demo VC to the Examples project that uses this new horizontal flow layout -- I have some demo code handy (I used it for testing), but didn't want to clutter up the PR if you didn't want/need it.
Closes https://github.com/Instagram/IGListKit/pull/857
Reviewed By: ryanolsonk
Differential Revision: D5547266
Pulled By: rnystrom
fbshipit-source-id: 6094c45069fc265273d0f95c296fa78e47470384
2017-08-07 16:22:40 +00:00
|
|
|
CGFloat itemCoordInScrollDirection = 0.0;
|
|
|
|
|
CGFloat itemCoordInFixedDirection = 0.0;
|
|
|
|
|
CGFloat nextRowCoordInScrollDirection = 0.0;
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
// union item frames and optionally the header to find a bounding box of the entire section
|
2018-02-02 21:14:16 +00:00
|
|
|
CGRect rollingSectionBounds = CGRectZero;
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-12-15 17:19:20 +00:00
|
|
|
// populate last valid section information
|
|
|
|
|
const NSInteger lastValidSection = _minimumInvalidatedSection - 1;
|
|
|
|
|
if (lastValidSection >= 0 && lastValidSection < sectionCount) {
|
|
|
|
|
itemCoordInScrollDirection = _sectionData[lastValidSection].lastItemCoordInScrollDirection;
|
|
|
|
|
itemCoordInFixedDirection = _sectionData[lastValidSection].lastItemCoordInFixedDirection;
|
|
|
|
|
nextRowCoordInScrollDirection = _sectionData[lastValidSection].lastNextRowCoordInScrollDirection;
|
|
|
|
|
rollingSectionBounds = _sectionData[lastValidSection].bounds;
|
|
|
|
|
}
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-12-15 17:19:20 +00:00
|
|
|
for (NSInteger section = _minimumInvalidatedSection; section < sectionCount; section++) {
|
2019-06-14 23:19:38 +00:00
|
|
|
const NSInteger itemCount = (IGListExperimentEnabled(_experiments, IGListExperimentUseCollectionViewInsteadOfDataSourceInLayout)
|
|
|
|
|
? [collectionView numberOfItemsInSection:section]
|
|
|
|
|
: [dataSource collectionView:collectionView numberOfItemsInSection:section]);
|
Show header when section item is empty
Summary:
Issue fixed: #1117
I adding a new constructor for making a `IGListCollectionViewLayout` instance that can always show sticky header although section data is empty.
It's working well and [this is demo project](https://github.com/marcuswu0814/IGListKit_ShowStickyHeaderWhenDataEmpty).
Bug I'm not sure is any good way to let this much more readability. Is there any good advice?
```objc
const CGRect headerBounds = (self.scrollDirection == UICollectionViewScrollDirectionVertical) ?
CGRectMake(insets.left,
(itemCount == 0) ? CGRectGetMaxY(rollingSectionBounds) : CGRectGetMinY(rollingSectionBounds) - headerSize.height,
paddedLengthInFixedDirection,
headerSize.height) :
CGRectMake((itemCount == 0) ? CGRectGetMaxX(rollingSectionBounds) : CGRectGetMinX(rollingSectionBounds) - headerSize.width,
insets.top,
headerSize.width,
paddedLengthInFixedDirection);
```
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
Closes https://github.com/Instagram/IGListKit/pull/1129
Differential Revision: D7551628
Pulled By: rnystrom
fbshipit-source-id: a60b65a92efcea5175c86aaed1de02686ea6d20a
2018-04-09 15:28:05 +00:00
|
|
|
const BOOL itemsEmpty = itemCount == 0;
|
|
|
|
|
const BOOL hideHeaderWhenItemsEmpty = itemsEmpty && !self.showHeaderWhenEmpty;
|
2017-12-15 17:19:20 +00:00
|
|
|
_sectionData[section].itemBounds = std::vector<CGRect>(itemCount);
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
const CGSize headerSize = [delegate collectionView:collectionView layout:self referenceSizeForHeaderInSection:section];
|
2017-11-21 20:39:09 +00:00
|
|
|
const CGSize footerSize = [delegate collectionView:collectionView layout:self referenceSizeForFooterInSection:section];
|
2017-02-11 01:58:52 +00:00
|
|
|
const UIEdgeInsets insets = [delegate collectionView:collectionView layout:self insetForSectionAtIndex:section];
|
|
|
|
|
const CGFloat lineSpacing = [delegate collectionView:collectionView layout:self minimumLineSpacingForSectionAtIndex:section];
|
|
|
|
|
const CGFloat interitemSpacing = [delegate collectionView:collectionView layout:self minimumInteritemSpacingForSectionAtIndex:section];
|
2019-06-14 23:19:38 +00:00
|
|
|
|
Add horizontal scrolling support to IGListCollectionViewLayout
Summary:
Issue fixed: #752
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
This PR generalizes the layout logic in `IGListCollectionViewLayout.mm` to handle horizontally scrolling layouts, mainly by generalizing references to `width`, `height`, `x` and `y` to take scrolling direction into account. This changes the signature of `IGListCollectionViewLayout.init` as well as the names of a few properties, so it would be a breaking change.
I added a couple of unit tests specifically for horizontal layouts -- but held off from adding a horizontal version of *every* unit test for this class, as it would basically double the number of tests. But if you want that, just let me know and I'm happy to do it.
Also let me know if you want me to add a demo VC to the Examples project that uses this new horizontal flow layout -- I have some demo code handy (I used it for testing), but didn't want to clutter up the PR if you didn't want/need it.
Closes https://github.com/Instagram/IGListKit/pull/857
Reviewed By: ryanolsonk
Differential Revision: D5547266
Pulled By: rnystrom
fbshipit-source-id: 6094c45069fc265273d0f95c296fa78e47470384
2017-08-07 16:22:40 +00:00
|
|
|
const CGSize paddedCollectionViewSize = UIEdgeInsetsInsetRect(contentInsetAdjustedCollectionViewBounds, insets).size;
|
|
|
|
|
const UICollectionViewScrollDirection fixedDirection = self.scrollDirection == UICollectionViewScrollDirectionHorizontal ? UICollectionViewScrollDirectionVertical : UICollectionViewScrollDirectionHorizontal;
|
|
|
|
|
const CGFloat paddedLengthInFixedDirection = CGSizeGetLengthInDirection(paddedCollectionViewSize, fixedDirection);
|
Show header when section item is empty
Summary:
Issue fixed: #1117
I adding a new constructor for making a `IGListCollectionViewLayout` instance that can always show sticky header although section data is empty.
It's working well and [this is demo project](https://github.com/marcuswu0814/IGListKit_ShowStickyHeaderWhenDataEmpty).
Bug I'm not sure is any good way to let this much more readability. Is there any good advice?
```objc
const CGRect headerBounds = (self.scrollDirection == UICollectionViewScrollDirectionVertical) ?
CGRectMake(insets.left,
(itemCount == 0) ? CGRectGetMaxY(rollingSectionBounds) : CGRectGetMinY(rollingSectionBounds) - headerSize.height,
paddedLengthInFixedDirection,
headerSize.height) :
CGRectMake((itemCount == 0) ? CGRectGetMaxX(rollingSectionBounds) : CGRectGetMinX(rollingSectionBounds) - headerSize.width,
insets.top,
headerSize.width,
paddedLengthInFixedDirection);
```
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
Closes https://github.com/Instagram/IGListKit/pull/1129
Differential Revision: D7551628
Pulled By: rnystrom
fbshipit-source-id: a60b65a92efcea5175c86aaed1de02686ea6d20a
2018-04-09 15:28:05 +00:00
|
|
|
const CGFloat headerLengthInScrollDirection = hideHeaderWhenItemsEmpty ? 0 : CGSizeGetLengthInDirection(headerSize, self.scrollDirection);
|
|
|
|
|
const CGFloat footerLengthInScrollDirection = hideHeaderWhenItemsEmpty ? 0 : CGSizeGetLengthInDirection(footerSize, self.scrollDirection);
|
Add horizontal scrolling support to IGListCollectionViewLayout
Summary:
Issue fixed: #752
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
This PR generalizes the layout logic in `IGListCollectionViewLayout.mm` to handle horizontally scrolling layouts, mainly by generalizing references to `width`, `height`, `x` and `y` to take scrolling direction into account. This changes the signature of `IGListCollectionViewLayout.init` as well as the names of a few properties, so it would be a breaking change.
I added a couple of unit tests specifically for horizontal layouts -- but held off from adding a horizontal version of *every* unit test for this class, as it would basically double the number of tests. But if you want that, just let me know and I'm happy to do it.
Also let me know if you want me to add a demo VC to the Examples project that uses this new horizontal flow layout -- I have some demo code handy (I used it for testing), but didn't want to clutter up the PR if you didn't want/need it.
Closes https://github.com/Instagram/IGListKit/pull/857
Reviewed By: ryanolsonk
Differential Revision: D5547266
Pulled By: rnystrom
fbshipit-source-id: 6094c45069fc265273d0f95c296fa78e47470384
2017-08-07 16:22:40 +00:00
|
|
|
const BOOL headerExists = headerLengthInScrollDirection > 0;
|
2017-11-21 20:39:09 +00:00
|
|
|
const BOOL footerExists = footerLengthInScrollDirection > 0;
|
2019-06-14 23:19:38 +00:00
|
|
|
|
Add horizontal scrolling support to IGListCollectionViewLayout
Summary:
Issue fixed: #752
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
This PR generalizes the layout logic in `IGListCollectionViewLayout.mm` to handle horizontally scrolling layouts, mainly by generalizing references to `width`, `height`, `x` and `y` to take scrolling direction into account. This changes the signature of `IGListCollectionViewLayout.init` as well as the names of a few properties, so it would be a breaking change.
I added a couple of unit tests specifically for horizontal layouts -- but held off from adding a horizontal version of *every* unit test for this class, as it would basically double the number of tests. But if you want that, just let me know and I'm happy to do it.
Also let me know if you want me to add a demo VC to the Examples project that uses this new horizontal flow layout -- I have some demo code handy (I used it for testing), but didn't want to clutter up the PR if you didn't want/need it.
Closes https://github.com/Instagram/IGListKit/pull/857
Reviewed By: ryanolsonk
Differential Revision: D5547266
Pulled By: rnystrom
fbshipit-source-id: 6094c45069fc265273d0f95c296fa78e47470384
2017-08-07 16:22:40 +00:00
|
|
|
// start the section accounting for the header size
|
|
|
|
|
// header length in scroll direction is subtracted from the sectionBounds when calculating the header bounds after items are done
|
|
|
|
|
// this bumps the first row of items over enough to make room for the header
|
|
|
|
|
itemCoordInScrollDirection += headerLengthInScrollDirection;
|
|
|
|
|
nextRowCoordInScrollDirection += headerLengthInScrollDirection;
|
2019-06-14 23:19:38 +00:00
|
|
|
|
Add horizontal scrolling support to IGListCollectionViewLayout
Summary:
Issue fixed: #752
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
This PR generalizes the layout logic in `IGListCollectionViewLayout.mm` to handle horizontally scrolling layouts, mainly by generalizing references to `width`, `height`, `x` and `y` to take scrolling direction into account. This changes the signature of `IGListCollectionViewLayout.init` as well as the names of a few properties, so it would be a breaking change.
I added a couple of unit tests specifically for horizontal layouts -- but held off from adding a horizontal version of *every* unit test for this class, as it would basically double the number of tests. But if you want that, just let me know and I'm happy to do it.
Also let me know if you want me to add a demo VC to the Examples project that uses this new horizontal flow layout -- I have some demo code handy (I used it for testing), but didn't want to clutter up the PR if you didn't want/need it.
Closes https://github.com/Instagram/IGListKit/pull/857
Reviewed By: ryanolsonk
Differential Revision: D5547266
Pulled By: rnystrom
fbshipit-source-id: 6094c45069fc265273d0f95c296fa78e47470384
2017-08-07 16:22:40 +00:00
|
|
|
// add the leading inset in fixed direction in case the section falls on the same row as the previous
|
|
|
|
|
// if the section is newlined then the coord in fixed direction is reset
|
|
|
|
|
itemCoordInFixedDirection += UIEdgeInsetsLeadingInsetInDirection(insets, fixedDirection);
|
2019-06-14 23:19:38 +00:00
|
|
|
|
Add horizontal scrolling support to IGListCollectionViewLayout
Summary:
Issue fixed: #752
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
This PR generalizes the layout logic in `IGListCollectionViewLayout.mm` to handle horizontally scrolling layouts, mainly by generalizing references to `width`, `height`, `x` and `y` to take scrolling direction into account. This changes the signature of `IGListCollectionViewLayout.init` as well as the names of a few properties, so it would be a breaking change.
I added a couple of unit tests specifically for horizontal layouts -- but held off from adding a horizontal version of *every* unit test for this class, as it would basically double the number of tests. But if you want that, just let me know and I'm happy to do it.
Also let me know if you want me to add a demo VC to the Examples project that uses this new horizontal flow layout -- I have some demo code handy (I used it for testing), but didn't want to clutter up the PR if you didn't want/need it.
Closes https://github.com/Instagram/IGListKit/pull/857
Reviewed By: ryanolsonk
Differential Revision: D5547266
Pulled By: rnystrom
fbshipit-source-id: 6094c45069fc265273d0f95c296fa78e47470384
2017-08-07 16:22:40 +00:00
|
|
|
// the farthest in the fixed direction the frame of an item in this section can go
|
|
|
|
|
const CGFloat maxCoordinateInFixedDirection = CGRectGetLengthInDirection(contentInsetAdjustedCollectionViewBounds, fixedDirection) - UIEdgeInsetsTrailingInsetInDirection(insets, fixedDirection);
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
for (NSInteger item = 0; item < itemCount; item++) {
|
|
|
|
|
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:item inSection:section];
|
|
|
|
|
const CGSize size = [delegate collectionView:collectionView layout:self sizeForItemAtIndexPath:indexPath];
|
2019-06-14 23:19:38 +00:00
|
|
|
|
Add horizontal scrolling support to IGListCollectionViewLayout
Summary:
Issue fixed: #752
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
This PR generalizes the layout logic in `IGListCollectionViewLayout.mm` to handle horizontally scrolling layouts, mainly by generalizing references to `width`, `height`, `x` and `y` to take scrolling direction into account. This changes the signature of `IGListCollectionViewLayout.init` as well as the names of a few properties, so it would be a breaking change.
I added a couple of unit tests specifically for horizontal layouts -- but held off from adding a horizontal version of *every* unit test for this class, as it would basically double the number of tests. But if you want that, just let me know and I'm happy to do it.
Also let me know if you want me to add a demo VC to the Examples project that uses this new horizontal flow layout -- I have some demo code handy (I used it for testing), but didn't want to clutter up the PR if you didn't want/need it.
Closes https://github.com/Instagram/IGListKit/pull/857
Reviewed By: ryanolsonk
Differential Revision: D5547266
Pulled By: rnystrom
fbshipit-source-id: 6094c45069fc265273d0f95c296fa78e47470384
2017-08-07 16:22:40 +00:00
|
|
|
IGAssert(CGSizeGetLengthInDirection(size, fixedDirection) <= paddedLengthInFixedDirection
|
2018-01-16 15:35:21 +00:00
|
|
|
|| fabs(CGSizeGetLengthInDirection(size, fixedDirection) - paddedLengthInFixedDirection) < FLT_EPSILON,
|
Minimum fixes for Xcode 9.3 build errors
Summary:
Issue fixed: #1141
This is a set of minimum fixes for Xcode 9.3 rather than #1142. Much smaller diffs 😃
The changes here were done by Xcode's FixIt. See also https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html#//apple_ref/doc/uid/TP40004265-SW5.
> Platform Dependencies
>
> OS X uses several data types—NSInteger, NSUInteger,CGFloat, and CFIndex—to provide a consistent means of representing values in 32- and 64-bit environments. In a 32-bit environment, NSInteger and NSUInteger are defined as int and unsigned int, respectively. In 64-bit environments, NSInteger and NSUInteger are defined as long and unsigned long, respectively. To avoid the need to use different printf-style type specifiers depending on the platform, you can use the specifiers shown in Table 3. Note that in some cases you may have to cast the value.
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
Closes https://github.com/Instagram/IGListKit/pull/1143
Differential Revision: D7551617
Pulled By: rnystrom
fbshipit-source-id: b27ebe2b1a1c93ebfd1218dc38b7621fefee2e6b
2018-04-09 15:06:47 +00:00
|
|
|
@"%@ of item %li in section %li (%.0f pt) must be less than or equal to container (%.0f pt) accounting for section insets %@",
|
2018-01-16 15:35:21 +00:00
|
|
|
self.scrollDirection == UICollectionViewScrollDirectionVertical ? @"Width" : @"Height",
|
Minimum fixes for Xcode 9.3 build errors
Summary:
Issue fixed: #1141
This is a set of minimum fixes for Xcode 9.3 rather than #1142. Much smaller diffs 😃
The changes here were done by Xcode's FixIt. See also https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html#//apple_ref/doc/uid/TP40004265-SW5.
> Platform Dependencies
>
> OS X uses several data types—NSInteger, NSUInteger,CGFloat, and CFIndex—to provide a consistent means of representing values in 32- and 64-bit environments. In a 32-bit environment, NSInteger and NSUInteger are defined as int and unsigned int, respectively. In 64-bit environments, NSInteger and NSUInteger are defined as long and unsigned long, respectively. To avoid the need to use different printf-style type specifiers depending on the platform, you can use the specifiers shown in Table 3. Note that in some cases you may have to cast the value.
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
Closes https://github.com/Instagram/IGListKit/pull/1143
Differential Revision: D7551617
Pulled By: rnystrom
fbshipit-source-id: b27ebe2b1a1c93ebfd1218dc38b7621fefee2e6b
2018-04-09 15:06:47 +00:00
|
|
|
(long)item,
|
|
|
|
|
(long)section,
|
2018-01-16 15:35:21 +00:00
|
|
|
CGSizeGetLengthInDirection(size, fixedDirection),
|
|
|
|
|
CGRectGetLengthInDirection(contentInsetAdjustedCollectionViewBounds, fixedDirection),
|
|
|
|
|
NSStringFromUIEdgeInsets(insets));
|
2019-06-14 23:19:38 +00:00
|
|
|
|
Add horizontal scrolling support to IGListCollectionViewLayout
Summary:
Issue fixed: #752
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
This PR generalizes the layout logic in `IGListCollectionViewLayout.mm` to handle horizontally scrolling layouts, mainly by generalizing references to `width`, `height`, `x` and `y` to take scrolling direction into account. This changes the signature of `IGListCollectionViewLayout.init` as well as the names of a few properties, so it would be a breaking change.
I added a couple of unit tests specifically for horizontal layouts -- but held off from adding a horizontal version of *every* unit test for this class, as it would basically double the number of tests. But if you want that, just let me know and I'm happy to do it.
Also let me know if you want me to add a demo VC to the Examples project that uses this new horizontal flow layout -- I have some demo code handy (I used it for testing), but didn't want to clutter up the PR if you didn't want/need it.
Closes https://github.com/Instagram/IGListKit/pull/857
Reviewed By: ryanolsonk
Differential Revision: D5547266
Pulled By: rnystrom
fbshipit-source-id: 6094c45069fc265273d0f95c296fa78e47470384
2017-08-07 16:22:40 +00:00
|
|
|
CGFloat itemLengthInFixedDirection = MIN(CGSizeGetLengthInDirection(size, fixedDirection), paddedLengthInFixedDirection);
|
2019-06-14 23:19:38 +00:00
|
|
|
|
Add horizontal scrolling support to IGListCollectionViewLayout
Summary:
Issue fixed: #752
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
This PR generalizes the layout logic in `IGListCollectionViewLayout.mm` to handle horizontally scrolling layouts, mainly by generalizing references to `width`, `height`, `x` and `y` to take scrolling direction into account. This changes the signature of `IGListCollectionViewLayout.init` as well as the names of a few properties, so it would be a breaking change.
I added a couple of unit tests specifically for horizontal layouts -- but held off from adding a horizontal version of *every* unit test for this class, as it would basically double the number of tests. But if you want that, just let me know and I'm happy to do it.
Also let me know if you want me to add a demo VC to the Examples project that uses this new horizontal flow layout -- I have some demo code handy (I used it for testing), but didn't want to clutter up the PR if you didn't want/need it.
Closes https://github.com/Instagram/IGListKit/pull/857
Reviewed By: ryanolsonk
Differential Revision: D5547266
Pulled By: rnystrom
fbshipit-source-id: 6094c45069fc265273d0f95c296fa78e47470384
2017-08-07 16:22:40 +00:00
|
|
|
// if the origin and length in fixed direction of the item busts the size of the container
|
2017-02-11 01:58:52 +00:00
|
|
|
// or if this is the first item and the header has a non-zero size
|
|
|
|
|
// newline to the next row and reset
|
2017-03-17 19:26:10 +00:00
|
|
|
// define epsilon to avoid float overflow issue
|
|
|
|
|
const CGFloat epsilon = 1.0;
|
Add horizontal scrolling support to IGListCollectionViewLayout
Summary:
Issue fixed: #752
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
This PR generalizes the layout logic in `IGListCollectionViewLayout.mm` to handle horizontally scrolling layouts, mainly by generalizing references to `width`, `height`, `x` and `y` to take scrolling direction into account. This changes the signature of `IGListCollectionViewLayout.init` as well as the names of a few properties, so it would be a breaking change.
I added a couple of unit tests specifically for horizontal layouts -- but held off from adding a horizontal version of *every* unit test for this class, as it would basically double the number of tests. But if you want that, just let me know and I'm happy to do it.
Also let me know if you want me to add a demo VC to the Examples project that uses this new horizontal flow layout -- I have some demo code handy (I used it for testing), but didn't want to clutter up the PR if you didn't want/need it.
Closes https://github.com/Instagram/IGListKit/pull/857
Reviewed By: ryanolsonk
Differential Revision: D5547266
Pulled By: rnystrom
fbshipit-source-id: 6094c45069fc265273d0f95c296fa78e47470384
2017-08-07 16:22:40 +00:00
|
|
|
if (itemCoordInFixedDirection + itemLengthInFixedDirection > maxCoordinateInFixedDirection + epsilon
|
2017-03-05 00:08:00 +00:00
|
|
|
|| (item == 0 && headerExists)) {
|
Add horizontal scrolling support to IGListCollectionViewLayout
Summary:
Issue fixed: #752
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
This PR generalizes the layout logic in `IGListCollectionViewLayout.mm` to handle horizontally scrolling layouts, mainly by generalizing references to `width`, `height`, `x` and `y` to take scrolling direction into account. This changes the signature of `IGListCollectionViewLayout.init` as well as the names of a few properties, so it would be a breaking change.
I added a couple of unit tests specifically for horizontal layouts -- but held off from adding a horizontal version of *every* unit test for this class, as it would basically double the number of tests. But if you want that, just let me know and I'm happy to do it.
Also let me know if you want me to add a demo VC to the Examples project that uses this new horizontal flow layout -- I have some demo code handy (I used it for testing), but didn't want to clutter up the PR if you didn't want/need it.
Closes https://github.com/Instagram/IGListKit/pull/857
Reviewed By: ryanolsonk
Differential Revision: D5547266
Pulled By: rnystrom
fbshipit-source-id: 6094c45069fc265273d0f95c296fa78e47470384
2017-08-07 16:22:40 +00:00
|
|
|
itemCoordInScrollDirection = nextRowCoordInScrollDirection;
|
|
|
|
|
itemCoordInFixedDirection = UIEdgeInsetsLeadingInsetInDirection(insets, fixedDirection);
|
2019-06-14 23:19:38 +00:00
|
|
|
|
|
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
// if newlining, always append line spacing unless its the very first item of the section
|
|
|
|
|
if (item > 0) {
|
2017-11-21 20:39:09 +00:00
|
|
|
itemCoordInScrollDirection += lineSpacing;
|
2017-02-11 01:58:52 +00:00
|
|
|
}
|
|
|
|
|
}
|
2019-06-14 23:19:38 +00:00
|
|
|
|
Add horizontal scrolling support to IGListCollectionViewLayout
Summary:
Issue fixed: #752
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
This PR generalizes the layout logic in `IGListCollectionViewLayout.mm` to handle horizontally scrolling layouts, mainly by generalizing references to `width`, `height`, `x` and `y` to take scrolling direction into account. This changes the signature of `IGListCollectionViewLayout.init` as well as the names of a few properties, so it would be a breaking change.
I added a couple of unit tests specifically for horizontal layouts -- but held off from adding a horizontal version of *every* unit test for this class, as it would basically double the number of tests. But if you want that, just let me know and I'm happy to do it.
Also let me know if you want me to add a demo VC to the Examples project that uses this new horizontal flow layout -- I have some demo code handy (I used it for testing), but didn't want to clutter up the PR if you didn't want/need it.
Closes https://github.com/Instagram/IGListKit/pull/857
Reviewed By: ryanolsonk
Differential Revision: D5547266
Pulled By: rnystrom
fbshipit-source-id: 6094c45069fc265273d0f95c296fa78e47470384
2017-08-07 16:22:40 +00:00
|
|
|
const CGFloat distanceToEdge = paddedLengthInFixedDirection - (itemCoordInFixedDirection + itemLengthInFixedDirection);
|
|
|
|
|
if (self.stretchToEdge && distanceToEdge > 0 && distanceToEdge <= epsilon) {
|
|
|
|
|
itemLengthInFixedDirection = paddedLengthInFixedDirection - itemCoordInFixedDirection;
|
2017-03-17 19:26:10 +00:00
|
|
|
}
|
2019-06-14 23:19:38 +00:00
|
|
|
|
Add horizontal scrolling support to IGListCollectionViewLayout
Summary:
Issue fixed: #752
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
This PR generalizes the layout logic in `IGListCollectionViewLayout.mm` to handle horizontally scrolling layouts, mainly by generalizing references to `width`, `height`, `x` and `y` to take scrolling direction into account. This changes the signature of `IGListCollectionViewLayout.init` as well as the names of a few properties, so it would be a breaking change.
I added a couple of unit tests specifically for horizontal layouts -- but held off from adding a horizontal version of *every* unit test for this class, as it would basically double the number of tests. But if you want that, just let me know and I'm happy to do it.
Also let me know if you want me to add a demo VC to the Examples project that uses this new horizontal flow layout -- I have some demo code handy (I used it for testing), but didn't want to clutter up the PR if you didn't want/need it.
Closes https://github.com/Instagram/IGListKit/pull/857
Reviewed By: ryanolsonk
Differential Revision: D5547266
Pulled By: rnystrom
fbshipit-source-id: 6094c45069fc265273d0f95c296fa78e47470384
2017-08-07 16:22:40 +00:00
|
|
|
const CGRect rawFrame = (self.scrollDirection == UICollectionViewScrollDirectionVertical) ?
|
2019-06-14 23:19:38 +00:00
|
|
|
CGRectMake(itemCoordInFixedDirection,
|
|
|
|
|
itemCoordInScrollDirection + insets.top,
|
|
|
|
|
itemLengthInFixedDirection,
|
|
|
|
|
size.height) :
|
|
|
|
|
CGRectMake(itemCoordInScrollDirection + insets.left,
|
|
|
|
|
itemCoordInFixedDirection,
|
|
|
|
|
size.width,
|
|
|
|
|
itemLengthInFixedDirection);
|
Add horizontal scrolling support to IGListCollectionViewLayout
Summary:
Issue fixed: #752
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
This PR generalizes the layout logic in `IGListCollectionViewLayout.mm` to handle horizontally scrolling layouts, mainly by generalizing references to `width`, `height`, `x` and `y` to take scrolling direction into account. This changes the signature of `IGListCollectionViewLayout.init` as well as the names of a few properties, so it would be a breaking change.
I added a couple of unit tests specifically for horizontal layouts -- but held off from adding a horizontal version of *every* unit test for this class, as it would basically double the number of tests. But if you want that, just let me know and I'm happy to do it.
Also let me know if you want me to add a demo VC to the Examples project that uses this new horizontal flow layout -- I have some demo code handy (I used it for testing), but didn't want to clutter up the PR if you didn't want/need it.
Closes https://github.com/Instagram/IGListKit/pull/857
Reviewed By: ryanolsonk
Differential Revision: D5547266
Pulled By: rnystrom
fbshipit-source-id: 6094c45069fc265273d0f95c296fa78e47470384
2017-08-07 16:22:40 +00:00
|
|
|
const CGRect frame = IGListRectIntegralScaled(rawFrame);
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-12-15 17:19:20 +00:00
|
|
|
_sectionData[section].itemBounds[item] = frame;
|
2019-06-14 23:19:38 +00:00
|
|
|
|
Add horizontal scrolling support to IGListCollectionViewLayout
Summary:
Issue fixed: #752
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
This PR generalizes the layout logic in `IGListCollectionViewLayout.mm` to handle horizontally scrolling layouts, mainly by generalizing references to `width`, `height`, `x` and `y` to take scrolling direction into account. This changes the signature of `IGListCollectionViewLayout.init` as well as the names of a few properties, so it would be a breaking change.
I added a couple of unit tests specifically for horizontal layouts -- but held off from adding a horizontal version of *every* unit test for this class, as it would basically double the number of tests. But if you want that, just let me know and I'm happy to do it.
Also let me know if you want me to add a demo VC to the Examples project that uses this new horizontal flow layout -- I have some demo code handy (I used it for testing), but didn't want to clutter up the PR if you didn't want/need it.
Closes https://github.com/Instagram/IGListKit/pull/857
Reviewed By: ryanolsonk
Differential Revision: D5547266
Pulled By: rnystrom
fbshipit-source-id: 6094c45069fc265273d0f95c296fa78e47470384
2017-08-07 16:22:40 +00:00
|
|
|
// track the max size of the row to find the coord of the next row, adjust for leading inset while iterating items
|
|
|
|
|
nextRowCoordInScrollDirection = MAX(CGRectGetMaxInDirection(frame, self.scrollDirection) - UIEdgeInsetsLeadingInsetInDirection(insets, self.scrollDirection), nextRowCoordInScrollDirection);
|
2019-06-14 23:19:38 +00:00
|
|
|
|
Add horizontal scrolling support to IGListCollectionViewLayout
Summary:
Issue fixed: #752
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
This PR generalizes the layout logic in `IGListCollectionViewLayout.mm` to handle horizontally scrolling layouts, mainly by generalizing references to `width`, `height`, `x` and `y` to take scrolling direction into account. This changes the signature of `IGListCollectionViewLayout.init` as well as the names of a few properties, so it would be a breaking change.
I added a couple of unit tests specifically for horizontal layouts -- but held off from adding a horizontal version of *every* unit test for this class, as it would basically double the number of tests. But if you want that, just let me know and I'm happy to do it.
Also let me know if you want me to add a demo VC to the Examples project that uses this new horizontal flow layout -- I have some demo code handy (I used it for testing), but didn't want to clutter up the PR if you didn't want/need it.
Closes https://github.com/Instagram/IGListKit/pull/857
Reviewed By: ryanolsonk
Differential Revision: D5547266
Pulled By: rnystrom
fbshipit-source-id: 6094c45069fc265273d0f95c296fa78e47470384
2017-08-07 16:22:40 +00:00
|
|
|
// increase the rolling coord in fixed direction appropriately and add item spacing for all items on the same row
|
|
|
|
|
itemCoordInFixedDirection += itemLengthInFixedDirection + interitemSpacing;
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
// union the rolling section bounds
|
|
|
|
|
if (item == 0) {
|
|
|
|
|
rollingSectionBounds = frame;
|
|
|
|
|
} else {
|
|
|
|
|
rollingSectionBounds = CGRectUnion(rollingSectionBounds, frame);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-06-14 23:19:38 +00:00
|
|
|
|
Show header when section item is empty
Summary:
Issue fixed: #1117
I adding a new constructor for making a `IGListCollectionViewLayout` instance that can always show sticky header although section data is empty.
It's working well and [this is demo project](https://github.com/marcuswu0814/IGListKit_ShowStickyHeaderWhenDataEmpty).
Bug I'm not sure is any good way to let this much more readability. Is there any good advice?
```objc
const CGRect headerBounds = (self.scrollDirection == UICollectionViewScrollDirectionVertical) ?
CGRectMake(insets.left,
(itemCount == 0) ? CGRectGetMaxY(rollingSectionBounds) : CGRectGetMinY(rollingSectionBounds) - headerSize.height,
paddedLengthInFixedDirection,
headerSize.height) :
CGRectMake((itemCount == 0) ? CGRectGetMaxX(rollingSectionBounds) : CGRectGetMinX(rollingSectionBounds) - headerSize.width,
insets.top,
headerSize.width,
paddedLengthInFixedDirection);
```
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
Closes https://github.com/Instagram/IGListKit/pull/1129
Differential Revision: D7551628
Pulled By: rnystrom
fbshipit-source-id: a60b65a92efcea5175c86aaed1de02686ea6d20a
2018-04-09 15:28:05 +00:00
|
|
|
const CGRect headerBounds = self.scrollDirection == UICollectionViewScrollDirectionVertical ?
|
|
|
|
|
CGRectMake(insets.left,
|
|
|
|
|
itemsEmpty ? CGRectGetMaxY(rollingSectionBounds) : CGRectGetMinY(rollingSectionBounds) - headerSize.height,
|
|
|
|
|
paddedLengthInFixedDirection,
|
|
|
|
|
hideHeaderWhenItemsEmpty ? 0 : headerSize.height) :
|
|
|
|
|
CGRectMake(itemsEmpty ? CGRectGetMaxX(rollingSectionBounds) : CGRectGetMinX(rollingSectionBounds) - headerSize.width,
|
|
|
|
|
insets.top,
|
|
|
|
|
hideHeaderWhenItemsEmpty ? 0 : headerSize.width,
|
|
|
|
|
paddedLengthInFixedDirection);
|
|
|
|
|
|
2017-12-15 17:19:20 +00:00
|
|
|
_sectionData[section].headerBounds = headerBounds;
|
Show header when section item is empty
Summary:
Issue fixed: #1117
I adding a new constructor for making a `IGListCollectionViewLayout` instance that can always show sticky header although section data is empty.
It's working well and [this is demo project](https://github.com/marcuswu0814/IGListKit_ShowStickyHeaderWhenDataEmpty).
Bug I'm not sure is any good way to let this much more readability. Is there any good advice?
```objc
const CGRect headerBounds = (self.scrollDirection == UICollectionViewScrollDirectionVertical) ?
CGRectMake(insets.left,
(itemCount == 0) ? CGRectGetMaxY(rollingSectionBounds) : CGRectGetMinY(rollingSectionBounds) - headerSize.height,
paddedLengthInFixedDirection,
headerSize.height) :
CGRectMake((itemCount == 0) ? CGRectGetMaxX(rollingSectionBounds) : CGRectGetMinX(rollingSectionBounds) - headerSize.width,
insets.top,
headerSize.width,
paddedLengthInFixedDirection);
```
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
Closes https://github.com/Instagram/IGListKit/pull/1129
Differential Revision: D7551628
Pulled By: rnystrom
fbshipit-source-id: a60b65a92efcea5175c86aaed1de02686ea6d20a
2018-04-09 15:28:05 +00:00
|
|
|
|
|
|
|
|
if (itemsEmpty) {
|
|
|
|
|
rollingSectionBounds = headerBounds;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-21 20:39:09 +00:00
|
|
|
const CGRect footerBounds = (self.scrollDirection == UICollectionViewScrollDirectionVertical) ?
|
Show header when section item is empty
Summary:
Issue fixed: #1117
I adding a new constructor for making a `IGListCollectionViewLayout` instance that can always show sticky header although section data is empty.
It's working well and [this is demo project](https://github.com/marcuswu0814/IGListKit_ShowStickyHeaderWhenDataEmpty).
Bug I'm not sure is any good way to let this much more readability. Is there any good advice?
```objc
const CGRect headerBounds = (self.scrollDirection == UICollectionViewScrollDirectionVertical) ?
CGRectMake(insets.left,
(itemCount == 0) ? CGRectGetMaxY(rollingSectionBounds) : CGRectGetMinY(rollingSectionBounds) - headerSize.height,
paddedLengthInFixedDirection,
headerSize.height) :
CGRectMake((itemCount == 0) ? CGRectGetMaxX(rollingSectionBounds) : CGRectGetMinX(rollingSectionBounds) - headerSize.width,
insets.top,
headerSize.width,
paddedLengthInFixedDirection);
```
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
Closes https://github.com/Instagram/IGListKit/pull/1129
Differential Revision: D7551628
Pulled By: rnystrom
fbshipit-source-id: a60b65a92efcea5175c86aaed1de02686ea6d20a
2018-04-09 15:28:05 +00:00
|
|
|
CGRectMake(insets.left,
|
|
|
|
|
CGRectGetMaxY(rollingSectionBounds),
|
|
|
|
|
paddedLengthInFixedDirection,
|
|
|
|
|
hideHeaderWhenItemsEmpty ? 0 : footerSize.height) :
|
|
|
|
|
CGRectMake(CGRectGetMaxX(rollingSectionBounds) + insets.right,
|
|
|
|
|
insets.top,
|
|
|
|
|
hideHeaderWhenItemsEmpty ? 0 : footerSize.width,
|
|
|
|
|
paddedLengthInFixedDirection);
|
|
|
|
|
|
2017-12-15 17:19:20 +00:00
|
|
|
_sectionData[section].footerBounds = footerBounds;
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
// union the header before setting the bounds of the section
|
|
|
|
|
// only do this when the header has a size, otherwise the union stretches to box empty space
|
|
|
|
|
if (headerExists) {
|
|
|
|
|
rollingSectionBounds = CGRectUnion(rollingSectionBounds, headerBounds);
|
|
|
|
|
}
|
2017-11-21 20:39:09 +00:00
|
|
|
if (footerExists) {
|
|
|
|
|
rollingSectionBounds = CGRectUnion(rollingSectionBounds, footerBounds);
|
|
|
|
|
}
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-12-15 17:19:20 +00:00
|
|
|
_sectionData[section].bounds = rollingSectionBounds;
|
|
|
|
|
_sectionData[section].insets = insets;
|
2019-06-14 23:19:38 +00:00
|
|
|
|
Add horizontal scrolling support to IGListCollectionViewLayout
Summary:
Issue fixed: #752
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
This PR generalizes the layout logic in `IGListCollectionViewLayout.mm` to handle horizontally scrolling layouts, mainly by generalizing references to `width`, `height`, `x` and `y` to take scrolling direction into account. This changes the signature of `IGListCollectionViewLayout.init` as well as the names of a few properties, so it would be a breaking change.
I added a couple of unit tests specifically for horizontal layouts -- but held off from adding a horizontal version of *every* unit test for this class, as it would basically double the number of tests. But if you want that, just let me know and I'm happy to do it.
Also let me know if you want me to add a demo VC to the Examples project that uses this new horizontal flow layout -- I have some demo code handy (I used it for testing), but didn't want to clutter up the PR if you didn't want/need it.
Closes https://github.com/Instagram/IGListKit/pull/857
Reviewed By: ryanolsonk
Differential Revision: D5547266
Pulled By: rnystrom
fbshipit-source-id: 6094c45069fc265273d0f95c296fa78e47470384
2017-08-07 16:22:40 +00:00
|
|
|
// bump the coord for the next section with the right insets
|
|
|
|
|
itemCoordInFixedDirection += UIEdgeInsetsTrailingInsetInDirection(insets, fixedDirection);
|
2019-06-14 23:19:38 +00:00
|
|
|
|
Add horizontal scrolling support to IGListCollectionViewLayout
Summary:
Issue fixed: #752
- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
This PR generalizes the layout logic in `IGListCollectionViewLayout.mm` to handle horizontally scrolling layouts, mainly by generalizing references to `width`, `height`, `x` and `y` to take scrolling direction into account. This changes the signature of `IGListCollectionViewLayout.init` as well as the names of a few properties, so it would be a breaking change.
I added a couple of unit tests specifically for horizontal layouts -- but held off from adding a horizontal version of *every* unit test for this class, as it would basically double the number of tests. But if you want that, just let me know and I'm happy to do it.
Also let me know if you want me to add a demo VC to the Examples project that uses this new horizontal flow layout -- I have some demo code handy (I used it for testing), but didn't want to clutter up the PR if you didn't want/need it.
Closes https://github.com/Instagram/IGListKit/pull/857
Reviewed By: ryanolsonk
Differential Revision: D5547266
Pulled By: rnystrom
fbshipit-source-id: 6094c45069fc265273d0f95c296fa78e47470384
2017-08-07 16:22:40 +00:00
|
|
|
// find the farthest point in the section and add the trailing inset to find the next row's coord
|
|
|
|
|
nextRowCoordInScrollDirection = MAX(nextRowCoordInScrollDirection, CGRectGetMaxInDirection(rollingSectionBounds, self.scrollDirection) + UIEdgeInsetsTrailingInsetInDirection(insets, self.scrollDirection));
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-12-15 17:19:20 +00:00
|
|
|
// keep track of coordinates for partial invalidation
|
|
|
|
|
_sectionData[section].lastItemCoordInScrollDirection = itemCoordInScrollDirection;
|
|
|
|
|
_sectionData[section].lastItemCoordInFixedDirection = itemCoordInFixedDirection;
|
|
|
|
|
_sectionData[section].lastNextRowCoordInScrollDirection = nextRowCoordInScrollDirection;
|
2017-02-11 01:58:52 +00:00
|
|
|
}
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-12-15 17:19:20 +00:00
|
|
|
_minimumInvalidatedSection = NSNotFound;
|
2017-02-11 01:58:52 +00:00
|
|
|
}
|
|
|
|
|
|
2018-04-02 22:06:52 +00:00
|
|
|
- (NSRange)_rangeOfSectionsInRect:(CGRect)rect {
|
2017-02-11 01:58:52 +00:00
|
|
|
NSRange result = NSMakeRange(NSNotFound, 0);
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
const NSInteger sectionCount = _sectionData.size();
|
|
|
|
|
for (NSInteger section = 0; section < sectionCount; section++) {
|
|
|
|
|
IGListSectionEntry entry = _sectionData[section];
|
|
|
|
|
if (entry.isValid() && CGRectIntersectsRect(entry.bounds, rect)) {
|
|
|
|
|
const NSRange sectionRange = NSMakeRange(section, 1);
|
|
|
|
|
if (result.location == NSNotFound) {
|
|
|
|
|
result = sectionRange;
|
|
|
|
|
} else {
|
|
|
|
|
result = NSUnionRange(result, sectionRange);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-06-14 23:19:38 +00:00
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-02 22:06:52 +00:00
|
|
|
- (void)_resetSupplementaryAttributesCache {
|
2017-11-21 20:39:09 +00:00
|
|
|
[_supplementaryAttributesCache enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSMutableDictionary<NSIndexPath *,UICollectionViewLayoutAttributes *> * _Nonnull attributesCache, BOOL * _Nonnull stop) {
|
|
|
|
|
[attributesCache removeAllObjects];
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-15 17:19:22 +00:00
|
|
|
#pragma mark - Minimum Invalidated Section
|
|
|
|
|
|
|
|
|
|
- (void)didModifySection:(NSInteger)modifiedSection {
|
|
|
|
|
_minimumInvalidatedSection = IGListMergeMinimumInvalidatedSection(_minimumInvalidatedSection, modifiedSection);
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-11 01:58:52 +00:00
|
|
|
@end
|