Skip to content

Commit 8bb4eba

Browse files
committed
Initial attempt at implementing Display Traits
Initial attempt to get display traits working with ASEnvironment. To get proper ASDisplayTraits support, you must use an ASViewController. The ASViewController implements UITraitCollection-related methods (`traitCollectionDidChange:`, `willTransitionToTraitCollection:withTransitionCoordinator:`, viewWillTransitionToSize:withTransitionCoordinator`) to update the internal ASDisplayTraits and propagate them to subnodes. ASTableNode and ASCollectionNode don't actually have their cells as subnodes, so a little bit of trickery is involved (on `setEnvironment:` the table/collection node gets its data controllers completedNodes and propagates the new traits. see `ASDisplayTraitsCollectionTableSetEnvironmentState`). The data controller also passes the current display traits when creating new cells. ASViewController also supports the ability to return a custom set of display traits. So if you have a modal dialog that should always be told it is in a compact size class, you can set the override block before displaying the VC. A new example, called Display Traits, has been added. It shows how display traits can be used in a ASViewController with a normal ASDisplayNode as its root, as well as in ASViewControllers hosting table nodes and collection nodes. There is also an example of overriding the default display traits of a VC. Please provide feedback!
1 parent 495f32f commit 8bb4eba

37 files changed

Lines changed: 1535 additions & 68 deletions

AsyncDisplayKit.xcodeproj/project.pbxproj

Lines changed: 12 additions & 18 deletions
Large diffs are not rendered by default.

AsyncDisplayKit/ASCollectionNode.mm

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#import "ASCollectionInternal.h"
1111
#import "ASCollectionViewLayoutFacilitatorProtocol.h"
1212
#import "ASDisplayNode+Subclasses.h"
13+
#import "ASEnvironmentInternal.h"
1314
#import "ASRangeControllerUpdateRangeProtocol+Beta.h"
1415
#include <vector>
1516

@@ -244,4 +245,6 @@ - (void)reloadDataImmediately
244245
[self.view reloadDataImmediately];
245246
}
246247

248+
ASDisplayTraitsCollectionTableSetEnvironmentState
249+
247250
@end

AsyncDisplayKit/ASCollectionView.mm

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ - (instancetype)init
9191
#pragma mark -
9292
#pragma mark ASCollectionView.
9393

94-
@interface ASCollectionView () <ASRangeControllerDataSource, ASRangeControllerDelegate, ASDataControllerSource, ASCellNodeLayoutDelegate, ASDelegateProxyInterceptor, ASBatchFetchingScrollView> {
94+
@interface ASCollectionView () <ASRangeControllerDataSource, ASRangeControllerDelegate, ASDataControllerSource, ASCellNodeLayoutDelegate, ASDelegateProxyInterceptor, ASBatchFetchingScrollView, ASDataControllerEnvironmentDelegate> {
9595
ASCollectionViewProxy *_proxyDataSource;
9696
ASCollectionViewProxy *_proxyDelegate;
9797

@@ -225,6 +225,7 @@ - (instancetype)_initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionV
225225
_dataController = [[ASCollectionDataController alloc] initWithAsyncDataFetching:NO];
226226
_dataController.delegate = _rangeController;
227227
_dataController.dataSource = self;
228+
_dataController.environmentDelegate = self;
228229

229230
_batchContext = [[ASBatchContext alloc] init];
230231

@@ -917,6 +918,14 @@ - (void)dataControllerUnlockDataSource
917918
}
918919
}
919920

921+
- (id<ASEnvironment>)dataControllerEnvironment
922+
{
923+
if (self.collectionNode) {
924+
return self.collectionNode;
925+
}
926+
return self.strongCollectionNode;
927+
}
928+
920929
#pragma mark - ASCollectionViewDataControllerSource Supplementary view support
921930

922931
- (ASCellNode *)dataController:(ASCollectionDataController *)dataController supplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath

AsyncDisplayKit/ASDisplayNode.mm

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2687,11 +2687,13 @@ - (void)setInHierarchy:(BOOL)inHierarchy
26872687

26882688
- (ASEnvironmentState)environmentState
26892689
{
2690+
ASDN::MutexLocker l(_propertyLock);
26902691
return _environmentState;
26912692
}
26922693

26932694
- (void)setEnvironmentState:(ASEnvironmentState)environmentState
26942695
{
2696+
ASDN::MutexLocker l(_propertyLock);
26952697
_environmentState = environmentState;
26962698
}
26972699

@@ -2707,7 +2709,12 @@ - (ASDisplayNode *)parent
27072709

27082710
- (BOOL)supportsUpwardPropagation
27092711
{
2710-
return ASEnvironmentStatePropagationEnabled();
2712+
return ASEnvironmentStateUpwardPropagationEnabled();
2713+
}
2714+
2715+
- (BOOL)supportsDownwardPropagation
2716+
{
2717+
return ASEnvironmentStateDownwardPropagationEnabled();
27112718
}
27122719

27132720
ASEnvironmentLayoutOptionsForwarding
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
// Copyright © 2015 Facebook. All rights reserved.
77
//
88

9+
#import "ASEnvironmentInternal.h"
910
#import "ASFlowLayoutController.h"
1011
#import "ASTableViewInternal.h"
1112
#import "ASDisplayNode+Subclasses.h"
@@ -158,4 +159,6 @@ - (void)clearFetchedData
158159
[self.view clearFetchedData];
159160
}
160161

162+
ASDisplayTraitsCollectionTableSetEnvironmentState
163+
161164
@end

AsyncDisplayKit/ASTableView.mm

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#import "ASDisplayNodeExtras.h"
1717
#import "ASDisplayNode+Beta.h"
1818
#import "ASDisplayNode+FrameworkPrivate.h"
19+
#import "ASEnvironmentInternal.h"
1920
#import "ASInternalHelpers.h"
2021
#import "ASLayout.h"
2122
#import "ASLayoutController.h"
@@ -88,7 +89,7 @@ @interface ASTableNode ()
8889
- (instancetype)_initWithTableView:(ASTableView *)tableView;
8990
@end
9091

91-
@interface ASTableView () <ASRangeControllerDataSource, ASRangeControllerDelegate, ASDataControllerSource, _ASTableViewCellDelegate, ASCellNodeLayoutDelegate, ASDelegateProxyInterceptor, ASBatchFetchingScrollView>
92+
@interface ASTableView () <ASRangeControllerDataSource, ASRangeControllerDelegate, ASDataControllerSource, _ASTableViewCellDelegate, ASCellNodeLayoutDelegate, ASDelegateProxyInterceptor, ASBatchFetchingScrollView, ASDataControllerEnvironmentDelegate>
9293
{
9394
ASTableViewProxy *_proxyDataSource;
9495
ASTableViewProxy *_proxyDelegate;
@@ -175,6 +176,7 @@ - (void)configureWithDataControllerClass:(Class)dataControllerClass
175176
_dataController = [[dataControllerClass alloc] initWithAsyncDataFetching:NO];
176177
_dataController.dataSource = self;
177178
_dataController.delegate = _rangeController;
179+
_dataController.environmentDelegate = self;
178180

179181
_layoutController.dataSource = _dataController;
180182

@@ -1078,6 +1080,16 @@ - (NSUInteger)numberOfSectionsInDataController:(ASDataController *)dataControlle
10781080
}
10791081
}
10801082

1083+
#pragma mark - ASDataControllerEnvironmentDelegate
1084+
1085+
- (id<ASEnvironment>)dataControllerEnvironment
1086+
{
1087+
if (self.tableNode) {
1088+
return self.tableNode;
1089+
}
1090+
return self.strongTableNode;
1091+
}
1092+
10811093
#pragma mark - _ASTableViewCellDelegate
10821094

10831095
- (void)didLayoutSubviewsOfTableViewCell:(_ASTableViewCell *)tableViewCell

AsyncDisplayKit/ASViewController.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,27 @@
1111

1212
NS_ASSUME_NONNULL_BEGIN
1313

14+
typedef ASDisplayTraits (^ASDisplayTraitsForTraitCollectionBlock)(UITraitCollection *traitCollection);
15+
typedef ASDisplayTraits (^ASDisplayTraitsForTraitWindowSizeBlock)(CGSize windowSize);
16+
1417
@interface ASViewController<__covariant DisplayNodeType : ASDisplayNode *> : UIViewController
1518

1619
- (instancetype)initWithNode:(DisplayNodeType)node NS_DESIGNATED_INITIALIZER;
1720

1821
@property (nonatomic, strong, readonly) DisplayNodeType node;
1922

23+
@property (nonatomic, strong) id displayTraitsContext;
24+
25+
/**
26+
* Set this block to customize the ASDisplayTraits returned when the VC transitions to the given traitCollection.
27+
*/
28+
@property (nonatomic, copy) ASDisplayTraitsForTraitCollectionBlock overrideDisplayTraitsWithTraitCollection;
29+
30+
/**
31+
* Set this block to customize the ASDisplayTraits returned when the VC transitions to the given window size.
32+
*/
33+
@property (nonatomic, copy) ASDisplayTraitsForTraitWindowSizeBlock overrideDisplayTraitsWithWindowSize;
34+
2035
/**
2136
* @abstract Passthrough property to the the .interfaceState of the node.
2237
* @return The current ASInterfaceState of the node, indicating whether it is visible and other situational properties.
Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#import "ASDimension.h"
1212
#import "ASDisplayNode+FrameworkPrivate.h"
1313
#import "ASDisplayNode+Beta.h"
14+
#import "ASEnvironmentInternal.h"
1415
#import "ASRangeControllerUpdateRangeProtocol+Beta.h"
1516

1617
@implementation ASViewController
@@ -42,10 +43,18 @@ - (instancetype)initWithNode:(ASDisplayNode *)node
4243
_node = node;
4344

4445
_automaticallyAdjustRangeModeBasedOnViewEvents = NO;
45-
46+
4647
return self;
4748
}
4849

50+
- (void)dealloc
51+
{
52+
if (_displayTraitsContext != nil) {
53+
ASDisplayTraitsClearDisplayContext(self.node);
54+
_displayTraitsContext = nil;
55+
}
56+
}
57+
4958
- (void)loadView
5059
{
5160
ASDisplayNodeAssertTrue(!_node.layerBacked);
@@ -132,4 +141,66 @@ - (ASInterfaceState)interfaceState
132141
return _node.interfaceState;
133142
}
134143

144+
#pragma mark - ASDisplayTraits
145+
146+
- (ASDisplayTraits)displayTraitsForTraitCollection:(UITraitCollection *)traitCollection
147+
{
148+
if (self.overrideDisplayTraitsWithTraitCollection) {
149+
return self.overrideDisplayTraitsWithTraitCollection(traitCollection);
150+
}
151+
152+
ASDisplayTraits displayTraits = ASDisplayTraitsFromUITraitCollection(traitCollection);
153+
displayTraits.displayContext = _displayTraitsContext;
154+
return displayTraits;
155+
}
156+
157+
- (ASDisplayTraits)displayTraitsForWindowSize:(CGSize)windowSize
158+
{
159+
if (self.overrideDisplayTraitsWithWindowSize) {
160+
return self.overrideDisplayTraitsWithWindowSize(windowSize);
161+
}
162+
return self.node.environmentState.displayTraits;
163+
}
164+
165+
- (void)progagateNewDisplayTraits:(ASDisplayTraits)displayTraits
166+
{
167+
ASEnvironmentState environmentState = self.node.environmentState;
168+
ASDisplayTraits oldDisplayTraits = environmentState.displayTraits;
169+
170+
if (ASDisplayTraitsIsEqualToASDisplayTraits(displayTraits, oldDisplayTraits) == NO) {
171+
environmentState.displayTraits = displayTraits;
172+
[self.node setEnvironmentState:environmentState];
173+
[self.node setNeedsLayout];
174+
175+
NSArray<id<ASEnvironment>> *children = [self.node children];
176+
for (id<ASEnvironment> child in children) {
177+
ASEnvironmentStatePropagateDown(child, environmentState.displayTraits);
178+
}
179+
}
180+
}
181+
182+
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
183+
{
184+
[super traitCollectionDidChange:previousTraitCollection];
185+
186+
ASDisplayTraits displayTraits = [self displayTraitsForTraitCollection:self.traitCollection];
187+
[self progagateNewDisplayTraits:displayTraits];
188+
}
189+
190+
- (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
191+
{
192+
[super willTransitionToTraitCollection:newCollection withTransitionCoordinator:coordinator];
193+
194+
ASDisplayTraits displayTraits = [self displayTraitsForTraitCollection:self.traitCollection];
195+
[self progagateNewDisplayTraits:displayTraits];
196+
}
197+
198+
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
199+
{
200+
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
201+
202+
ASDisplayTraits displayTraits = [self displayTraitsForWindowSize:size];
203+
[self progagateNewDisplayTraits:displayTraits];
204+
}
205+
135206
@end

AsyncDisplayKit/Details/ASDataController.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ NS_ASSUME_NONNULL_BEGIN
1717

1818
@class ASCellNode;
1919
@class ASDataController;
20+
@protocol ASEnvironment;
2021

2122
typedef NSUInteger ASDataControllerAnimationOptions;
2223

@@ -64,6 +65,11 @@ FOUNDATION_EXPORT NSString * const ASDataControllerRowNodeKind;
6465
*/
6566
- (void)dataControllerUnlockDataSource;
6667

68+
69+
@end
70+
71+
@protocol ASDataControllerEnvironmentDelegate
72+
- (id<ASEnvironment>)dataControllerEnvironment;
6773
@end
6874

6975
/**
@@ -122,6 +128,11 @@ FOUNDATION_EXPORT NSString * const ASDataControllerRowNodeKind;
122128
*/
123129
@property (nonatomic, weak) id<ASDataControllerDelegate> delegate;
124130

131+
/**
132+
*
133+
*/
134+
@property (nonatomic, weak) id<ASDataControllerEnvironmentDelegate> environmentDelegate;
135+
125136
/**
126137
* Designated initializer.
127138
*

AsyncDisplayKit/Details/ASDataController.mm

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#import "ASAssert.h"
1414
#import "ASCellNode.h"
1515
#import "ASDisplayNode.h"
16+
#import "ASEnvironmentInternal.h"
1617
#import "ASFlowLayoutController.h"
1718
#import "ASInternalHelpers.h"
1819
#import "ASLayout.h"
@@ -519,8 +520,17 @@ - (void)accessDataSourceSynchronously:(BOOL)synchronously withBlock:(dispatch_bl
519520
for (NSUInteger i = 0; i < rowNum; i++) {
520521
NSIndexPath *indexPath = [sectionIndex indexPathByAddingIndex:i];
521522
ASCellNodeBlock nodeBlock = [_dataSource dataController:self nodeBlockAtIndexPath:indexPath];
523+
524+
// When creating a node, make sure to pass along the current display traits so it will be laid out properly
525+
ASCellNodeBlock nodeBlockPropagatingDisplayTraits = ^{
526+
ASCellNode *cellNode = nodeBlock();
527+
id<ASEnvironment> environment = [self.environmentDelegate dataControllerEnvironment];
528+
ASEnvironmentStatePropagateDown(cellNode, [environment environmentState].displayTraits);
529+
return cellNode;
530+
};
531+
522532
ASSizeRange constrainedSize = [self constrainedSizeForNodeOfKind:ASDataControllerRowNodeKind atIndexPath:indexPath];
523-
[contexts addObject:[[ASIndexedNodeContext alloc] initWithNodeBlock:nodeBlock
533+
[contexts addObject:[[ASIndexedNodeContext alloc] initWithNodeBlock:nodeBlockPropagatingDisplayTraits
524534
indexPath:indexPath
525535
constrainedSize:constrainedSize]];
526536
}

0 commit comments

Comments
 (0)