From 588f30c7dd20e22386783b1ca6ceb2ac893b386a Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Thu, 4 May 2017 05:41:58 -0700 Subject: [PATCH] Move Last Few Properties from ASTableView,ASCollectionView to Node (#225) * Finish moving properties ASTableView->ASTableNode, ASCollectionView->ASCollectionNode * Update changeling --- CHANGELOG.md | 1 + Source/ASCollectionNode.h | 35 +++++++++- Source/ASCollectionNode.mm | 40 +++++++++++ Source/ASCollectionView.h | 67 +++++++++---------- Source/ASCollectionView.mm | 22 ++++++ Source/ASTableNode.h | 19 ++++++ Source/ASTableNode.mm | 46 +++++++++++++ Source/ASTableView.h | 54 +++++++-------- Source/ASTableView.mm | 35 ++++++++++ .../ASCollectionViewLayoutController.m | 2 +- .../Private/ASCollectionView+Undeprecated.h | 10 +++ Source/Private/ASTableView+Undeprecated.h | 4 ++ 12 files changed, 266 insertions(+), 69 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b091f3c80..0f88d83431 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,5 +9,6 @@ - Update the rasterization API and un-deprecate it. [Adlai Holler](https://github.com/Adlai-Holler)[#82](https://github.com/TextureGroup/Texture/pull/49) - Simplified & optimized hashing code. [Adlai Holler](https://github.com/Adlai-Holler) [#86](https://github.com/TextureGroup/Texture/pull/86) - Improve the performance & safety of ASDisplayNode subnodes. [Adlai Holler](https://github.com/Adlai-Holler) [#223](https://github.com/TextureGroup/Texture/pull/223) +- Move more properties from ASTableView, ASCollectionView to their respective node classes. [Adlai Holler](https://github.com/Adlai-Holler) - Remove finalLayoutElement [Michael Schneider] (https://github.com/maicki)[#96](https://github.com/TextureGroup/Texture/pull/96) - Add ASPageTable - A map table for fast retrieval of objects within a certain page [Huy Nguyen](https://github.com/nguyenhuy) diff --git a/Source/ASCollectionNode.h b/Source/ASCollectionNode.h index b3b8e30623..c614cd85c7 100644 --- a/Source/ASCollectionNode.h +++ b/Source/ASCollectionNode.h @@ -83,6 +83,13 @@ NS_ASSUME_NONNULL_BEGIN */ @property (weak, nonatomic) id dataSource; +/** + * The number of screens left to scroll before the delegate -collectionNode:beginBatchFetchingWithContext: is called. + * + * Defaults to two screenfuls. + */ +@property (nonatomic, assign) CGFloat leadingScreensForBatching; + /* * A Boolean value that determines whether the collection node will be flipped. * If the value of this property is YES, the first cell node will be at the bottom of the collection node (as opposed to the top by default). This is useful for chat/messaging apps. The default value is NO. @@ -109,6 +116,18 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic, strong) UICollectionViewLayout *collectionViewLayout; +/** + * Optional introspection object for the collection node's layout. + * + * @discussion Since supplementary and decoration nodes are controlled by the layout, this object + * is used as a bridge to provide information to the internal data controller about the existence of these views and + * their associated index paths. For collections using `UICollectionViewFlowLayout`, a default inspector + * implementation `ASCollectionViewFlowLayoutInspector` is created and set on this property by default. Custom + * collection layout subclasses will need to provide their own implementation of an inspector object for their + * supplementary elements to be compatible with `ASCollectionNode`'s supplementary node support. + */ +@property (nonatomic, weak) id layoutInspector; + /** * Tuning parameters for a range type in full mode. * @@ -168,6 +187,20 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)scrollToItemAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UICollectionViewScrollPosition)scrollPosition animated:(BOOL)animated; +/** + * Determines collection node's current scroll direction. Supports 2-axis collection nodes. + * + * @return a bitmask of ASScrollDirection values. + */ +@property (nonatomic, readonly) ASScrollDirection scrollDirection; + +/** + * Determines collection node's scrollable directions. + * + * @return a bitmask of ASScrollDirection values. + */ +@property (nonatomic, readonly) ASScrollDirection scrollableDirections; + #pragma mark - Editing /** @@ -745,7 +778,7 @@ NS_ASSUME_NONNULL_BEGIN * 4. Lastly, you must implement a method to provide the size for the cell. There are two ways this is done: * 4a. UICollectionViewFlowLayout (incl. ASPagerNode). Implement collectionNode:constrainedSizeForItemAtIndexPath:. - * 4b. Custom collection layouts. Set .view.layoutInspector and have it implement + * 4b. Custom collection layouts. Set .layoutInspector and have it implement collectionView:constrainedSizeForNodeAtIndexPath:. * * For an example of using this method with all steps above (including a custom layout, 4b.), diff --git a/Source/ASCollectionNode.mm b/Source/ASCollectionNode.mm index 469d73b46b..9bcdc78061 100644 --- a/Source/ASCollectionNode.mm +++ b/Source/ASCollectionNode.mm @@ -45,6 +45,8 @@ @property (nonatomic, assign) BOOL allowsSelection; // default is YES @property (nonatomic, assign) BOOL allowsMultipleSelection; // default is NO @property (nonatomic, assign) BOOL inverted; //default is NO +@property (nonatomic, assign) CGFloat leadingScreensForBatching; +@property (weak, nonatomic) id layoutInspector; @end @implementation _ASCollectionPendingState @@ -275,6 +277,44 @@ } } +- (void)setLayoutInspector:(id)layoutInspector +{ + if ([self pendingState]) { + _pendingState.layoutInspector = layoutInspector; + } else { + ASDisplayNodeAssert([self isNodeLoaded], @"ASCollectionNode should be loaded if pendingState doesn't exist"); + self.view.layoutInspector = layoutInspector; + } +} + +- (id)layoutInspector +{ + if ([self pendingState]) { + return _pendingState.layoutInspector; + } else { + return self.view.layoutInspector; + } +} + +- (void)setLeadingScreensForBatching:(CGFloat)leadingScreensForBatching +{ + if ([self pendingState]) { + _pendingState.leadingScreensForBatching = leadingScreensForBatching; + } else { + ASDisplayNodeAssert([self isNodeLoaded], @"ASCollectionNode should be loaded if pendingState doesn't exist"); + self.view.leadingScreensForBatching = leadingScreensForBatching; + } +} + +- (CGFloat)leadingScreensForBatching +{ + if ([self pendingState]) { + return _pendingState.leadingScreensForBatching; + } else { + return self.view.leadingScreensForBatching; + } +} + - (void)setDelegate:(id )delegate { if ([self pendingState]) { diff --git a/Source/ASCollectionView.h b/Source/ASCollectionView.h index 44e590c486..2972ced495 100644 --- a/Source/ASCollectionView.h +++ b/Source/ASCollectionView.h @@ -36,13 +36,6 @@ NS_ASSUME_NONNULL_BEGIN /** * Asynchronous UICollectionView with Intelligent Preloading capabilities. * - * @discussion ASCollectionView is a true subclass of UICollectionView, meaning it is pointer-compatible - * with code that currently uses UICollectionView. - * - * The main difference is that asyncDataSource expects -nodeForItemAtIndexPath, an ASCellNode, and - * the sizeForItemAtIndexPath: method is eliminated (as are the performance problems caused by it). - * This is made possible because ASCellNodes can calculate their own size, and preload ahead of time. - * * @note ASCollectionNode is strongly recommended over ASCollectionView. This class exists for adoption convenience. */ @interface ASCollectionView : UICollectionView @@ -54,25 +47,6 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic, weak, readonly) ASCollectionNode *collectionNode; -/** - * The number of screens left to scroll before the delegate -collectionView:beginBatchFetchingWithContext: is called. - * - * Defaults to two screenfuls. - */ -@property (nonatomic, assign) CGFloat leadingScreensForBatching; - -/** - * Optional introspection object for the collection view's layout. - * - * @discussion Since supplementary and decoration views are controlled by the collection view's layout, this object - * is used as a bridge to provide information to the internal data controller about the existence of these views and - * their associated index paths. For collection views using `UICollectionViewFlowLayout`, a default inspector - * implementation `ASCollectionViewFlowLayoutInspector` is created and set on this property by default. Custom - * collection view layout subclasses will need to provide their own implementation of an inspector object for their - * supplementary views to be compatible with `ASCollectionView`'s supplementary node support. - */ -@property (nonatomic, weak) id layoutInspector; - /** * Retrieves the node for the item at the given index path. * @@ -115,28 +89,47 @@ NS_ASSUME_NONNULL_BEGIN */ - (nullable id)contextForSection:(NSInteger)section AS_WARN_UNUSED_RESULT; +@end + +@interface ASCollectionView (Deprecated) + +/* + * A Boolean value that determines whether the nodes that the data source renders will be flipped. + */ +@property (nonatomic, assign) BOOL inverted ASDISPLAYNODE_DEPRECATED_MSG("Use ASCollectionNode property instead."); + +/** + * The number of screens left to scroll before the delegate -collectionView:beginBatchFetchingWithContext: is called. + * + * Defaults to two screenfuls. + */ +@property (nonatomic, assign) CGFloat leadingScreensForBatching ASDISPLAYNODE_DEPRECATED_MSG("Use ASCollectionNode property instead."); + +/** + * Optional introspection object for the collection view's layout. + * + * @discussion Since supplementary and decoration views are controlled by the collection view's layout, this object + * is used as a bridge to provide information to the internal data controller about the existence of these views and + * their associated index paths. For collection views using `UICollectionViewFlowLayout`, a default inspector + * implementation `ASCollectionViewFlowLayoutInspector` is created and set on this property by default. Custom + * collection view layout subclasses will need to provide their own implementation of an inspector object for their + * supplementary views to be compatible with `ASCollectionView`'s supplementary node support. + */ +@property (nonatomic, weak) id layoutInspector ASDISPLAYNODE_DEPRECATED_MSG("Use ASCollectionNode property instead."); + /** * Determines collection view's current scroll direction. Supports 2-axis collection views. * * @return a bitmask of ASScrollDirection values. */ -@property (nonatomic, readonly) ASScrollDirection scrollDirection; +@property (nonatomic, readonly) ASScrollDirection scrollDirection ASDISPLAYNODE_DEPRECATED_MSG("Use ASCollectionNode property instead."); /** * Determines collection view's scrollable directions. * * @return a bitmask of ASScrollDirection values. */ -@property (nonatomic, readonly) ASScrollDirection scrollableDirections; - -/* - * A Boolean value that determines whether the nodes that the data source renders will be flipped. - */ -@property (nonatomic, assign) BOOL inverted; - -@end - -@interface ASCollectionView (Deprecated) +@property (nonatomic, readonly) ASScrollDirection scrollableDirections ASDISPLAYNODE_DEPRECATED_MSG("Use ASCollectionNode property instead."); /** * Forces the .contentInset to be UIEdgeInsetsZero. diff --git a/Source/ASCollectionView.mm b/Source/ASCollectionView.mm index fe7d0f5109..47d13e8495 100644 --- a/Source/ASCollectionView.mm +++ b/Source/ASCollectionView.mm @@ -92,6 +92,8 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier"; NSMutableSet *_cellsForVisibilityUpdates; NSMutableSet *_cellsForLayoutUpdates; id _layoutFacilitator; + CGFloat _leadingScreensForBatching; + BOOL _inverted; NSUInteger _superBatchUpdateCount; BOOL _isDeallocating; @@ -1388,6 +1390,26 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier"; #pragma mark - Scroll Direction. +- (BOOL)inverted +{ + return _inverted; +} + +- (void)setInverted:(BOOL)inverted +{ + _inverted = inverted; +} + +- (void)setLeadingScreensForBatching:(CGFloat)leadingScreensForBatching +{ + _leadingScreensForBatching = leadingScreensForBatching; +} + +- (CGFloat)leadingScreensForBatching +{ + return _leadingScreensForBatching; +} + - (ASScrollDirection)scrollDirection { CGPoint scrollVelocity; diff --git a/Source/ASTableNode.h b/Source/ASTableNode.h index a68efc47cb..dec925465a 100644 --- a/Source/ASTableNode.h +++ b/Source/ASTableNode.h @@ -42,11 +42,30 @@ NS_ASSUME_NONNULL_BEGIN @property (weak, nonatomic) id delegate; @property (weak, nonatomic) id dataSource; +/** + * The number of screens left to scroll before the delegate -tableNode:beginBatchFetchingWithContext: is called. + * + * Defaults to two screenfuls. + */ +@property (nonatomic, assign) CGFloat leadingScreensForBatching; + /* * A Boolean value that determines whether the table will be flipped. * If the value of this property is YES, the first cell node will be at the bottom of the table (as opposed to the top by default). This is useful for chat/messaging apps. The default value is NO. */ @property (nonatomic, assign) BOOL inverted; + +/** + * YES to automatically adjust the contentOffset when cells are inserted or deleted above + * visible cells, maintaining the users' visible scroll position. + * + * @note This is only applied to non-animated updates. For animated updates, there is no way to + * synchronize or "cancel out" the appearance of a scroll due to UITableView API limitations. + * + * default is NO. + */ +@property (nonatomic, assign) BOOL automaticallyAdjustsContentOffset; + /* * A Boolean value that determines whether users can select a row. * If the value of this property is YES (the default), users can select rows. If you set it to NO, they cannot select rows. Setting this property affects cell selection only when the table view is not in editing mode. If you want to restrict selection of cells in editing mode, use `allowsSelectionDuringEditing`. diff --git a/Source/ASTableNode.mm b/Source/ASTableNode.mm index a94441cc23..9241e09559 100644 --- a/Source/ASTableNode.mm +++ b/Source/ASTableNode.mm @@ -40,6 +40,8 @@ @property (nonatomic, assign) BOOL allowsMultipleSelection; @property (nonatomic, assign) BOOL allowsMultipleSelectionDuringEditing; @property (nonatomic, assign) BOOL inverted; +@property (nonatomic, assign) CGFloat leadingScreensForBatching; +@property (nonatomic, assign) BOOL automaticallyAdjustsContentOffset; @end @implementation _ASTablePendingState @@ -53,6 +55,8 @@ _allowsMultipleSelection = NO; _allowsMultipleSelectionDuringEditing = NO; _inverted = NO; + _leadingScreensForBatching = 2; + _automaticallyAdjustsContentOffset = NO; } return self; } @@ -204,6 +208,48 @@ } } +- (void)setLeadingScreensForBatching:(CGFloat)leadingScreensForBatching +{ + _ASTablePendingState *pendingState = self.pendingState; + if (pendingState) { + pendingState.leadingScreensForBatching = leadingScreensForBatching; + } else { + ASDisplayNodeAssert(self.nodeLoaded, @"ASTableNode should be loaded if pendingState doesn't exist"); + self.view.leadingScreensForBatching = leadingScreensForBatching; + } +} + +- (CGFloat)leadingScreensForBatching +{ + _ASTablePendingState *pendingState = self.pendingState; + if (pendingState) { + return pendingState.leadingScreensForBatching; + } else { + return self.view.leadingScreensForBatching; + } +} + +- (void)setAutomaticallyAdjustsContentOffset:(BOOL)automaticallyAdjustsContentOffset +{ + _ASTablePendingState *pendingState = self.pendingState; + if (pendingState) { + pendingState.automaticallyAdjustsContentOffset = automaticallyAdjustsContentOffset; + } else { + ASDisplayNodeAssert(self.nodeLoaded, @"ASTableNode should be loaded if pendingState doesn't exist"); + self.view.automaticallyAdjustsContentOffset = automaticallyAdjustsContentOffset; + } +} + +- (BOOL)automaticallyAdjustsContentOffset +{ + _ASTablePendingState *pendingState = self.pendingState; + if (pendingState) { + return pendingState.automaticallyAdjustsContentOffset; + } else { + return self.view.automaticallyAdjustsContentOffset; + } +} + - (void)setDelegate:(id )delegate { if ([self pendingState]) { diff --git a/Source/ASTableView.h b/Source/ASTableView.h index c99e343fde..eb0c92c984 100644 --- a/Source/ASTableView.h +++ b/Source/ASTableView.h @@ -31,13 +31,6 @@ NS_ASSUME_NONNULL_BEGIN /** * Asynchronous UITableView with Intelligent Preloading capabilities. * - * @discussion ASTableView is a true subclass of UITableView, meaning it is pointer-compatible with code that - * currently uses UITableView - * - * The main difference is that asyncDataSource expects -nodeForRowAtIndexPath, an ASCellNode, and - * the heightForRowAtIndexPath: method is eliminated (as are the performance problems caused by it). - * This is made possible because ASCellNodes can calculate their own size, and preload ahead of time. - * * @note ASTableNode is strongly recommended over ASTableView. This class is provided for adoption convenience. */ @interface ASTableView : UITableView @@ -50,29 +43,6 @@ NS_ASSUME_NONNULL_BEGIN */ - (nullable ASCellNode *)nodeForRowAtIndexPath:(NSIndexPath *)indexPath AS_WARN_UNUSED_RESULT; -/** - * YES to automatically adjust the contentOffset when cells are inserted or deleted above - * visible cells, maintaining the users' visible scroll position. - * - * @note This is only applied to non-animated updates. For animated updates, there is no way to - * synchronize or "cancel out" the appearance of a scroll due to UITableView API limitations. - * - * default is NO. - */ -@property (nonatomic) BOOL automaticallyAdjustsContentOffset; - -/** - * The number of screens left to scroll before the delegate -tableView:beginBatchFetchingWithContext: is called. - * - * Defaults to two screenfuls. - */ -@property (nonatomic, assign) CGFloat leadingScreensForBatching; - -/* - * A Boolean value that determines whether the nodes that the data source renders will be flipped. - */ -@property (nonatomic, assign) BOOL inverted; - @end @interface ASTableView (Deprecated) @@ -90,6 +60,30 @@ NS_ASSUME_NONNULL_BEGIN */ - (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style ASDISPLAYNODE_DEPRECATED_MSG("Please use ASTableNode instead of ASTableView."); +/** + * The number of screens left to scroll before the delegate -tableView:beginBatchFetchingWithContext: is called. + * + * Defaults to two screenfuls. + */ +@property (nonatomic, assign) CGFloat leadingScreensForBatching ASDISPLAYNODE_DEPRECATED_MSG("Use ASTableNode property instead."); + + +/** + * YES to automatically adjust the contentOffset when cells are inserted or deleted above + * visible cells, maintaining the users' visible scroll position. + * + * @note This is only applied to non-animated updates. For animated updates, there is no way to + * synchronize or "cancel out" the appearance of a scroll due to UITableView API limitations. + * + * default is NO. + */ +@property (nonatomic) BOOL automaticallyAdjustsContentOffset ASDISPLAYNODE_DEPRECATED_MSG("Use ASTableNode property instead."); + +/* + * A Boolean value that determines whether the nodes that the data source renders will be flipped. + */ +@property (nonatomic, assign) BOOL inverted ASDISPLAYNODE_DEPRECATED_MSG("Use ASTableNode property instead."); + /** * Tuning parameters for a range type in full mode. * diff --git a/Source/ASTableView.mm b/Source/ASTableView.mm index c7cc544c9c..d3cb59bcac 100644 --- a/Source/ASTableView.mm +++ b/Source/ASTableView.mm @@ -161,11 +161,14 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; // When we update our data controller in response to an interactive move, // we don't want to tell the table view about the change (it knows!) BOOL _updatingInResponseToInteractiveMove; + BOOL _inverted; // The top cell node that was visible before the update. __weak ASCellNode *_contentOffsetAdjustmentTopVisibleNode; // The y-offset of the top visible row's origin before the update. CGFloat _contentOffsetAdjustmentTopVisibleNodeOffset; + CGFloat _leadingScreensForBatching; + BOOL _automaticallyAdjustsContentOffset; CGPoint _deceleratingVelocity; @@ -1275,6 +1278,38 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; } } +#pragma mark - Misc + +- (BOOL)inverted +{ + return _inverted; +} + +- (void)setInverted:(BOOL)inverted +{ + _inverted = inverted; +} + +- (CGFloat)leadingScreensForBatching +{ + return _leadingScreensForBatching; +} + +- (void)setLeadingScreensForBatching:(CGFloat)leadingScreensForBatching +{ + _leadingScreensForBatching = leadingScreensForBatching; +} + +- (BOOL)automaticallyAdjustsContentOffset +{ + return _automaticallyAdjustsContentOffset; +} + +- (void)setAutomaticallyAdjustsContentOffset:(BOOL)automaticallyAdjustsContentOffset +{ + _automaticallyAdjustsContentOffset = automaticallyAdjustsContentOffset; +} + #pragma mark - Scroll Direction - (ASScrollDirection)scrollDirection diff --git a/Source/Details/ASCollectionViewLayoutController.m b/Source/Details/ASCollectionViewLayoutController.m index 4336e2711d..c61d95da66 100644 --- a/Source/Details/ASCollectionViewLayoutController.m +++ b/Source/Details/ASCollectionViewLayoutController.m @@ -18,7 +18,7 @@ #import #import -#import +#import #import #import #import diff --git a/Source/Private/ASCollectionView+Undeprecated.h b/Source/Private/ASCollectionView+Undeprecated.h index 777c10b9fb..2764d479a8 100644 --- a/Source/Private/ASCollectionView+Undeprecated.h +++ b/Source/Private/ASCollectionView+Undeprecated.h @@ -65,6 +65,16 @@ NS_ASSUME_NONNULL_BEGIN */ - (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout; +@property (nonatomic, assign) CGFloat leadingScreensForBatching; + +@property (nonatomic, assign) BOOL inverted; + +@property (nonatomic, readonly) ASScrollDirection scrollDirection; + +@property (nonatomic, readonly) ASScrollDirection scrollableDirections; + +@property (nonatomic, weak) id layoutInspector; + /** * Tuning parameters for a range type in full mode. * diff --git a/Source/Private/ASTableView+Undeprecated.h b/Source/Private/ASTableView+Undeprecated.h index 17e74e117b..f7d0d2a264 100644 --- a/Source/Private/ASTableView+Undeprecated.h +++ b/Source/Private/ASTableView+Undeprecated.h @@ -44,6 +44,10 @@ NS_ASSUME_NONNULL_BEGIN */ - (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style; +@property (nonatomic, assign) BOOL automaticallyAdjustsContentOffset; + +@property (nonatomic, assign) BOOL inverted; + /** * Tuning parameters for a range type in full mode. *