Skip to content

Commit

Permalink
Customized post insertion animation
Browse files Browse the repository at this point in the history
Summary:
The current animation is the collection default animation - fade in/out: demo: https://pxl.cl/bj8R
Based on our design, we want the Shelf to be push down: demo https://pxl.cl/bj9R

1. Created **IGListCollectionViewDelegate** which inherits **UICollectionViewDelegateFlowLayout**
2. **IGListAdapter ** conforms **UICollectionViewDelegateFlowLayout**
3. add **transitionDelegate** to IGListSectionController
4. **IGFeedSectionController** sets transitionDelegate as itself and handles IGListCollectionViewDelegate methods

Reviewed By: rnystrom

Differential Revision: D6785726

fbshipit-source-id: bdf19f84fef05264ca0e082c6a326a31494a20da
  • Loading branch information
myworkaccount authored and facebook-github-bot committed Jan 29, 2018
1 parent b0283bf commit 26924ec
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 2 deletions.
36 changes: 36 additions & 0 deletions Source/IGListCollectionViewDelegateLayout.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* Copyright (c) 2016-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

/**
Conform to `IGListCollectionViewDelegateLayout` to provide customized layout information for a collection view.
*/
@protocol IGListCollectionViewDelegateLayout <UICollectionViewDelegateFlowLayout>

/**
Asks the delegate to customize and return the starting layout information for an item being inserted into the collection view.
@param collectionView The collection view to perform the transition on.
@param collectionViewLayout The layout to use with the collection view.
@param attributes The starting layout information for an item being inserted into the collection view.
@param indexPath The index path of the item being inserted.
*/
- (UICollectionViewLayoutAttributes *)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout customizedInitialLayoutAttributes:(UICollectionViewLayoutAttributes *)attributes atIndexPath:(NSIndexPath *)indexPath;

/**
Asks the delegate to customize and return the final layout information for an item that is about to be removed from the collection view.
@param collectionView The collection view to perform the transition on.
@param collectionViewLayout The layout to use with the collection view.
@param attributes The final layout information for an item that is about to be removed from the collection view.
@param indexPath The index path of the item being deleted.
*/
- (UICollectionViewLayoutAttributes *)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout customizedFinalLayoutAttributes:(UICollectionViewLayoutAttributes *)attributes atIndexPath:(NSIndexPath *)indexPath;

@end

25 changes: 25 additions & 0 deletions Source/IGListCollectionViewLayout.mm
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#import <vector>

#import <IGListKit/IGListAssert.h>
#import <IGListKit/IGListCollectionViewDelegateLayout.h>

