Swiftgram/AsyncDisplayKit/ASTableNode.mm
rcancro 8bb4eba080 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!
2016-05-10 14:44:22 -07:00

165 lines
4.0 KiB
Plaintext

//
// ASTableNode.m
// AsyncDisplayKit
//
// Created by Steven Ramkumar on 11/4/15.
// Copyright © 2015 Facebook. All rights reserved.
//
#import "ASEnvironmentInternal.h"
#import "ASFlowLayoutController.h"
#import "ASTableViewInternal.h"
#import "ASDisplayNode+Subclasses.h"
#import "ASRangeControllerUpdateRangeProtocol+Beta.h"
@interface _ASTablePendingState : NSObject
@property (weak, nonatomic) id <ASTableDelegate> delegate;
@property (weak, nonatomic) id <ASTableDataSource> dataSource;
@end
@implementation _ASTablePendingState
@end
@interface ASTableNode ()
@property (nonatomic, strong) _ASTablePendingState *pendingState;
@end
@interface ASTableView ()
- (instancetype)_initWithFrame:(CGRect)frame style:(UITableViewStyle)style dataControllerClass:(Class)dataControllerClass;
@end
@implementation ASTableNode
- (instancetype)_initWithTableView:(ASTableView *)tableView
{
// Avoid a retain cycle. In this case, the ASTableView is creating us, and strongly retains us.
ASTableView * __weak weakTableView = tableView;
if (self = [super initWithViewBlock:^UIView *{ return weakTableView; }]) {
__unused __weak ASTableView *view = [self view];
return self;
}
return nil;
}
- (instancetype)_initWithFrame:(CGRect)frame style:(UITableViewStyle)style dataControllerClass:(Class)dataControllerClass
{
ASDisplayNodeViewBlock tableViewBlock = ^UIView *{
return [[ASTableView alloc] _initWithFrame:frame style:style dataControllerClass:dataControllerClass ownedByNode:YES];
};
if (self = [super initWithViewBlock:tableViewBlock]) {
return self;
}
return nil;
}
- (instancetype)initWithStyle:(UITableViewStyle)style
{
return [self _initWithFrame:CGRectZero style:style dataControllerClass:nil];
}
- (instancetype)init
{
return [self _initWithFrame:CGRectZero style:UITableViewStylePlain dataControllerClass:nil];
}
- (void)didLoad
{
[super didLoad];
ASTableView *view = self.view;
view.tableNode = self;
if (_pendingState) {
_ASTablePendingState *pendingState = _pendingState;
self.pendingState = nil;
view.asyncDelegate = pendingState.delegate;
view.asyncDataSource = pendingState.dataSource;
}
}
- (void)updateCurrentRangeWithMode:(ASLayoutRangeMode)rangeMode
{
if (!self.isNodeLoaded) {
return;
}
[self.view.rangeController updateCurrentRangeWithMode:rangeMode];
}
- (_ASTablePendingState *)pendingState
{
if (!_pendingState && ![self isNodeLoaded]) {
self.pendingState = [[_ASTablePendingState alloc] init];
}
ASDisplayNodeAssert(![self isNodeLoaded] || !_pendingState, @"ASTableNode should not have a pendingState once it is loaded");
return _pendingState;
}
- (void)setDelegate:(id <ASTableDelegate>)delegate
{
if ([self pendingState]) {
_pendingState.delegate = delegate;
} else {
ASDisplayNodeAssert([self isNodeLoaded], @"ASTableNode should be loaded if pendingState doesn't exist");
self.view.asyncDelegate = delegate;
}
}
- (id <ASTableDelegate>)delegate
{
if ([self pendingState]) {
return _pendingState.delegate;
} else {
return self.view.asyncDelegate;
}
}
- (void)setDataSource:(id <ASTableDataSource>)dataSource
{
if ([self pendingState]) {
_pendingState.dataSource = dataSource;
} else {
ASDisplayNodeAssert([self isNodeLoaded], @"ASTableNode should be loaded if pendingState doesn't exist");
self.view.asyncDataSource = dataSource;
}
}
- (id <ASTableDataSource>)dataSource
{
if ([self pendingState]) {
return _pendingState.dataSource;
} else {
return self.view.asyncDataSource;
}
}
- (ASTableView *)view
{
return (ASTableView *)[super view];
}
#if ASRangeControllerLoggingEnabled
- (void)visibilityDidChange:(BOOL)isVisible
{
[super visibilityDidChange:isVisible];
NSLog(@"%@ - visible: %d", self, isVisible);
}
#endif
- (void)clearContents
{
[super clearContents];
[self.view clearContents];
}
- (void)clearFetchedData
{
[super clearFetchedData];
[self.view clearFetchedData];
}
ASDisplayTraitsCollectionTableSetEnvironmentState
@end