Improve measurement code for cell nodes (#3119)

This commit is contained in:
Michael Schneider
2017-03-03 09:24:04 -08:00
committed by GitHub
parent 93809bd4e7
commit 62d7e14ce1
7 changed files with 55 additions and 50 deletions

View File

@@ -125,47 +125,10 @@
}
}
- (void)transitionLayoutWithAnimation:(BOOL)animated
shouldMeasureAsync:(BOOL)shouldMeasureAsync
measurementCompletion:(void(^)())completion
{
CGSize oldSize = self.calculatedSize;
[super transitionLayoutWithAnimation:animated
shouldMeasureAsync:shouldMeasureAsync
measurementCompletion:^{
[self didRelayoutFromOldSize:oldSize toNewSize:self.calculatedSize];
if (completion) {
completion();
}
}
];
}
- (void)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize
animated:(BOOL)animated
shouldMeasureAsync:(BOOL)shouldMeasureAsync
measurementCompletion:(void(^)())completion
{
CGSize oldSize = self.calculatedSize;
[super transitionLayoutWithSizeRange:constrainedSize
animated:animated
shouldMeasureAsync:shouldMeasureAsync
measurementCompletion:^{
[self didRelayoutFromOldSize:oldSize toNewSize:self.calculatedSize];
if (completion) {
completion();
}
}
];
}
- (void)didRelayoutFromOldSize:(CGSize)oldSize toNewSize:(CGSize)newSize
- (void)_layoutTransitionMeasurementDidFinish
{
if (_interactionDelegate != nil) {
ASPerformBlockOnMainThread(^{
BOOL sizeChanged = !CGSizeEqualToSize(oldSize, newSize);
[_interactionDelegate nodeDidRelayout:self sizeChanged:sizeChanged];
});
[_interactionDelegate nodeDidInvalidateSize:self];
}
}

View File

@@ -32,6 +32,7 @@
#import <AsyncDisplayKit/ASSectionContext.h>
#import <AsyncDisplayKit/ASCollectionView+Undeprecated.h>
#import <AsyncDisplayKit/_ASHierarchyChangeSet.h>
#import <AsyncDisplayKit/CoreGraphics+ASConvenience.h>
/**
* A macro to get self.collectionNode and assign it to a local variable, or return
@@ -1563,6 +1564,15 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
}
}
- (BOOL)dataController:(ASDataController *)dataController presentedSizeForElement:(ASCollectionElement *)element matchesSize:(CGSize)size
{
NSIndexPath *indexPath = [self indexPathForNode:element.node];
UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexPath];
CGRect rect = attributes.frame;
return CGSizeEqualToSizeWithIn(rect.size, size, FLT_EPSILON);
}
- (id<ASTraitEnvironment>)dataControllerEnvironment
{
return self.collectionNode;

View File

@@ -1266,6 +1266,12 @@ ASLayoutElementFinalLayoutElementDefault
return _calculatedDisplayNodeLayout->constrainedSize;
}
/**
* @abstract Informs the root node that the intrinsic size of the receiver is no longer valid.
*
* @discussion The size of a root node is determined by each subnode. Calling invalidateSize will let the root node know
* that the intrinsic size of the receiver node is no longer valid and a resizing of the root node needs to happen.
*/
- (void)setNeedsLayoutFromAbove
{
ASDisplayNodeAssertThreadAffinity(self);
@@ -1487,6 +1493,8 @@ ASLayoutElementFinalLayoutElementDefault
});
// Measurement pass completion
// Give the subclass a change to hook into before calling the completion block
[self _layoutTransitionMeasurementDidFinish];
if (completion) {
completion();
}
@@ -1560,6 +1568,11 @@ ASLayoutElementFinalLayoutElementDefault
return _transitionID;
}
- (void)_layoutTransitionMeasurementDidFinish
{
// No-Op in ASDisplayNode
}
- (void)_finishOrCancelTransition
{
ASDN::MutexLocker l(__instanceLock__);

View File

@@ -1695,6 +1695,22 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
}
}
- (BOOL)dataController:(ASDataController *)dataController presentedSizeForElement:(ASCollectionElement *)element matchesSize:(CGSize)size
{
NSIndexPath *indexPath = [self indexPathForNode:element.node];
CGRect rect = [self rectForRowAtIndexPath:indexPath];
/**
* Weirdly enough, Apple expects the return value in tableView:heightForRowAtIndexPath: to _include_ the height
* of the separator, if there is one! So if rectForRow would return 44.0 we need to use 43.5.
*/
if (self.separatorStyle != UITableViewCellSeparatorStyleNone) {
rect.size.height -= 1.0 / ASScreenScale();
}
return (fabs(rect.size.height - size.height) < FLT_EPSILON);
}
#pragma mark - ASDataControllerEnvironmentDelegate
- (id<ASTraitEnvironment>)dataControllerEnvironment

View File

@@ -29,6 +29,7 @@ NS_ASSUME_NONNULL_BEGIN
@class ASCellNode;
@class ASDataController;
@class ASElementMap;
@class ASCollectionElement;
@class _ASHierarchyChangeSet;
@protocol ASTraitEnvironment;
@protocol ASSectionContext;
@@ -65,6 +66,11 @@ extern NSString * const ASCollectionInvalidUpdateException;
*/
- (NSUInteger)numberOfSectionsInDataController:(ASDataController *)dataController;
/**
Returns if the collection element size matches a given size
*/
- (BOOL)dataController:(ASDataController *)dataController presentedSizeForElement:(ASCollectionElement *)element matchesSize:(CGSize)size;
@optional
- (NSArray<NSString *> *)dataController:(ASDataController *)dataController supplementaryNodeKindsInSections:(NSIndexSet *)sections;

View File

@@ -640,10 +640,9 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCollectionElement *> *
NSString *kind = node.collectionElement.supplementaryElementKind ?: ASDataControllerRowNodeKind;
NSIndexPath *indexPath = [_pendingMap indexPathForElement:node.collectionElement];
ASSizeRange constrainedSize = [self constrainedSizeForNodeOfKind:kind atIndexPath:indexPath];
CGSize oldSize = node.bounds.size;
[self _layoutNode:node withConstrainedSize:constrainedSize];
if (! CGSizeEqualToSize(node.frame.size, oldSize)) {
BOOL matchesSize = [_dataSource dataController:self presentedSizeForElement:node.collectionElement matchesSize:node.frame.size];
if (! matchesSize) {
[nodesSizesChanged addObject:node];
}
}

View File

@@ -214,20 +214,18 @@ __unused static NSString * _Nonnull NSStringFromASHierarchyState(ASHierarchyStat
*/
- (BOOL)shouldScheduleDisplayWithNewInterfaceState:(ASInterfaceState)newInterfaceState;
/**
* @abstract Informs the root node that the intrinsic size of the receiver is no longer valid.
*
* @discussion The size of a root node is determined by each subnode. Calling invalidateSize will let the root node know
* that the intrinsic size of the receiver node is no longer valid and a resizing of the root node needs to happen.
*/
- (void)setNeedsLayoutFromAbove;
/**
* @abstract Subclass hook for nodes that are acting as root nodes. This method is called if one of the subnodes
* size is invalidated and may need to result in a different size as the current calculated size.
*/
- (void)_locked_rootNodeDidInvalidateSize;
/**
* @abstract Subclass hook for nodes that are acting as root nodes. This method is called after measurement
* finished in a layout transition but before the measurement completion handler is called
*/
- (void)_layoutTransitionMeasurementDidFinish;
@end
@interface UIView (ASDisplayNodeInternal)