static CGFloat UIEdgeInsetsLeadingInsetInDirection(UIEdgeInsets insets, UICollectionViewScrollDirection direction) {
switch (direction) {
Expand Down Expand Up @@ -206,6 +207,30 @@ - (instancetype)initWithCoder:(NSCoder *)aDecoder {

#pragma mark - UICollectionViewLayout

- (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

This comment has been minimized.

Copy link
@jessesquires

jessesquires Jan 29, 2018

Contributor

Seems like it would be better to introduce a new delegate instead of piggy-backing on the default.

Maybe that's too much trouble though?

This comment has been minimized.

Copy link
@rnystrom

rnystrom Jan 29, 2018

Contributor

Ya we could, though it'll all be the same in the end. I'm not too offended by it tbh. A little sprinkle of magic 😉

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;
}

- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
IGAssertMainThread();

Expand Down
10 changes: 10 additions & 0 deletions Source/IGListSectionController.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#import <IGListKit/IGListScrollDelegate.h>
#import <IGListKit/IGListSupplementaryViewSource.h>
#import <IGListKit/IGListWorkingRangeDelegate.h>
#import <IGListKit/IGListTransitionDelegate.h>

NS_ASSUME_NONNULL_BEGIN

Expand Down Expand Up @@ -200,6 +201,15 @@ NS_SWIFT_NAME(ListSectionController)
*/
@property (nonatomic, weak, nullable) id <IGListScrollDelegate> scrollDelegate;

/**
An object that handles transition events for the section controller. Can be `nil`.
@return An object that conforms to `IGListTransitionDelegat` or `nil`.
@note You may wish to return `self` if your section controller implements this protocol.
*/
@property (nonatomic, weak, nullable) id<IGListTransitionDelegate> transitionDelegate;

@end

NS_ASSUME_NONNULL_END
36 changes: 36 additions & 0 deletions Source/IGListTransitionDelegate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* Copyright (c) 2016-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

/**
Conform to `IGListTransitionDelegate` to provide customized layout information for a collection view.
*/
@protocol IGListTransitionDelegate

This comment has been minimized.

Copy link
@jessesquires

jessesquires Jan 29, 2018

Contributor

This should be <NSObject>, I'm pretty sure

This comment has been minimized.

Copy link
@rnystrom

rnystrom Jan 29, 2018

Contributor

Ya it should


/**
Asks the delegate to customize and return the starting layout information for an item being inserted into the collection view.
@param listAdapter The adapter controlling the list.
@param attributes The starting layout information for an item being inserted into the collection view.
@param sectionController The section controller to perform the transition on.
@param index The index of the item being inserted.
*/
- (UICollectionViewLayoutAttributes *)listAdapter:(IGListAdapter *)listAdapter customizedInitialLayoutAttributes:(UICollectionViewLayoutAttributes *)attributes sectionController:(IGListSectionController *)sectionController atIndex:(NSInteger)index;

/**
Asks the delegate to customize and return the final layout information for an item that is about to be removed from the collection view.
@param listAdapter The adapter controlling the list.
@param attributes The final layout information for an item that is about to be removed from the collection view.
@param sectionController The section controller to perform the transition on.
@param index The index of the item being deleted.
*/
- (UICollectionViewLayoutAttributes *)listAdapter:(IGListAdapter *)listAdapter customizedFinalLayoutAttributes:(UICollectionViewLayoutAttributes *)attributes sectionController:(IGListSectionController *)sectionController atIndex:(NSInteger)index;

@end

3 changes: 2 additions & 1 deletion Source/Internal/IGListAdapter+UICollectionView.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@
#import <UIKit/UIKit.h>

#import <IGListKit/IGListAdapter.h>
#import <IGListKit/IGListCollectionViewDelegateLayout.h>

@interface IGListAdapter (UICollectionView)
<
UICollectionViewDataSource,
UICollectionViewDelegateFlowLayout

This comment has been minimized.

Copy link
@jessesquires

jessesquires Jan 29, 2018

Contributor

@rnystrom isn't this a bug? ListAdapter should still conform to this, right?

This comment has been minimized.

Copy link
@rnystrom

rnystrom Jan 29, 2018

Contributor

IGListCollectionViewDelegateLayout inherits from UICollectionViewDelegateFlowLayout

This comment has been minimized.

Copy link
@jessesquires

jessesquires Jan 30, 2018

Contributor

oh derp.

#inheritance 😏

IGListCollectionViewDelegateLayout
>
@end
30 changes: 30 additions & 0 deletions Source/Internal/IGListAdapter+UICollectionView.m
Original file line number Diff line number Diff line change
Expand Up @@ -211,4 +211,34 @@ - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollection
return [self sizeForSupplementaryViewOfKind:UICollectionElementKindSectionFooter atIndexPath:indexPath];
}

#pragma mark - IGListCollectionViewDelegateLayout

- (UICollectionViewLayoutAttributes *)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout*)collectionViewLayout
customizedInitialLayoutAttributes:(UICollectionViewLayoutAttributes *)attributes
atIndexPath:(NSIndexPath *)indexPath {
IGListSectionController *sectionController = [self sectionControllerForSection:indexPath.section];
if (sectionController.transitionDelegate) {

This comment has been minimized.

Copy link
@jessesquires

jessesquires Jan 29, 2018

Contributor

these 2 if checks aren't needed, right? if .transitionDelegate is nil, this will no-op...

This comment has been minimized.

Copy link
@rnystrom

rnystrom Jan 29, 2018

Contributor

Ya, should remove and just let it message nil

return [sectionController.transitionDelegate listAdapter:self
customizedInitialLayoutAttributes:attributes
sectionController:sectionController
atIndex:indexPath.item];
}
return attributes;
}

- (UICollectionViewLayoutAttributes *)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout*)collectionViewLayout
customizedFinalLayoutAttributes:(UICollectionViewLayoutAttributes *)attributes
atIndexPath:(NSIndexPath *)indexPath {
IGListSectionController *sectionController = [self sectionControllerForSection:indexPath.section];
if (sectionController.transitionDelegate) {
return [sectionController.transitionDelegate listAdapter:self
customizedFinalLayoutAttributes:attributes
sectionController:sectionController
atIndex:indexPath.item];
}
return attributes;
}

@end
6 changes: 5 additions & 1 deletion Source/Internal/IGListAdapterProxy.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#import "IGListAdapterProxy.h"

#import <IGListKit/IGListAssert.h>
#import "IGListCollectionViewDelegateLayout.h"

/**
Define messages that you want the IGListAdapter object to intercept. Pattern copied from
Expand All @@ -34,7 +35,10 @@ static BOOL isInterceptedSelector(SEL sel) {
sel == @selector(scrollViewDidScroll:) ||
sel == @selector(scrollViewWillBeginDragging:) ||
sel == @selector(scrollViewDidEndDragging:willDecelerate:) ||
sel == @selector(scrollViewDidEndDecelerating:)
sel == @selector(scrollViewDidEndDecelerating:) ||
// IGListCollectionViewDelegateLayout
sel == @selector(collectionView:layout:customizedInitialLayoutAttributes:atIndexPath:) ||
sel == @selector(collectionView:layout:customizedFinalLayoutAttributes:atIndexPath:)
);
}

Expand Down

0 comments on commit 26924ec

Please sign in to comment.