Skip to content

Commit

Permalink
Add horizontal scrolling support to IGListCollectionViewLayout
Browse files Browse the repository at this point in the history
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 #857

Reviewed By: ryanolsonk

Differential Revision: D5547266

Pulled By: rnystrom

fbshipit-source-id: 6094c45069fc265273d0f95c296fa78e47470384
  • Loading branch information
Peter Edmonston authored and facebook-github-bot committed Aug 7, 2017
1 parent 5bede7b commit 9e31227
Show file tree
Hide file tree
Showing 5 changed files with 354 additions and 79 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ The changelog for `IGListKit`. Also see the [releases](https://github.com/instag
- Added `-[IGListSectionController didDeselectItemAtIndex:]` API to support default `UICollectionView` cell deselection. [Ryan Nystrom](https://github.com/rnystrom) (tbd)
- Added `-[IGListCollectionContext selectItemAtIndex:]` Select an item through IGListCollectionContext like `-[IGListCollectionContext deselectItemAtIndex:]`. [Marvin Nazari](https://github.com/MarvinNazari) (tbd)

- Added horizontal scrolling support to `IGListCollectionViewLayout`. [Peter Edmonston](https://github.com/edmonston) [(#857)](https://github.com/Instagram/IGListKit/pull/857)

3.0.0
-----

Expand Down
49 changes: 37 additions & 12 deletions Source/IGListCollectionViewLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
NS_ASSUME_NONNULL_BEGIN

/**
This UICollectionViewLayout subclass is for vertically-scrolling lists of data with variable widths and heights. It
supports an infinite number of sections and items. All work is done on the main thread, and while extremely efficient,
This UICollectionViewLayout subclass is for vertically or horizontally scrolling lists of data with variable widths and
heights. It supports an infinite number of sections and items. All work is done on the main thread, and while extremely efficient,
care must be taken not to stall the main thread in sizing delegate methods.
This layout piggybacks on the mechanics of UICollectionViewFlowLayout in that:
Expand All @@ -33,9 +33,9 @@ NS_ASSUME_NONNULL_BEGIN
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section;
```
Sections and items are put into the same horizontal row until the max-x position of an item extends beyond the width
of the collection view. When that happens, the item is "newlined" to the next row. The y position of that row is
determined by the maximum height (including section insets) of the section/item of the previous row.
In a vertically scrolling layout, sections and items are put into the same horizontal row until the max-x position
of an item extends beyond the width of the collection view. When that happens, the item is "newlined" to the next row.
The y position of that row is determined by the maximum height (including section insets) of the section/item of the previous row.
Ex. of a section (2,0) with a large width causing a newline.
```
Expand Down Expand Up @@ -64,34 +64,59 @@ NS_ASSUME_NONNULL_BEGIN
Interitem spacing applies to items and sections within the same row. Line spacing only applies to items within the same
section.
In a horizontally scrolling layout, sections and items are flowed vertically until they need to be "newlined" to the
next column. Headers, if used, are stretched to the height of the collection view, minus the section insets.
Please see the unit tests for more configuration examples and expected output.
*/
NS_SWIFT_NAME(ListCollectionViewLayout)
@interface IGListCollectionViewLayout : UICollectionViewLayout

/**
Set this to adjust the offset of the sticky headers. Can be used to change the sticky header position as UI like the
navigation bar is scrolled offscreen. Changing this to the height of the navigation bar will give the effect of the
headers sticking to the nav as it is collapsed.
Direction in which layout will be scrollable; items will be flowed in the perpendicular direction, "newlining" when they
run out of space along that axis or when a non-zero header is found.
*/
@property (nonatomic, readonly) UICollectionViewScrollDirection scrollDirection;

/**
Set this to adjust the offset of the sticky headers in the scrolling direction. Can be used to change the sticky
header position as UI like the navigation bar is scrolled offscreen. In a vertically scrolling layout, changing
this to the height of the navigation bar will give the effect of the headers sticking to the nav as it is collapsed.
@discussion Changing the value on this method will invalidate the layout every time.
@note Changing the value on this method will invalidate the layout every time.
*/
@property (nonatomic, assign) CGFloat stickyHeaderOriginYAdjustment;
@property (nonatomic, assign) CGFloat stickyHeaderYOffset;


/**
Create and return a new collection view layout.
@param stickyHeaders Set to `YES` to stick section headers to the top of the bounds while scrolling.
@param topContentInset The top content inset used to offset the sticky headers. Ignored if stickyHeaders is `NO`.
@param stretchToEdge Specifies whether to stretch width of last item to right edge when distance from last item to right edge < epsilon(1)
@param scrollDirection Direction along which the collection view will be scrollable (if content size exceeds the frame size)
@param topContentInset The content inset (top or left, depending on scrolling direction) used to offset the sticky headers. Ignored if stickyHeaders is `NO`.
@param stretchToEdge Specifies whether to stretch width (in vertically scrolling layout) or height (horizontally scrolling) of last item to right/bottom edge when distance from last item to right/bottom edge < epsilon(1)
@return A new collection view layout.
*/
- (instancetype)initWithStickyHeaders:(BOOL)stickyHeaders
scrollDirection:(UICollectionViewScrollDirection)scrollDirection
topContentInset:(CGFloat)topContentInset
stretchToEdge:(BOOL)stretchToEdge NS_DESIGNATED_INITIALIZER;

/**
Create and return a new vertically scrolling collection view layout.
@param stickyHeaders Set to `YES` to stick section headers to the top of the bounds while scrolling.
@param topContentInset The top content inset used to offset the sticky headers. Ignored if stickyHeaders is `NO`.
@param stretchToEdge Specifies whether to stretch width of last item to right edge when distance from last item to right edge < epsilon(1)
@return A new collection view layout.
*/
- (instancetype)initWithStickyHeaders:(BOOL)stickyHeaders
topContentInset:(CGFloat)topContentInset
stretchToEdge:(BOOL)stretchToEdge;

/**
:nodoc:
*/
Expand Down
Loading

0 comments on commit 9e31227

Please sign in to comment.