Make ASCollectionView always create an ASCollectionNode. Add visibilityDidChange:, interfaceStateDidChange:fromState:

This commit is contained in:
Scott Goodson
2015-12-22 21:46:46 -08:00
parent d7492b331f
commit 065625f246
9 changed files with 180 additions and 169 deletions

View File

@@ -9,6 +9,10 @@
#import "ASCollectionNode.h"
#import "ASDisplayNode+Subclasses.h"
@interface ASCollectionView (Internal)
- (ASCollectionView *)_initWithCollectionViewLayout:(UICollectionViewLayout *)layout;
@end
@implementation ASCollectionNode
- (instancetype)init
@@ -20,7 +24,7 @@
- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout
{
if (self = [super initWithViewBlock:^UIView *{ return [[ASCollectionView alloc] initWithCollectionViewLayout:layout]; }]) {
if (self = [super initWithViewBlock:^UIView *{ return [[ASCollectionView alloc] _initWithCollectionViewLayout:layout]; }]) {
return self;
}
return nil;
@@ -31,6 +35,11 @@
return (ASCollectionView *)[super view];
}
- (void)visibilityDidChange:(BOOL)isVisible
{
}
- (void)clearContents
{
[super clearContents];

View File

@@ -12,7 +12,7 @@
#import <AsyncDisplayKit/ASCollectionViewProtocols.h>
#import <AsyncDisplayKit/ASBaseDefines.h>
#import <AsyncDisplayKit/ASBatchContext.h>
#import <AsyncDisplayKit/ASCollectionViewFlowLayoutInspector.h>
@class ASCellNode;
@protocol ASCollectionViewDataSource;
@@ -27,6 +27,11 @@
*/
@interface ASCollectionView : UICollectionView
/**
* Initializer.
*
* @param layout The layout object to use for organizing items. The collection view stores a strong reference to the specified object. Must not be nil.
*/
- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout;
@property (nonatomic, weak) id<ASCollectionViewDataSource> asyncDataSource;
@@ -52,27 +57,6 @@
*/
- (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeType:(ASLayoutRangeType)rangeType;
/**
* Initializer.
*
* @param frame The frame rectangle for the collection view, measured in points. The origin of the frame is relative to the superview
* in which you plan to add it. This frame is passed to the superclass during initialization.
*
* @param layout The layout object to use for organizing items. The collection view stores a strong reference to the specified object.
* Must not be nil.
*
* @param asyncDataFetchingEnabled Enable the data fetching in async mode.
*
* @discussion If asyncDataFetching is enabled, the `ASCollectionView` will fetch data through `collectionView:numberOfRowsInSection:` and
* `collectionView:nodeForRowAtIndexPath:` in async mode from background thread. Otherwise, the methods will be invoked synchronically
* from calling thread.
* Enabling asyncDataFetching could avoid blocking main thread for `ASCellNode` allocation, which is frequently reported issue for
* large scale data. On another hand, the application code need take the responsibility to avoid data inconsistence. Specifically,
* we will lock the data source through `collectionViewLockDataSource`, and unlock it by `collectionViewUnlockDataSource` after the data fetching.
* The application should not update the data source while the data source is locked, to keep data consistence.
*/
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout asyncDataFetching:(BOOL)asyncDataFetchingEnabled;
/**
* The number of screens left to scroll before the delegate -collectionView:beginBatchFetchingWithContext: is called.
*
@@ -429,4 +413,10 @@
*/
- (CGSize)collectionView:(ASCollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section;
@end
@end
@interface ASCollectionView (Deprecated)
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout asyncDataFetching:(BOOL)asyncDataFetchingEnabled ASDISPLAYNODE_DEPRECATED;
@end

View File

@@ -9,6 +9,7 @@
#import "ASAssert.h"
#import "ASBatchFetching.h"
#import "ASCollectionView.h"
#import "ASCollectionNode.h"
#import "ASCollectionDataController.h"
#import "ASCollectionViewLayoutController.h"
#import "ASCollectionViewFlowLayoutInspector.h"
@@ -31,7 +32,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
*/
static BOOL _isInterceptedSelector(SEL sel)
{
return (
return (
// handled by ASCollectionView node<->cell machinery
sel == @selector(collectionView:cellForItemAtIndexPath:) ||
sel == @selector(collectionView:layout:sizeForItemAtIndexPath:) ||
@@ -44,7 +45,7 @@ static BOOL _isInterceptedSelector(SEL sel)
// used for ASRangeController visibility updates
sel == @selector(collectionView:willDisplayCell:forItemAtIndexPath:) ||
sel == @selector(collectionView:didEndDisplayingCell:forItemAtIndexPath:) ||
// used for batch fetching API
sel == @selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)
);
@@ -70,7 +71,7 @@ static BOOL _isInterceptedSelector(SEL sel)
if (!self) {
return nil;
}
ASDisplayNodeAssert(target, @"target must not be nil");
ASDisplayNodeAssert(interceptor, @"interceptor must not be nil");
@@ -84,7 +85,7 @@ static BOOL _isInterceptedSelector(SEL sel)
{
ASDisplayNodeAssert(_target, @"target must not be nil"); // catch weak ref's being nilled early
ASDisplayNodeAssert(_interceptor, @"interceptor must not be nil");
return (_isInterceptedSelector(aSelector) || [_target respondsToSelector:aSelector]);
}
@@ -92,7 +93,7 @@ static BOOL _isInterceptedSelector(SEL sel)
{
ASDisplayNodeAssert(_target, @"target must not be nil"); // catch weak ref's being nilled early
ASDisplayNodeAssert(_interceptor, @"interceptor must not be nil");
if (_isInterceptedSelector(aSelector)) {
return _interceptor;
}
@@ -140,21 +141,21 @@ static BOOL _isInterceptedSelector(SEL sel)
@interface ASCollectionView () <ASRangeControllerDataSource, ASRangeControllerDelegate, ASDataControllerSource, ASCellNodeLayoutDelegate> {
_ASCollectionViewProxy *_proxyDataSource;
_ASCollectionViewProxy *_proxyDelegate;
ASCollectionDataController *_dataController;
ASRangeController *_rangeController;
ASCollectionViewLayoutController *_layoutController;
ASCollectionViewFlowLayoutInspector *_flowLayoutInspector;
BOOL _performingBatchUpdates;
NSMutableArray *_batchUpdateBlocks;
BOOL _asyncDataFetchingEnabled;
BOOL _asyncDelegateImplementsInsetSection;
BOOL _collectionViewLayoutImplementsInsetSection;
BOOL _asyncDataSourceImplementsConstrainedSizeForNode;
BOOL _queuedNodeSizeUpdate;
ASBatchContext *_batchContext;
CGSize _maxSizeForNodesConstrainedSize;
@@ -172,7 +173,7 @@ static BOOL _isInterceptedSelector(SEL sel)
* You will get an assertion failure saying `Invalid number of items in section 0.
* The number of items after the update (1) must be equal to the number of items before the update (1) plus or minus the items added and removed (1 added, 0 removed).`
* The collection view never queried your data source before the update to see that it actually had 0 items.
*/
*/
BOOL _superIsPendingDataLoad;
}
@@ -187,48 +188,53 @@ static BOOL _isInterceptedSelector(SEL sel)
- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout
{
return [self initWithFrame:CGRectZero collectionViewLayout:layout asyncDataFetching:NO];
return [self initWithFrame:CGRectZero collectionViewLayout:layout];
}
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout
{
return [self initWithFrame:frame collectionViewLayout:layout asyncDataFetching:NO];
// ASCollectionNode *collectionNode = [[ASCollectionNode alloc] initWithCollectionViewLayout:layout];
// collectionNode.frame = frame;
// return collectionNode.view;
return [self _initWithFrame:frame collectionViewLayout:layout];
}
// FIXME: This method is deprecated and will probably be removed in or shortly after 2.0.
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout asyncDataFetching:(BOOL)asyncDataFetchingEnabled
{
return [self initWithFrame:frame collectionViewLayout:layout];
}
- (instancetype)_initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout
{
if (!(self = [super initWithFrame:frame collectionViewLayout:layout]))
return nil;
// FIXME: asyncDataFetching is currently unreliable for some use cases.
// https://github.com/facebook/AsyncDisplayKit/issues/385
asyncDataFetchingEnabled = NO;
_layoutController = [[ASCollectionViewLayoutController alloc] initWithCollectionView:self];
_rangeController = [[ASRangeController alloc] init];
_rangeController.dataSource = self;
_rangeController.delegate = self;
_rangeController.layoutController = _layoutController;
_dataController = [[ASCollectionDataController alloc] initWithAsyncDataFetching:asyncDataFetchingEnabled];
_dataController = [[ASCollectionDataController alloc] initWithAsyncDataFetching:NO];
_dataController.delegate = _rangeController;
_dataController.dataSource = self;
_batchContext = [[ASBatchContext alloc] init];
_leadingScreensForBatching = 1.0;
_asyncDataFetchingEnabled = asyncDataFetchingEnabled;
_asyncDataFetchingEnabled = NO;
_asyncDataSourceLocked = NO;
_performingBatchUpdates = NO;
_batchUpdateBlocks = [NSMutableArray array];
_superIsPendingDataLoad = YES;
_collectionViewLayoutImplementsInsetSection = [layout respondsToSelector:@selector(sectionInset)];
_maxSizeForNodesConstrainedSize = self.bounds.size;
// If the initial size is 0, expect a size change very soon which is part of the initial configuration
// and should not trigger a relayout.
@@ -262,13 +268,13 @@ static BOOL _isInterceptedSelector(SEL sel)
*/
- (ASCollectionViewFlowLayoutInspector *)flowLayoutInspector
{
if (_flowLayoutInspector == nil) {
UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)self.collectionViewLayout;
ASDisplayNodeAssertNotNil(layout, @"Collection view layout must be a flow layout to use the built-in inspector");
_flowLayoutInspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:self
flowLayout:layout];
}
return _flowLayoutInspector;
if (_flowLayoutInspector == nil) {
UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)self.collectionViewLayout;
ASDisplayNodeAssertNotNil(layout, @"Collection view layout must be a flow layout to use the built-in inspector");
_flowLayoutInspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:self
flowLayout:layout];
}
return _flowLayoutInspector;
}
#pragma mark -
@@ -314,7 +320,7 @@ static BOOL _isInterceptedSelector(SEL sel)
// the (common) case of nilling the asyncDataSource in the ViewController's dealloc. In this case our _asyncDataSource
// will return as nil (ARC magic) even though the _proxyDataSource still exists. It's really important to nil out
// super.dataSource in this case because calls to _ASTableViewProxy will start failing and cause crashes.
if (asyncDataSource == nil) {
super.dataSource = nil;
_asyncDataSource = nil;
@@ -334,7 +340,7 @@ static BOOL _isInterceptedSelector(SEL sel)
// the (common) case of nilling the asyncDelegate in the ViewController's dealloc. In this case our _asyncDelegate
// will return as nil (ARC magic) even though the _proxyDelegate still exists. It's really important to nil out
// super.delegate in this case because calls to _ASTableViewProxy will start failing and cause crashes.
if (asyncDelegate == nil) {
// order is important here, the delegate must be callable while nilling super.delegate to avoid random crashes
// in UIScrollViewAccessibility.
@@ -348,7 +354,7 @@ static BOOL _isInterceptedSelector(SEL sel)
super.delegate = (id<UICollectionViewDelegate>)_proxyDelegate;
_asyncDelegateImplementsInsetSection = ([_asyncDelegate respondsToSelector:@selector(collectionView:layout:insetForSectionAtIndex:)] ? 1 : 0);
}
[_layoutInspector didChangeCollectionViewDelegate:asyncDelegate];
}
@@ -409,7 +415,7 @@ static BOOL _isInterceptedSelector(SEL sel)
- (void)performBatchAnimated:(BOOL)animated updates:(void (^)())updates completion:(void (^)(BOOL))completion
{
ASDisplayNodeAssertMainThread();
[_dataController beginUpdates];
updates();
[_dataController endUpdatesAnimated:animated completion:completion];
@@ -487,7 +493,7 @@ static BOOL _isInterceptedSelector(SEL sel)
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
_ASCollectionViewCell *cell = [self dequeueReusableCellWithReuseIdentifier:kCellReuseIdentifier forIndexPath:indexPath];
ASCellNode *node = [_dataController nodeAtIndexPath:indexPath];
cell.node = node;
[_rangeController configureContentView:cell.contentView forCellNode:node];
@@ -524,7 +530,7 @@ static BOOL _isInterceptedSelector(SEL sel)
CGPoint scrollVelocity = [self.panGestureRecognizer velocityInView:self.superview];
return [self scrollDirectionForVelocity:scrollVelocity];
}
- (ASScrollDirection)scrollDirectionForVelocity:(CGPoint)scrollVelocity
{
ASScrollDirection direction = ASScrollDirectionNone;
@@ -544,7 +550,7 @@ static BOOL _isInterceptedSelector(SEL sel)
direction |= ASScrollDirectionUp;
}
}
return direction;
}
@@ -623,7 +629,7 @@ static BOOL _isInterceptedSelector(SEL sel)
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
[self handleBatchFetchScrollingToOffset:*targetContentOffset];
if ([_asyncDelegate respondsToSelector:@selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)]) {
[_asyncDelegate scrollViewWillEndDragging:scrollView withVelocity:velocity targetContentOffset:targetContentOffset];
}
@@ -643,11 +649,11 @@ static BOOL _isInterceptedSelector(SEL sel)
- (void)handleBatchFetchScrollingToOffset:(CGPoint)targetOffset
{
ASDisplayNodeAssert(_batchContext != nil, @"Batch context should exist");
if (![self shouldBatchFetch]) {
return;
}
if (ASDisplayShouldFetchBatchForContext(_batchContext, [self scrollDirection], self.bounds, self.contentSize, targetOffset, _leadingScreensForBatching)) {
[_batchContext beginBatchFetching];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@@ -695,7 +701,7 @@ static BOOL _isInterceptedSelector(SEL sel)
}
constrainedSize = ASSizeRangeMake(CGSizeZero, maxSize);
}
UIEdgeInsets sectionInset = UIEdgeInsetsZero;
if (_collectionViewLayoutImplementsInsetSection) {
sectionInset = [(UICollectionViewFlowLayout *)self.collectionViewLayout sectionInset];
@@ -704,7 +710,7 @@ static BOOL _isInterceptedSelector(SEL sel)
if (_asyncDelegateImplementsInsetSection) {
sectionInset = [(id<ASCollectionViewDelegateFlowLayout>)_asyncDelegate collectionView:self layout:self.collectionViewLayout insetForSectionAtIndex:indexPath.section];
}
if (ASScrollDirectionContainsHorizontalDirection([self scrollableDirections])) {
constrainedSize.min.width = MAX(0, constrainedSize.min.width - sectionInset.left - sectionInset.right);
//ignore insets for FLT_MAX so FLT_MAX can be compared against
@@ -718,7 +724,7 @@ static BOOL _isInterceptedSelector(SEL sel)
constrainedSize.max.height = MAX(0, constrainedSize.max.height - sectionInset.top - sectionInset.bottom);
}
}
return constrainedSize;
}
@@ -738,7 +744,7 @@ static BOOL _isInterceptedSelector(SEL sel)
- (void)dataControllerLockDataSource
{
ASDisplayNodeAssert(!self.asyncDataSourceLocked, @"The data source has already been locked");
self.asyncDataSourceLocked = YES;
if ([_asyncDataSource respondsToSelector:@selector(collectionViewLockDataSource:)]) {
[_asyncDataSource collectionViewLockDataSource:self];
@@ -748,7 +754,7 @@ static BOOL _isInterceptedSelector(SEL sel)
- (void)dataControllerUnlockDataSource
{
ASDisplayNodeAssert(self.asyncDataSourceLocked, @"The data source has already been unlocked");
self.asyncDataSourceLocked = NO;
if ([_asyncDataSource respondsToSelector:@selector(collectionViewUnlockDataSource:)]) {
[_asyncDataSource collectionViewUnlockDataSource:self];
@@ -817,7 +823,7 @@ static BOOL _isInterceptedSelector(SEL sel)
- (void)rangeController:(ASRangeController *)rangeController didEndUpdatesAnimated:(BOOL)animated completion:(void (^)(BOOL))completion
{
ASDisplayNodeAssertMainThread();
if (!self.asyncDataSource || _superIsPendingDataLoad) {
if (completion) {
completion(NO);
@@ -832,7 +838,7 @@ static BOOL _isInterceptedSelector(SEL sel)
}
} completion:completion];
});
[_batchUpdateBlocks removeAllObjects];
_performingBatchUpdates = NO;
}
@@ -840,11 +846,11 @@ static BOOL _isInterceptedSelector(SEL sel)
- (void)rangeController:(ASRangeController *)rangeController didInsertNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
{
ASDisplayNodeAssertMainThread();
if (!self.asyncDataSource || _superIsPendingDataLoad) {
return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes
}
if (_performingBatchUpdates) {
[_batchUpdateBlocks addObject:^{
[super insertItemsAtIndexPaths:indexPaths];
@@ -859,11 +865,11 @@ static BOOL _isInterceptedSelector(SEL sel)
- (void)rangeController:(ASRangeController *)rangeController didDeleteNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
{
ASDisplayNodeAssertMainThread();
if (!self.asyncDataSource || _superIsPendingDataLoad) {
return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes
}
if (_performingBatchUpdates) {
[_batchUpdateBlocks addObject:^{
[super deleteItemsAtIndexPaths:indexPaths];
@@ -878,11 +884,11 @@ static BOOL _isInterceptedSelector(SEL sel)
- (void)rangeController:(ASRangeController *)rangeController didInsertSectionsAtIndexSet:(NSIndexSet *)indexSet withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
{
ASDisplayNodeAssertMainThread();
if (!self.asyncDataSource || _superIsPendingDataLoad) {
return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes
}
if (_performingBatchUpdates) {
[_batchUpdateBlocks addObject:^{
[super insertSections:indexSet];
@@ -897,11 +903,11 @@ static BOOL _isInterceptedSelector(SEL sel)
- (void)rangeController:(ASRangeController *)rangeController didDeleteSectionsAtIndexSet:(NSIndexSet *)indexSet withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
{
ASDisplayNodeAssertMainThread();
if (!self.asyncDataSource || _superIsPendingDataLoad) {
return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes
}
if (_performingBatchUpdates) {
[_batchUpdateBlocks addObject:^{
[super deleteSections:indexSet];
@@ -918,11 +924,11 @@ static BOOL _isInterceptedSelector(SEL sel)
- (void)nodeDidRelayout:(ASCellNode *)node sizeChanged:(BOOL)sizeChanged
{
ASDisplayNodeAssertMainThread();
if (!sizeChanged || _queuedNodeSizeUpdate) {
return;
}
_queuedNodeSizeUpdate = YES;
[self performSelector:@selector(requeryNodeSizes)
withObject:nil
@@ -934,7 +940,7 @@ static BOOL _isInterceptedSelector(SEL sel)
- (void)requeryNodeSizes
{
_queuedNodeSizeUpdate = NO;
[super performBatchUpdates:^{} completion:nil];
}
@@ -944,7 +950,7 @@ static BOOL _isInterceptedSelector(SEL sel)
{
for (NSArray *section in [_dataController completedNodes]) {
for (ASDisplayNode *node in section) {
[node recursivelyClearContents];
[node exitInterfaceState:ASInterfaceStateDisplay];
}
}
}
@@ -953,7 +959,7 @@ static BOOL _isInterceptedSelector(SEL sel)
{
for (NSArray *section in [_dataController completedNodes]) {
for (ASDisplayNode *node in section) {
[node recursivelyClearFetchedData];
[node exitInterfaceState:ASInterfaceStateFetchData];
}
}
}

View File

@@ -37,35 +37,8 @@
@interface ASDisplayNode (Subclassing)
/** @name View Configuration */
/**
* @return The view class to use when creating a new display node instance. Defaults to _ASDisplayView.
*/
+ (Class)viewClass;
/** @name Properties */
/**
* @abstract The scale factor to apply to the rendering.
*
* @discussion Use setNeedsDisplayAtScale: to set a value and then after display, the display node will set the layer's
* contentsScale. This is to prevent jumps when re-rasterizing at a different contentsScale.
* Read this property if you need to know the future contentsScale of your layer, eg in drawParameters.
*
* @see setNeedsDisplayAtScale:
*/
@property (nonatomic, assign, readonly) CGFloat contentsScaleForDisplay;
/**
* @abstract Whether the view or layer of this display node is currently in a window
*/
@property (nonatomic, readonly, assign, getter=isInHierarchy) BOOL inHierarchy;
/**
* @abstract Return the calculated layout.
*
@@ -190,10 +163,9 @@
*
* @note Called on the display queue and/or main queue (MUST BE THREAD SAFE)
*/
+ (void)drawRect:(CGRect)bounds
withParameters:(id<NSObject>)parameters
isCancelled:(asdisplaynode_iscancelled_block_t)isCancelledBlock
isRasterizing:(BOOL)isRasterizing;
+ (void)drawRect:(CGRect)bounds withParameters:(id<NSObject>)parameters
isCancelled:(asdisplaynode_iscancelled_block_t)isCancelledBlock
isRasterizing:(BOOL)isRasterizing;
/**
* @summary Delegate override to provide new layer contents as a UIImage.
@@ -236,6 +208,33 @@
*/
- (void)displayDidFinish ASDISPLAYNODE_REQUIRES_SUPER;
/** @name Observing node-related changes */
/**
* @abstract Called whenever any bit in the ASInterfaceState bitfield is changed.
*
* @discussion Subclasses may use this to monitor when they become visible, should free cached data, and much more.
* @see ASInterfaceState
*/
- (void)interfaceStateDidChange:(ASInterfaceState)newState fromState:(ASInterfaceState)oldState;
- (void)visibilityDidChange:(BOOL)isVisible;
/**
* Called just before the view is added to a window.
*/
- (void)willEnterHierarchy ASDISPLAYNODE_REQUIRES_SUPER;
/**
* Called after the view is removed from the window.
*/
- (void)didExitHierarchy ASDISPLAYNODE_REQUIRES_SUPER;
/**
* @abstract Whether the view or layer of this display node is currently in a window
*/
@property (nonatomic, readonly, assign, getter=isInHierarchy) BOOL inHierarchy;
/**
* @abstract Indicates that the node should fetch any external data, such as images.
*
@@ -245,6 +244,23 @@
*/
- (void)fetchData ASDISPLAYNODE_REQUIRES_SUPER;
/**
* Provides an opportunity to clear any fetched data (e.g. remote / network or database-queried) on the current node.
*
* @discussion This will not clear data recursively for all subnodes. Either call -recursivelyClearFetchedData or
* selectively clear fetched data.
*/
- (void)clearFetchedData ASDISPLAYNODE_REQUIRES_SUPER;
/**
* Provides an opportunity to clear backing store and other memory-intensive intermediates, such as text layout managers
* on the current node.
*
* @discussion Called by -recursivelyClearContents. Base class implements self.contents = nil, clearing any backing
* store, for asynchronous regeneration when needed.
*/
- (void)clearContents ASDISPLAYNODE_REQUIRES_SUPER;
/**
* @abstract Indicates that the receiver is about to display its subnodes. This method is not called if there are no
* subnodes present.
@@ -267,7 +283,6 @@
*/
- (void)subnodeDisplayDidFinish:(ASDisplayNode *)subnode ASDISPLAYNODE_REQUIRES_SUPER;
/**
* @abstract Marks the receiver's bounds as needing to be redrawn, with a scale value.
*
@@ -295,6 +310,17 @@
*/
- (void)recursivelySetNeedsDisplayAtScale:(CGFloat)contentsScale;
/**
* @abstract The scale factor to apply to the rendering.
*
* @discussion Use setNeedsDisplayAtScale: to set a value and then after display, the display node will set the layer's
* contentsScale. This is to prevent jumps when re-rasterizing at a different contentsScale.
* Read this property if you need to know the future contentsScale of your layer, eg in drawParameters.
*
* @see setNeedsDisplayAtScale:
*/
@property (nonatomic, assign, readonly) CGFloat contentsScaleForDisplay;
/** @name Touch handling */
@@ -361,38 +387,6 @@
*/
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
/** @name Observing node-related changes */
/**
* Called just before the view is added to a window.
*/
- (void)willEnterHierarchy ASDISPLAYNODE_REQUIRES_SUPER;
/**
* Called after the view is removed from the window.
*/
- (void)didExitHierarchy ASDISPLAYNODE_REQUIRES_SUPER;
/**
* Provides an opportunity to clear backing store and other memory-intensive intermediates, such as text layout managers
* on the current node.
*
* @discussion Called by -recursivelyClearContents. Base class implements self.contents = nil, clearing any backing
* store, for asynchronous regeneration when needed.
*/
- (void)clearContents ASDISPLAYNODE_REQUIRES_SUPER;
/**
* Provides an opportunity to clear any fetched data (e.g. remote / network or database-queried) on the current node.
*
* @discussion This will not clear data recursively for all subnodes. Either call -recursivelyClearFetchedData or
* selectively clear fetched data.
*/
- (void)clearFetchedData ASDISPLAYNODE_REQUIRES_SUPER;
/** @name Placeholders */
/**
@@ -412,6 +406,7 @@
*/
- (UIImage *)placeholderImage;
/** @name Description */
/**

View File

@@ -1722,6 +1722,10 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
[self clearFetchedData];
}
- (void)visibilityDidChange:(BOOL)isVisible
{
}
/**
* We currently only set interface state on nodes in table/collection views. For other nodes, if they are
* in the hierarchy we enable all ASInterfaceState types with `ASInterfaceStateInHierarchy`, otherwise `None`.
@@ -1776,11 +1780,17 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
// Entered or exited data loading state.
if ((newState & ASInterfaceStateVisible) != (oldState & ASInterfaceStateVisible)) {
if (newState & ASInterfaceStateVisible) {
// Consider providing a -didBecomeVisible.
[self visibilityDidChange:YES];
} else {
// Consider providing a -didBecomeInvisible.
[self visibilityDidChange:NO];
}
}
[self interfaceStateDidChange:newState fromState:oldState];
}
- (void)interfaceStateDidChange:(ASInterfaceState)newState fromState:(ASInterfaceState)oldState
{
}
- (void)enterInterfaceState:(ASInterfaceState)interfaceState

View File

@@ -11,14 +11,23 @@
@interface ASViewController : UIViewController
- (instancetype)initWithNode:(ASDisplayNode *)node NS_DESIGNATED_INITIALIZER;
@property (nonatomic, strong, readonly) ASDisplayNode *node;
/**
* @abstract Passthrough property to the the .interfaceState of the node.
* @return The current ASInterfaceState of the node, indicating whether it is visible and other situational properties.
* @see ASInterfaceState
*/
@property (nonatomic, readonly) ASInterfaceState interfaceState;
// AsyncDisplayKit 2.0 BETA: This property is still being tested, but it allows
// blocking as a view controller becomes visible to ensure no placeholders flash onscreen.
// Refer to examples/SynchronousConcurrency, AsyncViewController.m
@property (nonatomic, assign) BOOL neverShowPlaceholders;
- (instancetype)initWithNode:(ASDisplayNode *)node;
/**
* The constrained size used to measure the backing node.

View File

@@ -65,4 +65,9 @@
return ASSizeRangeMake(viewSize, viewSize);
}
- (ASInterfaceState)interfaceState
{
return _node.interfaceState;
}
@end

View File

@@ -57,6 +57,9 @@ typedef NS_OPTIONS(NSUInteger, ASHierarchyState)
ASHierarchyState _hierarchyState;
}
// The view class to use when creating a new display node instance. Defaults to _ASDisplayView.
+ (Class)viewClass;
// These methods are recursive, and either union or remove the provided interfaceState to all sub-elements.
- (void)enterInterfaceState:(ASInterfaceState)interfaceState;
- (void)exitInterfaceState:(ASInterfaceState)interfaceState;

View File

@@ -130,7 +130,6 @@
AC3C4A5B1A11F47200143C57 /* Frameworks */,
AC3C4A5C1A11F47200143C57 /* Resources */,
A6902C454C7661D0D277AC62 /* Copy Pods Resources */,
EC37EEC9933F5786936BFE7C /* Embed Pods Frameworks */,
);
buildRules = (
);
@@ -201,21 +200,6 @@
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n";
showEnvVarsInLog = 0;
};
EC37EEC9933F5786936BFE7C /* Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
F868CFBB21824CC9521B6588 /* Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;