From 26924ec3b665d37aeed7e28887e4221a7f3501b1 Mon Sep 17 00:00:00 2001 From: Sue Suhan Ma Date: Mon, 29 Jan 2018 10:54:42 -0800 Subject: [PATCH] Customized post insertion animation 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 --- Source/IGListCollectionViewDelegateLayout.h | 36 +++++++++++++++++++ Source/IGListCollectionViewLayout.mm | 25 +++++++++++++ Source/IGListSectionController.h | 10 ++++++ Source/IGListTransitionDelegate.h | 36 +++++++++++++++++++ .../Internal/IGListAdapter+UICollectionView.h | 3 +- .../Internal/IGListAdapter+UICollectionView.m | 30 ++++++++++++++++ Source/Internal/IGListAdapterProxy.m | 6 +++- 7 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 Source/IGListCollectionViewDelegateLayout.h create mode 100644 Source/IGListTransitionDelegate.h diff --git a/Source/IGListCollectionViewDelegateLayout.h b/Source/IGListCollectionViewDelegateLayout.h new file mode 100644 index 00000000..a1f6b905 --- /dev/null +++ b/Source/IGListCollectionViewDelegateLayout.h @@ -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 + +/** + 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 + diff --git a/Source/IGListCollectionViewLayout.mm b/Source/IGListCollectionViewLayout.mm index cf4f3523..107922fe 100644 --- a/Source/IGListCollectionViewLayout.mm +++ b/Source/IGListCollectionViewLayout.mm @@ -14,6 +14,7 @@ #import #import +#import static CGFloat UIEdgeInsetsLeadingInsetInDirection(UIEdgeInsets insets, UICollectionViewScrollDirection direction) { switch (direction) { @@ -206,6 +207,30 @@ static void adjustZIndexForAttributes(UICollectionViewLayoutAttributes *attribut #pragma mark - UICollectionViewLayout +- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath { + UICollectionViewLayoutAttributes *attributes = [super initialLayoutAttributesForAppearingItemAtIndexPath:itemIndexPath]; + id delegate = (id)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 delegate = (id)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 *)layoutAttributesForElementsInRect:(CGRect)rect { IGAssertMainThread(); diff --git a/Source/IGListSectionController.h b/Source/IGListSectionController.h index 1846a9b9..6cc0cb5a 100644 --- a/Source/IGListSectionController.h +++ b/Source/IGListSectionController.h @@ -14,6 +14,7 @@ #import #import #import +#import NS_ASSUME_NONNULL_BEGIN @@ -200,6 +201,15 @@ NS_SWIFT_NAME(ListSectionController) */ @property (nonatomic, weak, nullable) id 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 transitionDelegate; + @end NS_ASSUME_NONNULL_END diff --git a/Source/IGListTransitionDelegate.h b/Source/IGListTransitionDelegate.h new file mode 100644 index 00000000..34394f1d --- /dev/null +++ b/Source/IGListTransitionDelegate.h @@ -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 + +/** + 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 + diff --git a/Source/Internal/IGListAdapter+UICollectionView.h b/Source/Internal/IGListAdapter+UICollectionView.h index db2e4d0d..b8768b83 100644 --- a/Source/Internal/IGListAdapter+UICollectionView.h +++ b/Source/Internal/IGListAdapter+UICollectionView.h @@ -10,10 +10,11 @@ #import #import +#import @interface IGListAdapter (UICollectionView) < UICollectionViewDataSource, -UICollectionViewDelegateFlowLayout +IGListCollectionViewDelegateLayout > @end diff --git a/Source/Internal/IGListAdapter+UICollectionView.m b/Source/Internal/IGListAdapter+UICollectionView.m index c6b97d37..5cfa3df0 100644 --- a/Source/Internal/IGListAdapter+UICollectionView.m +++ b/Source/Internal/IGListAdapter+UICollectionView.m @@ -211,4 +211,34 @@ 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) { + 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 diff --git a/Source/Internal/IGListAdapterProxy.m b/Source/Internal/IGListAdapterProxy.m index af3b2686..7b0bc214 100644 --- a/Source/Internal/IGListAdapterProxy.m +++ b/Source/Internal/IGListAdapterProxy.m @@ -10,6 +10,7 @@ #import "IGListAdapterProxy.h" #import +#import "IGListCollectionViewDelegateLayout.h" /** Define messages that you want the IGListAdapter object to intercept. Pattern copied from @@ -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:) ); }