mirror of
https://github.com/HackPlan/AsyncDisplayKit.git
synced 2026-05-23 07:22:36 +08:00
Merge branch 'master' of https://github.com/facebook/AsyncDisplayKit
This commit is contained in:
@@ -25,11 +25,11 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout;
|
||||
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout;
|
||||
|
||||
@property (strong, nonatomic, readonly) ASCollectionView *view;
|
||||
|
||||
@property (weak, nonatomic) id <ASCollectionDelegate> delegate;
|
||||
@property (weak, nonatomic) id <ASCollectionDataSource> dataSource;
|
||||
|
||||
@property (nonatomic, readonly) ASCollectionView *view;
|
||||
|
||||
/**
|
||||
* Tuning parameters for a range type in full mode.
|
||||
*
|
||||
|
||||
@@ -12,52 +12,76 @@
|
||||
|
||||
#import "ASCollectionNode.h"
|
||||
#import "ASCollectionInternal.h"
|
||||
#import "ASCollectionViewLayoutFacilitatorProtocol.h"
|
||||
#import "ASDisplayNode+Subclasses.h"
|
||||
#import "ASEnvironmentInternal.h"
|
||||
#import "ASInternalHelpers.h"
|
||||
#import "ASRangeControllerUpdateRangeProtocol+Beta.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#pragma mark - _ASCollectionPendingState
|
||||
|
||||
@interface _ASCollectionPendingState : NSObject
|
||||
@property (weak, nonatomic) id <ASCollectionDelegate> delegate;
|
||||
@property (weak, nonatomic) id <ASCollectionDataSource> dataSource;
|
||||
@property (assign, nonatomic) ASLayoutRangeMode rangeMode;
|
||||
@end
|
||||
|
||||
@implementation _ASCollectionPendingState
|
||||
@end
|
||||
|
||||
#if 0 // This is not used yet, but will provide a way to avoid creating the view to set range values.
|
||||
@implementation _ASCollectionPendingState
|
||||
- (instancetype)init
|
||||
{
|
||||
std::vector<ASRangeTuningParameters> _tuningParameters;
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_rangeMode = ASLayoutRangeModeCount;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
|
||||
// TODO: Add support for tuning parameters in the pending state
|
||||
#if 0 // This is not used yet, but will provide a way to avoid creating the view to set range values.
|
||||
@implementation _ASCollectionPendingState {
|
||||
std::vector<std::vector<ASRangeTuningParameters>> _tuningParameters;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if (!(self = [super init])) {
|
||||
return nil;
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_tuningParameters = std::vector<std::vector<ASRangeTuningParameters>> (ASLayoutRangeModeCount, std::vector<ASRangeTuningParameters> (ASLayoutRangeTypeCount));
|
||||
_rangeMode = ASLayoutRangeModeCount;
|
||||
}
|
||||
_tuningParameters = std::vector<ASRangeTuningParameters>(ASLayoutRangeTypeCount);
|
||||
return self;
|
||||
}
|
||||
|
||||
- (ASRangeTuningParameters)tuningParametersForRangeType:(ASLayoutRangeType)rangeType
|
||||
{
|
||||
ASDisplayNodeAssert(rangeType < _tuningParameters.size(), @"Requesting a range that is OOB for the configured tuning parameters");
|
||||
return _tuningParameters[rangeType];
|
||||
return [self tuningParametersForRangeMode:ASLayoutRangeModeFull rangeType:rangeType];
|
||||
}
|
||||
|
||||
- (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeType:(ASLayoutRangeType)rangeType
|
||||
{
|
||||
ASDisplayNodeAssert(rangeType < _tuningParameters.size(), @"Requesting a range that is OOB for the configured tuning parameters");
|
||||
ASDisplayNodeAssert(rangeType != ASLayoutRangeTypeVisible, @"Must not set Visible range tuning parameters (always 0, 0)");
|
||||
_tuningParameters[rangeType] = tuningParameters;
|
||||
return [self setTuningParameters:tuningParameters forRangeMode:ASLayoutRangeModeFull rangeType:rangeType];
|
||||
}
|
||||
|
||||
- (ASRangeTuningParameters)tuningParametersForRangeMode:(ASLayoutRangeMode)rangeMode rangeType:(ASLayoutRangeType)rangeType
|
||||
{
|
||||
ASDisplayNodeAssert(rangeMode < _tuningParameters.size() && rangeType < _tuningParameters[rangeMode].size(), @"Requesting a range that is OOB for the configured tuning parameters");
|
||||
return _tuningParameters[rangeMode][rangeType];
|
||||
}
|
||||
|
||||
- (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeMode:(ASLayoutRangeMode)rangeMode rangeType:(ASLayoutRangeType)rangeType
|
||||
{
|
||||
ASDisplayNodeAssert(rangeMode < _tuningParameters.size() && rangeType < _tuningParameters[rangeMode].size(), @"Setting a range that is OOB for the configured tuning parameters");
|
||||
_tuningParameters[rangeMode][rangeType] = tuningParameters;
|
||||
}
|
||||
|
||||
@end
|
||||
#endif
|
||||
|
||||
#pragma mark - ASCollectionNode
|
||||
|
||||
@interface ASCollectionNode ()
|
||||
{
|
||||
ASDN::RecursiveMutex _environmentStateLock;
|
||||
@@ -67,6 +91,8 @@
|
||||
|
||||
@implementation ASCollectionNode
|
||||
|
||||
#pragma mark Lifecycle
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
ASDISPLAYNODE_NOT_DESIGNATED_INITIALIZER();
|
||||
@@ -109,6 +135,8 @@
|
||||
return nil;
|
||||
}
|
||||
|
||||
#pragma mark ASDisplayNode
|
||||
|
||||
- (void)didLoad
|
||||
{
|
||||
[super didLoad];
|
||||
@@ -121,9 +149,39 @@
|
||||
self.pendingState = nil;
|
||||
view.asyncDelegate = pendingState.delegate;
|
||||
view.asyncDataSource = pendingState.dataSource;
|
||||
if (pendingState.rangeMode != ASLayoutRangeModeCount) {
|
||||
[view.rangeController updateCurrentRangeWithMode:pendingState.rangeMode];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (ASCollectionView *)view
|
||||
{
|
||||
return (ASCollectionView *)[super view];
|
||||
}
|
||||
|
||||
- (void)clearContents
|
||||
{
|
||||
[super clearContents];
|
||||
[self.view clearContents];
|
||||
}
|
||||
|
||||
- (void)clearFetchedData
|
||||
{
|
||||
[super clearFetchedData];
|
||||
[self.view clearFetchedData];
|
||||
}
|
||||
|
||||
#if ASRangeControllerLoggingEnabled
|
||||
- (void)visibleStateDidChange:(BOOL)isVisible
|
||||
{
|
||||
[super visibleStateDidChange:isVisible];
|
||||
NSLog(@"%@ - visible: %d", self, isVisible);
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma mark Setter / Getter
|
||||
|
||||
- (_ASCollectionPendingState *)pendingState
|
||||
{
|
||||
if (!_pendingState && ![self isNodeLoaded]) {
|
||||
@@ -171,47 +229,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (ASCollectionView *)view
|
||||
{
|
||||
return (ASCollectionView *)[super view];
|
||||
}
|
||||
|
||||
#if ASRangeControllerLoggingEnabled
|
||||
- (void)visibleStateDidChange:(BOOL)isVisible
|
||||
{
|
||||
[super visibleStateDidChange:isVisible];
|
||||
NSLog(@"%@ - visible: %d", self, isVisible);
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void)clearContents
|
||||
{
|
||||
[super clearContents];
|
||||
[self.view clearContents];
|
||||
}
|
||||
|
||||
- (void)clearFetchedData
|
||||
{
|
||||
[super clearFetchedData];
|
||||
[self.view clearFetchedData];
|
||||
}
|
||||
|
||||
- (void)beginUpdates
|
||||
{
|
||||
[self.view.dataController beginUpdates];
|
||||
}
|
||||
|
||||
- (void)endUpdatesAnimated:(BOOL)animated
|
||||
{
|
||||
[self endUpdatesAnimated:animated completion:nil];
|
||||
}
|
||||
|
||||
- (void)endUpdatesAnimated:(BOOL)animated completion:(void (^)(BOOL))completion
|
||||
{
|
||||
[self.view.dataController endUpdatesAnimated:animated completion:completion];
|
||||
}
|
||||
|
||||
#pragma mark - ASCollectionView Forwards
|
||||
#pragma mark ASCollectionView Forwards
|
||||
|
||||
- (ASRangeTuningParameters)tuningParametersForRangeType:(ASLayoutRangeType)rangeType
|
||||
{
|
||||
@@ -233,11 +251,6 @@
|
||||
return [self.view.rangeController setTuningParameters:tuningParameters forRangeMode:rangeMode rangeType:rangeType];
|
||||
}
|
||||
|
||||
- (void)updateCurrentRangeWithMode:(ASLayoutRangeMode)rangeMode;
|
||||
{
|
||||
[self.view.rangeController updateCurrentRangeWithMode:rangeMode];
|
||||
}
|
||||
|
||||
- (void)reloadDataWithCompletion:(void (^)())completion
|
||||
{
|
||||
[self.view reloadDataWithCompletion:completion];
|
||||
@@ -253,6 +266,34 @@
|
||||
[self.view reloadDataImmediately];
|
||||
}
|
||||
|
||||
- (void)beginUpdates
|
||||
{
|
||||
[self.view.dataController beginUpdates];
|
||||
}
|
||||
|
||||
- (void)endUpdatesAnimated:(BOOL)animated
|
||||
{
|
||||
[self endUpdatesAnimated:animated completion:nil];
|
||||
}
|
||||
|
||||
- (void)endUpdatesAnimated:(BOOL)animated completion:(void (^)(BOOL))completion
|
||||
{
|
||||
[self.view.dataController endUpdatesAnimated:animated completion:completion];
|
||||
}
|
||||
|
||||
#pragma mark - ASRangeControllerUpdateRangeProtocol
|
||||
|
||||
- (void)updateCurrentRangeWithMode:(ASLayoutRangeMode)rangeMode;
|
||||
{
|
||||
if ([self pendingState]) {
|
||||
_pendingState.rangeMode = rangeMode;
|
||||
} else {
|
||||
[self.view.rangeController updateCurrentRangeWithMode:rangeMode];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark ASEnvironment
|
||||
|
||||
ASEnvironmentCollectionTableSetEnvironmentState(_environmentStateLock)
|
||||
|
||||
@end
|
||||
|
||||
@@ -107,6 +107,15 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
||||
|
||||
ASCollectionViewInvalidationStyle _nextLayoutInvalidationStyle;
|
||||
|
||||
/**
|
||||
* Our layer, retained. Under iOS < 9, when collection views are removed from the hierarchy,
|
||||
* their layers may be deallocated and become dangling pointers. This puts the collection view
|
||||
* into a very dangerous state where pretty much any call will crash it. So we manually retain our layer.
|
||||
*
|
||||
* You should never access this, and it will be nil under iOS >= 9.
|
||||
*/
|
||||
CALayer *_retainedLayer;
|
||||
|
||||
/**
|
||||
* If YES, the `UICollectionView` will reload its data on next layout pass so we should not forward any updates to it.
|
||||
|
||||
@@ -248,6 +257,10 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
||||
|
||||
[self registerClass:[_ASCollectionViewCell class] forCellWithReuseIdentifier:kCellReuseIdentifier];
|
||||
|
||||
if (!AS_AT_LEAST_IOS9) {
|
||||
_retainedLayer = self.layer;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
@@ -245,9 +245,9 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
||||
dispatch_once(&onceToken, ^{
|
||||
renderQueue = [[ASRunLoopQueue<ASDisplayNode *> alloc] initWithRunLoop:CFRunLoopGetMain()
|
||||
andHandler:^(ASDisplayNode * _Nonnull dequeuedItem, BOOL isQueueDrained) {
|
||||
CFAbsoluteTime timestamp = isQueueDrained ? CFAbsoluteTimeGetCurrent() : 0;
|
||||
[dequeuedItem _recursivelyTriggerDisplayAndBlock:NO];
|
||||
if (isQueueDrained) {
|
||||
CFAbsoluteTime timestamp = CFAbsoluteTimeGetCurrent();
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ASRenderingEngineDidDisplayScheduledNodesNotification
|
||||
object:nil
|
||||
userInfo:@{ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp: @(timestamp)}];
|
||||
@@ -2317,27 +2317,27 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
|
||||
});
|
||||
}
|
||||
|
||||
- (void)recursivelySetInterfaceState:(ASInterfaceState)interfaceState
|
||||
- (void)recursivelySetInterfaceState:(ASInterfaceState)newInterfaceState
|
||||
{
|
||||
ASInterfaceState oldState = self.interfaceState;
|
||||
ASInterfaceState newState = interfaceState;
|
||||
// Instead of each node in the recursion assuming it needs to schedule itself for display,
|
||||
// setInterfaceState: skips this when handling range-managed nodes (our whole subtree has this set).
|
||||
// If our range manager intends for us to be displayed right now, and didn't before, get started!
|
||||
BOOL shouldScheduleDisplay = [self supportsRangeManagedInterfaceState] && [self shouldScheduleDisplayWithNewInterfaceState:newInterfaceState];
|
||||
ASDisplayNodePerformBlockOnEveryNode(nil, self, ^(ASDisplayNode *node) {
|
||||
node.interfaceState = interfaceState;
|
||||
node.interfaceState = newInterfaceState;
|
||||
});
|
||||
|
||||
if ([self supportsRangeManagedInterfaceState]) {
|
||||
// Instead of each node in the recursion assuming it needs to schedule itself for display,
|
||||
// setInterfaceState: skips this when handling range-managed nodes (our whole subtree has this set).
|
||||
// If our range manager intends for us to be displayed right now, and didn't before, get started!
|
||||
|
||||
BOOL nowDisplay = ASInterfaceStateIncludesDisplay(newState);
|
||||
BOOL wasDisplay = ASInterfaceStateIncludesDisplay(oldState);
|
||||
if (nowDisplay && (nowDisplay != wasDisplay)) {
|
||||
[ASDisplayNode scheduleNodeForRecursiveDisplay:self];
|
||||
}
|
||||
if (shouldScheduleDisplay) {
|
||||
[ASDisplayNode scheduleNodeForRecursiveDisplay:self];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)shouldScheduleDisplayWithNewInterfaceState:(ASInterfaceState)newInterfaceState
|
||||
{
|
||||
BOOL willDisplay = ASInterfaceStateIncludesDisplay(newInterfaceState);
|
||||
BOOL nowDisplay = ASInterfaceStateIncludesDisplay(self.interfaceState);
|
||||
return willDisplay && (willDisplay != nowDisplay);
|
||||
}
|
||||
|
||||
- (ASHierarchyState)hierarchyState
|
||||
{
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
- (instancetype)init; // UITableViewStylePlain
|
||||
- (instancetype)initWithStyle:(UITableViewStyle)style;
|
||||
|
||||
@property (nonatomic, readonly) ASTableView *view;
|
||||
@property (strong, nonatomic, readonly) ASTableView *view;
|
||||
|
||||
// These properties can be set without triggering the view to be created, so it's fine to set them in -init.
|
||||
@property (weak, nonatomic) id <ASTableDelegate> delegate;
|
||||
|
||||
@@ -10,21 +10,35 @@
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
|
||||
#import "ASTableNode.h"
|
||||
#import "ASTableViewInternal.h"
|
||||
#import "ASEnvironmentInternal.h"
|
||||
#import "ASDisplayNode+Subclasses.h"
|
||||
#import "ASFlowLayoutController.h"
|
||||
#import "ASInternalHelpers.h"
|
||||
#import "ASRangeControllerUpdateRangeProtocol+Beta.h"
|
||||
#import "ASTableViewInternal.h"
|
||||
|
||||
#pragma mark - _ASTablePendingState
|
||||
|
||||
@interface _ASTablePendingState : NSObject
|
||||
@property (weak, nonatomic) id <ASTableDelegate> delegate;
|
||||
@property (weak, nonatomic) id <ASTableDataSource> dataSource;
|
||||
@property (assign, nonatomic) ASLayoutRangeMode rangeMode;
|
||||
@end
|
||||
|
||||
@implementation _ASTablePendingState
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_rangeMode = ASLayoutRangeModeCount;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - ASTableView
|
||||
|
||||
@interface ASTableNode ()
|
||||
{
|
||||
ASDN::RecursiveMutex _environmentStateLock;
|
||||
@@ -39,6 +53,8 @@
|
||||
|
||||
@implementation ASTableNode
|
||||
|
||||
#pragma mark Lifecycle
|
||||
|
||||
- (instancetype)_initWithTableView:(ASTableView *)tableView
|
||||
{
|
||||
// Avoid a retain cycle. In this case, the ASTableView is creating us, and strongly retains us.
|
||||
@@ -72,6 +88,8 @@
|
||||
return [self _initWithFrame:CGRectZero style:UITableViewStylePlain dataControllerClass:nil];
|
||||
}
|
||||
|
||||
#pragma mark ASDisplayNode
|
||||
|
||||
- (void)didLoad
|
||||
{
|
||||
[super didLoad];
|
||||
@@ -84,22 +102,43 @@
|
||||
self.pendingState = nil;
|
||||
view.asyncDelegate = pendingState.delegate;
|
||||
view.asyncDataSource = pendingState.dataSource;
|
||||
if (pendingState.rangeMode != ASLayoutRangeModeCount) {
|
||||
[view.rangeController updateCurrentRangeWithMode:pendingState.rangeMode];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateCurrentRangeWithMode:(ASLayoutRangeMode)rangeMode
|
||||
- (ASTableView *)view
|
||||
{
|
||||
if (!self.isNodeLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self.view.rangeController updateCurrentRangeWithMode:rangeMode];
|
||||
return (ASTableView *)[super view];
|
||||
}
|
||||
|
||||
- (void)clearContents
|
||||
{
|
||||
[super clearContents];
|
||||
[self.view clearContents];
|
||||
}
|
||||
|
||||
- (void)clearFetchedData
|
||||
{
|
||||
[super clearFetchedData];
|
||||
[self.view clearFetchedData];
|
||||
}
|
||||
|
||||
#if ASRangeControllerLoggingEnabled
|
||||
- (void)visibleStateDidChange:(BOOL)isVisible
|
||||
{
|
||||
[super visibleStateDidChange:isVisible];
|
||||
NSLog(@"%@ - visible: %d", self, isVisible);
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma mark Setter / Getter
|
||||
|
||||
- (_ASTablePendingState *)pendingState
|
||||
{
|
||||
if (!_pendingState && ![self isNodeLoaded]) {
|
||||
self.pendingState = [[_ASTablePendingState alloc] init];
|
||||
_pendingState = [[_ASTablePendingState alloc] init];
|
||||
}
|
||||
ASDisplayNodeAssert(![self isNodeLoaded] || !_pendingState, @"ASTableNode should not have a pendingState once it is loaded");
|
||||
return _pendingState;
|
||||
@@ -143,30 +182,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (ASTableView *)view
|
||||
#pragma mark ASRangeControllerUpdateRangeProtocol
|
||||
|
||||
- (void)updateCurrentRangeWithMode:(ASLayoutRangeMode)rangeMode
|
||||
{
|
||||
return (ASTableView *)[super view];
|
||||
if ([self pendingState]) {
|
||||
_pendingState.rangeMode = rangeMode;
|
||||
} else {
|
||||
ASDisplayNodeAssert([self isNodeLoaded], @"ASTableNode should be loaded if pendingState doesn't exist");
|
||||
[self.view.rangeController updateCurrentRangeWithMode:rangeMode];
|
||||
}
|
||||
}
|
||||
|
||||
#if ASRangeControllerLoggingEnabled
|
||||
- (void)visibleStateDidChange:(BOOL)isVisible
|
||||
{
|
||||
[super visibleStateDidChange:isVisible];
|
||||
NSLog(@"%@ - visible: %d", self, isVisible);
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void)clearContents
|
||||
{
|
||||
[super clearContents];
|
||||
[self.view clearContents];
|
||||
}
|
||||
|
||||
- (void)clearFetchedData
|
||||
{
|
||||
[super clearFetchedData];
|
||||
[self.view clearFetchedData];
|
||||
}
|
||||
#pragma mark ASEnvironment
|
||||
|
||||
ASEnvironmentCollectionTableSetEnvironmentState(_environmentStateLock)
|
||||
|
||||
|
||||
@@ -27,18 +27,6 @@ typedef ASTraitCollection * _Nonnull (^ASDisplayTraitsForTraitWindowSizeBlock)(C
|
||||
|
||||
@property (nonatomic, strong, readonly) DisplayNodeType node;
|
||||
|
||||
/**
|
||||
* An optional context to pass along with an ASTraitCollection.
|
||||
* This can be used to pass any internal state to all subnodes via the ASTraitCollection that is not
|
||||
* included in UITraitCollection. This could range from more fine-tuned size classes to a class of
|
||||
* constants that is based upon the new trait collection.
|
||||
*
|
||||
* Be aware that internally this context is held by a C struct which cannot retain the pointer. Therefore
|
||||
* ASVC keeps a strong reference to the context to make sure that it stays alive. If you change this value
|
||||
* it will propagate the change to the subnodes.
|
||||
*/
|
||||
@property (nonatomic, strong) id _Nullable traitCollectionContext;
|
||||
|
||||
/**
|
||||
* Set this block to customize the ASDisplayTraits returned when the VC transitions to the given traitCollection.
|
||||
*/
|
||||
|
||||
@@ -58,17 +58,6 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (_traitCollectionContext != nil) {
|
||||
// The setter will iterate through the VC's subnodes and replace the traitCollectionContext in their ASEnvironmentTraitCollection with nil.
|
||||
// Since the VC holds the only strong reference to this context and we are in the process of destroying
|
||||
// the VC, all the references in the subnodes will be unsafe unless we nil them out. More than likely all the subnodes will be dealloc'ed
|
||||
// as part of the VC being dealloc'ed, but this is just to make extra sure.
|
||||
self.traitCollectionContext = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)loadView
|
||||
{
|
||||
ASDisplayNodeAssertTrue(!_node.layerBacked);
|
||||
@@ -199,27 +188,16 @@ ASVisibilityDepthImplementation;
|
||||
|
||||
#pragma mark - ASEnvironmentTraitCollection
|
||||
|
||||
- (void)setTraitCollectionContext:(id)traitCollectionContext
|
||||
{
|
||||
if (_traitCollectionContext != traitCollectionContext) {
|
||||
// nil out the displayContext in the subnodes so they aren't hanging around with a dealloc'ed pointer don't set
|
||||
// the new context yet as this will cause ASEnvironmentTraitCollectionIsEqualToASEnvironmentTraitCollection to fail
|
||||
ASEnvironmentTraitCollectionUpdateDisplayContext(self.node, nil);
|
||||
|
||||
_traitCollectionContext = traitCollectionContext;
|
||||
}
|
||||
}
|
||||
|
||||
- (ASEnvironmentTraitCollection)environmentTraitCollectionForUITraitCollection:(UITraitCollection *)traitCollection
|
||||
{
|
||||
if (self.overrideDisplayTraitsWithTraitCollection) {
|
||||
ASTraitCollection *asyncTraitCollection = self.overrideDisplayTraitsWithTraitCollection(traitCollection);
|
||||
self.traitCollectionContext = asyncTraitCollection.traitCollectionContext;
|
||||
return [asyncTraitCollection environmentTraitCollection];
|
||||
}
|
||||
|
||||
ASDisplayNodeAssertMainThread();
|
||||
ASEnvironmentTraitCollection asyncTraitCollection = ASEnvironmentTraitCollectionFromUITraitCollection(traitCollection);
|
||||
asyncTraitCollection.displayContext = self.traitCollectionContext;
|
||||
asyncTraitCollection.containerSize = self.view.frame.size;
|
||||
return asyncTraitCollection;
|
||||
}
|
||||
|
||||
@@ -227,9 +205,9 @@ ASVisibilityDepthImplementation;
|
||||
{
|
||||
if (self.overrideDisplayTraitsWithWindowSize) {
|
||||
ASTraitCollection *traitCollection = self.overrideDisplayTraitsWithWindowSize(windowSize);
|
||||
self.traitCollectionContext = traitCollection.traitCollectionContext;
|
||||
return [traitCollection environmentTraitCollection];
|
||||
}
|
||||
self.node.environmentTraitCollection.containerSize = windowSize;
|
||||
return self.node.environmentTraitCollection;
|
||||
}
|
||||
|
||||
@@ -255,17 +233,13 @@ ASVisibilityDepthImplementation;
|
||||
[super traitCollectionDidChange:previousTraitCollection];
|
||||
|
||||
ASEnvironmentTraitCollection environmentTraitCollection = [self environmentTraitCollectionForUITraitCollection:self.traitCollection];
|
||||
environmentTraitCollection.containerSize = self.view.bounds.size;
|
||||
[self progagateNewEnvironmentTraitCollection:environmentTraitCollection];
|
||||
}
|
||||
|
||||
- (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
|
||||
{
|
||||
[super willTransitionToTraitCollection:newCollection withTransitionCoordinator:coordinator];
|
||||
|
||||
ASEnvironmentTraitCollection environmentTraitCollection = [self environmentTraitCollectionForUITraitCollection:newCollection];
|
||||
[self progagateNewEnvironmentTraitCollection:environmentTraitCollection];
|
||||
}
|
||||
|
||||
// Note: We don't override willTransitionToTraitCollection:withTransitionCoordinator: because viewWillTransitionToSize:withTransitionCoordinator: will also called
|
||||
// called in all these cases. However, there are cases where viewWillTransitionToSize:withTransitionCoordinator: but willTransitionToTraitCollection:withTransitionCoordinator:
|
||||
// is not.
|
||||
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
|
||||
{
|
||||
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
|
||||
|
||||
@@ -91,15 +91,13 @@ extern BOOL ASRangeTuningParametersEqualToRangeTuningParameters(ASRangeTuningPar
|
||||
|
||||
- (ASRangeTuningParameters)tuningParametersForRangeMode:(ASLayoutRangeMode)rangeMode rangeType:(ASLayoutRangeType)rangeType
|
||||
{
|
||||
ASDisplayNodeAssert(rangeMode < _tuningParameters.size() && rangeType < _tuningParameters[rangeMode].size(),
|
||||
@"Requesting a range that is OOB for the configured tuning parameters");
|
||||
ASDisplayNodeAssert(rangeMode < _tuningParameters.size() && rangeType < _tuningParameters[rangeMode].size(), @"Requesting a range that is OOB for the configured tuning parameters");
|
||||
return _tuningParameters[rangeMode][rangeType];
|
||||
}
|
||||
|
||||
- (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeMode:(ASLayoutRangeMode)rangeMode rangeType:(ASLayoutRangeType)rangeType
|
||||
{
|
||||
ASDisplayNodeAssert(rangeMode < _tuningParameters.size() && rangeType < _tuningParameters[rangeMode].size(),
|
||||
@"Setting a range that is OOB for the configured tuning parameters");
|
||||
ASDisplayNodeAssert(rangeMode < _tuningParameters.size() && rangeType < _tuningParameters[rangeMode].size(), @"Setting a range that is OOB for the configured tuning parameters");
|
||||
_tuningParameters[rangeMode][rangeType] = tuningParameters;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
|
||||
- (void)beginUpdates
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
// NOTE: This assertion is failing in some apps and will be enabled soon.
|
||||
// ASDisplayNodeAssertMainThread();
|
||||
if (_changeSetBatchUpdateCounter <= 0) {
|
||||
_changeSet = [_ASHierarchyChangeSet new];
|
||||
_changeSetBatchUpdateCounter = 0;
|
||||
@@ -37,11 +38,13 @@
|
||||
|
||||
- (void)endUpdatesAnimated:(BOOL)animated completion:(void (^)(BOOL))completion
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
// NOTE: This assertion is failing in some apps and will be enabled soon.
|
||||
// ASDisplayNodeAssertMainThread();
|
||||
_changeSetBatchUpdateCounter--;
|
||||
|
||||
// Prevent calling endUpdatesAnimated:completion: in an unbalanced way
|
||||
NSAssert(_changeSetBatchUpdateCounter >= 0, @"endUpdatesAnimated:completion: called without having a balanced beginUpdates call");
|
||||
// NOTE: This assertion is failing in some apps and will be enabled soon.
|
||||
// NSAssert(_changeSetBatchUpdateCounter >= 0, @"endUpdatesAnimated:completion: called without having a balanced beginUpdates call");
|
||||
|
||||
if (_changeSetBatchUpdateCounter == 0) {
|
||||
[_changeSet markCompleted];
|
||||
|
||||
@@ -69,25 +69,9 @@ typedef struct ASEnvironmentTraitCollection {
|
||||
UIUserInterfaceIdiom userInterfaceIdiom;
|
||||
UIUserInterfaceSizeClass verticalSizeClass;
|
||||
UIForceTouchCapability forceTouchCapability;
|
||||
|
||||
// WARNING:
|
||||
// This pointer is in a C struct and therefore not managed by ARC. It is
|
||||
// an unsafe unretained pointer, so when you dereference it you better be
|
||||
// sure that it is valid.
|
||||
//
|
||||
// Use displayContext when you wish to pass view context specific data along with the
|
||||
// display traits to subnodes. This should be a piece of data owned by an
|
||||
// ASViewController, which will ensure that the data is still valid when laying out
|
||||
// its subviews. When the VC is dealloc'ed, the displayContext it created will also
|
||||
// be dealloced but any subnodes that are hanging around (why would they be?) will now
|
||||
// have a displayContext that points to a bad pointer.
|
||||
//
|
||||
// As an added precaution ASDisplayTraitsClearDisplayContext is called from ASVC's desctructor
|
||||
// which will propagate a nil displayContext to its subnodes.
|
||||
id __unsafe_unretained displayContext;
|
||||
} ASEnvironmentTraitCollection;
|
||||
|
||||
extern void ASEnvironmentTraitCollectionUpdateDisplayContext(id<ASEnvironment> rootEnvironment, id _Nullable context);
|
||||
CGSize containerSize;
|
||||
} ASEnvironmentTraitCollection;
|
||||
|
||||
extern ASEnvironmentTraitCollection ASEnvironmentTraitCollectionFromUITraitCollection(UITraitCollection *traitCollection);
|
||||
extern BOOL ASEnvironmentTraitCollectionIsEqualToASEnvironmentTraitCollection(ASEnvironmentTraitCollection lhs, ASEnvironmentTraitCollection rhs);
|
||||
@@ -165,14 +149,11 @@ ASDISPLAYNODE_EXTERN_C_END
|
||||
if (ASEnvironmentTraitCollectionIsEqualToASEnvironmentTraitCollection(currentTraits, oldTraits) == NO) {\
|
||||
/* Must dispatch to main for self.view && [self.view.dataController completedNodes]*/ \
|
||||
ASPerformBlockOnMainThread(^{\
|
||||
BOOL needsLayout = (oldTraits.displayContext == currentTraits.displayContext) || currentTraits.displayContext != nil;\
|
||||
NSArray<NSArray <ASCellNode *> *> *completedNodes = [self.view.dataController completedNodes];\
|
||||
for (NSArray *sectionArray in completedNodes) {\
|
||||
for (ASCellNode *cellNode in sectionArray) {\
|
||||
ASEnvironmentStatePropagateDown(cellNode, currentTraits);\
|
||||
if (needsLayout) {\
|
||||
[cellNode setNeedsLayout];\
|
||||
}\
|
||||
[cellNode setNeedsLayout];\
|
||||
}\
|
||||
}\
|
||||
});\
|
||||
|
||||
@@ -26,23 +26,11 @@ ASEnvironmentHierarchyState _ASEnvironmentHierarchyStateMakeDefault()
|
||||
};
|
||||
}
|
||||
|
||||
extern void ASEnvironmentTraitCollectionUpdateDisplayContext(id<ASEnvironment> rootEnvironment, id context)
|
||||
{
|
||||
ASEnvironmentState envState = [rootEnvironment environmentState];
|
||||
ASEnvironmentTraitCollection environmentTraitCollection = envState.environmentTraitCollection;
|
||||
environmentTraitCollection.displayContext = context;
|
||||
envState.environmentTraitCollection = environmentTraitCollection;
|
||||
[rootEnvironment setEnvironmentState:envState];
|
||||
|
||||
for (id<ASEnvironment> child in [rootEnvironment children]) {
|
||||
ASEnvironmentStatePropagateDown(child, environmentTraitCollection);
|
||||
}
|
||||
}
|
||||
|
||||
ASEnvironmentTraitCollection _ASEnvironmentTraitCollectionMakeDefault()
|
||||
{
|
||||
return (ASEnvironmentTraitCollection) {
|
||||
// Default values can be defined in here
|
||||
.containerSize = CGSizeZero,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -69,7 +57,7 @@ BOOL ASEnvironmentTraitCollectionIsEqualToASEnvironmentTraitCollection(ASEnviron
|
||||
lhs.displayScale == rhs.displayScale &&
|
||||
lhs.userInterfaceIdiom == rhs.userInterfaceIdiom &&
|
||||
lhs.forceTouchCapability == rhs.forceTouchCapability &&
|
||||
lhs.displayContext == rhs.displayContext;
|
||||
CGSizeEqualToSize(lhs.containerSize, rhs.containerSize);
|
||||
}
|
||||
|
||||
ASEnvironmentState ASEnvironmentStateMakeDefault()
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
NSSet<NSIndexPath *> *_allPreviousIndexPaths;
|
||||
ASLayoutRangeMode _currentRangeMode;
|
||||
BOOL _didUpdateCurrentRange;
|
||||
BOOL _didRegisterForNotifications;
|
||||
BOOL _didRegisterForNodeDisplayNotifications;
|
||||
CFAbsoluteTime _pendingDisplayNodesTimestamp;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (_didRegisterForNotifications) {
|
||||
if (_didRegisterForNodeDisplayNotifications) {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:ASRenderingEngineDidDisplayScheduledNodesNotification object:nil];
|
||||
}
|
||||
}
|
||||
@@ -242,10 +242,6 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive;
|
||||
[allIndexPaths addObjectsFromArray:ASIndexPathsForTwoDimensionalArray(allNodes)];
|
||||
}
|
||||
|
||||
// TODO Don't register for notifications if this range update doesn't cause any node to enter rendering pipeline.
|
||||
// This can be done once there is an API to observe to (or be notified upon) interface state changes or pipeline enterings
|
||||
[self registerForNotificationsForInterfaceStateIfNeeded:selfInterfaceState];
|
||||
|
||||
#if ASRangeControllerLoggingEnabled
|
||||
ASDisplayNodeAssertTrue([visibleIndexPaths isSubsetOfSet:displayIndexPaths]);
|
||||
NSMutableArray<NSIndexPath *> *modifiedIndexPaths = (ASRangeControllerLoggingEnabled ? [NSMutableArray array] : nil);
|
||||
@@ -309,16 +305,21 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive;
|
||||
#if ASRangeControllerLoggingEnabled
|
||||
[modifiedIndexPaths addObject:indexPath];
|
||||
#endif
|
||||
|
||||
BOOL nodeShouldScheduleDisplay = [node shouldScheduleDisplayWithNewInterfaceState:interfaceState];
|
||||
[node recursivelySetInterfaceState:interfaceState];
|
||||
|
||||
if (nodeShouldScheduleDisplay) {
|
||||
[self registerForNodeDisplayNotificationsForInterfaceStateIfNeeded:selfInterfaceState];
|
||||
if (_didRegisterForNodeDisplayNotifications) {
|
||||
_pendingDisplayNodesTimestamp = CFAbsoluteTimeGetCurrent();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_didRegisterForNotifications) {
|
||||
_pendingDisplayNodesTimestamp = CFAbsoluteTimeGetCurrent();
|
||||
}
|
||||
|
||||
_rangeIsValid = YES;
|
||||
_queuedRangeUpdate = NO;
|
||||
|
||||
@@ -338,9 +339,9 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive;
|
||||
|
||||
#pragma mark - Notification observers
|
||||
|
||||
- (void)registerForNotificationsForInterfaceStateIfNeeded:(ASInterfaceState)interfaceState
|
||||
- (void)registerForNodeDisplayNotificationsForInterfaceStateIfNeeded:(ASInterfaceState)interfaceState
|
||||
{
|
||||
if (!_didRegisterForNotifications) {
|
||||
if (!_didRegisterForNodeDisplayNotifications) {
|
||||
ASLayoutRangeMode nextRangeMode = [ASRangeController rangeModeForInterfaceState:interfaceState
|
||||
currentRangeMode:_currentRangeMode];
|
||||
if (_currentRangeMode != nextRangeMode) {
|
||||
@@ -348,7 +349,7 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive;
|
||||
selector:@selector(scheduledNodesDidDisplay:)
|
||||
name:ASRenderingEngineDidDisplayScheduledNodesNotification
|
||||
object:nil];
|
||||
_didRegisterForNotifications = YES;
|
||||
_didRegisterForNodeDisplayNotifications = YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -359,7 +360,7 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive;
|
||||
if (_pendingDisplayNodesTimestamp < notificationTimestamp) {
|
||||
// The rendering engine has processed all the nodes this range controller scheduled. Let's schedule a range update
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:ASRenderingEngineDidDisplayScheduledNodesNotification object:nil];
|
||||
_didRegisterForNotifications = NO;
|
||||
_didRegisterForNodeDisplayNotifications = NO;
|
||||
|
||||
[self scheduleRangeUpdate];
|
||||
}
|
||||
|
||||
@@ -18,27 +18,13 @@
|
||||
@property (nonatomic, assign, readonly) UIUserInterfaceIdiom userInterfaceIdiom;
|
||||
@property (nonatomic, assign, readonly) UIUserInterfaceSizeClass verticalSizeClass;
|
||||
@property (nonatomic, assign, readonly) UIForceTouchCapability forceTouchCapability;
|
||||
|
||||
/**
|
||||
* An optional context to pass along with an ASTraitCollection.
|
||||
* This can be used to pass any internal state to all subnodes via the ASTraitCollection that is not
|
||||
* included in UITraitCollection. This could range from more fine-tuned size classes to a class of
|
||||
* constants that is based upon the new trait collection.
|
||||
*
|
||||
* Be aware that internally this context is held by a C struct which cannot retain the pointer.
|
||||
* ASTraitCollection is generally a very short-lived class, existing only to provide a non-struct API
|
||||
* to trait collections. When an ASTraitCollection is returned via one of ASViewController's 2
|
||||
* custom trait collection creation blocks, traitCollectionContext is assigned to the VC's traitCollectionContext.
|
||||
* This makes sure that the VC is the owner of the context and ASEnvironmentTraitCollections will not
|
||||
* have a reference to a dangling pointer.
|
||||
*/
|
||||
@property (nonatomic, strong, readonly) id traitCollectionContext;
|
||||
@property (nonatomic, assign, readonly) CGSize containerSize;
|
||||
|
||||
|
||||
+ (ASTraitCollection *)traitCollectionWithASEnvironmentTraitCollection:(ASEnvironmentTraitCollection)traits;
|
||||
|
||||
+ (ASTraitCollection *)traitCollectionWithUITraitCollection:(UITraitCollection *)traitCollection
|
||||
traitCollectionContext:(id)traitCollectionContext;
|
||||
containerSize:(CGSize)windowSize;
|
||||
|
||||
|
||||
+ (ASTraitCollection *)traitCollectionWithDisplayScale:(CGFloat)displayScale
|
||||
@@ -46,7 +32,7 @@
|
||||
horizontalSizeClass:(UIUserInterfaceSizeClass)horizontalSizeClass
|
||||
verticalSizeClass:(UIUserInterfaceSizeClass)verticalSizeClass
|
||||
forceTouchCapability:(UIForceTouchCapability)forceTouchCapability
|
||||
traitCollectionContext:(id)traitCollectionContext;
|
||||
containerSize:(CGSize)windowSize;
|
||||
|
||||
|
||||
- (ASEnvironmentTraitCollection)environmentTraitCollection;
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
horizontalSizeClass:(UIUserInterfaceSizeClass)horizontalSizeClass
|
||||
verticalSizeClass:(UIUserInterfaceSizeClass)verticalSizeClass
|
||||
forceTouchCapability:(UIForceTouchCapability)forceTouchCapability
|
||||
traitCollectionContext:(id)traitCollectionContext
|
||||
containerSize:(CGSize)windowSize
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
@@ -30,7 +30,7 @@
|
||||
_horizontalSizeClass = horizontalSizeClass;
|
||||
_verticalSizeClass = verticalSizeClass;
|
||||
_forceTouchCapability = forceTouchCapability;
|
||||
_traitCollectionContext = traitCollectionContext;
|
||||
_containerSize = windowSize;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -40,29 +40,29 @@
|
||||
horizontalSizeClass:(UIUserInterfaceSizeClass)horizontalSizeClass
|
||||
verticalSizeClass:(UIUserInterfaceSizeClass)verticalSizeClass
|
||||
forceTouchCapability:(UIForceTouchCapability)forceTouchCapability
|
||||
traitCollectionContext:(id)traitCollectionContext
|
||||
containerSize:(CGSize)windowSize
|
||||
{
|
||||
return [[[self class] alloc] initWithDisplayScale:displayScale
|
||||
userInterfaceIdiom:userInterfaceIdiom
|
||||
horizontalSizeClass:horizontalSizeClass
|
||||
verticalSizeClass:verticalSizeClass
|
||||
forceTouchCapability:forceTouchCapability
|
||||
traitCollectionContext:traitCollectionContext];
|
||||
containerSize:windowSize];
|
||||
}
|
||||
|
||||
+ (ASTraitCollection *)traitCollectionWithASEnvironmentTraitCollection:(ASEnvironmentTraitCollection)traits
|
||||
{
|
||||
return [[[self class] alloc] initWithDisplayScale:traits.displayScale
|
||||
userInterfaceIdiom:traits.userInterfaceIdiom
|
||||
horizontalSizeClass:traits.horizontalSizeClass
|
||||
verticalSizeClass:traits.verticalSizeClass
|
||||
forceTouchCapability:traits.forceTouchCapability
|
||||
traitCollectionContext:traits.displayContext];
|
||||
return [[[self class] alloc] initWithDisplayScale:traits.displayScale
|
||||
userInterfaceIdiom:traits.userInterfaceIdiom
|
||||
horizontalSizeClass:traits.horizontalSizeClass
|
||||
verticalSizeClass:traits.verticalSizeClass
|
||||
forceTouchCapability:traits.forceTouchCapability
|
||||
containerSize:traits.containerSize];
|
||||
|
||||
}
|
||||
|
||||
+ (ASTraitCollection *)traitCollectionWithUITraitCollection:(UITraitCollection *)traitCollection
|
||||
traitCollectionContext:(id)traitCollectionContext
|
||||
containerSize:(CGSize)windowSize
|
||||
{
|
||||
ASTraitCollection *asyncTraitCollection = nil;
|
||||
if (AS_AT_LEAST_IOS9) {
|
||||
@@ -71,7 +71,7 @@
|
||||
horizontalSizeClass:traitCollection.horizontalSizeClass
|
||||
verticalSizeClass:traitCollection.verticalSizeClass
|
||||
forceTouchCapability:traitCollection.forceTouchCapability
|
||||
traitCollectionContext:traitCollectionContext];
|
||||
containerSize:windowSize];
|
||||
}
|
||||
else if (AS_AT_LEAST_IOS8) {
|
||||
asyncTraitCollection = [[[self class] alloc] initWithDisplayScale:traitCollection.displayScale
|
||||
@@ -79,7 +79,7 @@
|
||||
horizontalSizeClass:traitCollection.horizontalSizeClass
|
||||
verticalSizeClass:traitCollection.verticalSizeClass
|
||||
forceTouchCapability:0
|
||||
traitCollectionContext:traitCollectionContext];
|
||||
containerSize:windowSize];
|
||||
} else {
|
||||
asyncTraitCollection = [[[self class] alloc] init];
|
||||
}
|
||||
@@ -95,7 +95,7 @@
|
||||
.userInterfaceIdiom = self.userInterfaceIdiom,
|
||||
.verticalSizeClass = self.verticalSizeClass,
|
||||
.forceTouchCapability = self.forceTouchCapability,
|
||||
.displayContext = self.traitCollectionContext,
|
||||
.containerSize = self.containerSize,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
self.horizontalSizeClass == traitCollection.horizontalSizeClass &&
|
||||
self.verticalSizeClass == traitCollection.verticalSizeClass &&
|
||||
self.userInterfaceIdiom == traitCollection.userInterfaceIdiom &&
|
||||
self.traitCollectionContext == traitCollection.traitCollectionContext &&
|
||||
CGSizeEqualToSize(self.containerSize, traitCollection.containerSize) &&
|
||||
self.forceTouchCapability == traitCollection.forceTouchCapability;
|
||||
}
|
||||
|
||||
|
||||
@@ -135,6 +135,11 @@ inline BOOL ASHierarchyStateIncludesRangeManaged(ASHierarchyState hierarchyState
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL shouldBypassEnsureDisplay;
|
||||
|
||||
/**
|
||||
* @abstract Checks whether a node should be scheduled for display, considering its current and new interface states.
|
||||
*/
|
||||
- (BOOL)shouldScheduleDisplayWithNewInterfaceState:(ASInterfaceState)newInterfaceState;
|
||||
|
||||
@end
|
||||
|
||||
@interface UIView (ASDisplayNodeInternal)
|
||||
|
||||
@@ -207,7 +207,7 @@ ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState childEnvi
|
||||
childTraitCollection.userInterfaceIdiom = parentTraitCollection.userInterfaceIdiom;
|
||||
childTraitCollection.forceTouchCapability = parentTraitCollection.forceTouchCapability;
|
||||
childTraitCollection.displayScale = parentTraitCollection.displayScale;
|
||||
childTraitCollection.displayContext = parentTraitCollection.displayContext;
|
||||
childTraitCollection.containerSize = parentTraitCollection.containerSize;
|
||||
childEnvironmentState.environmentTraitCollection = childTraitCollection;
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user