mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
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!
This commit is contained in:
206
AsyncDisplayKit/ASViewController.mm
Normal file
206
AsyncDisplayKit/ASViewController.mm
Normal file
@@ -0,0 +1,206 @@
|
||||
//
|
||||
// ASViewController.m
|
||||
// AsyncDisplayKit
|
||||
//
|
||||
// Created by Huy Nguyen on 16/09/15.
|
||||
// Copyright (c) 2015 Facebook. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASViewController.h"
|
||||
#import "ASAssert.h"
|
||||
#import "ASDimension.h"
|
||||
#import "ASDisplayNode+FrameworkPrivate.h"
|
||||
#import "ASDisplayNode+Beta.h"
|
||||
#import "ASEnvironmentInternal.h"
|
||||
#import "ASRangeControllerUpdateRangeProtocol+Beta.h"
|
||||
|
||||
@implementation ASViewController
|
||||
{
|
||||
BOOL _ensureDisplayed;
|
||||
BOOL _automaticallyAdjustRangeModeBasedOnViewEvents;
|
||||
}
|
||||
|
||||
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
|
||||
{
|
||||
ASDisplayNodeAssert(NO, @"ASViewController requires using -initWithNode:");
|
||||
return [self initWithNode:[[ASDisplayNode alloc] init]];
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder
|
||||
{
|
||||
ASDisplayNodeAssert(NO, @"ASViewController requires using -initWithNode:");
|
||||
return [self initWithNode:[[ASDisplayNode alloc] init]];
|
||||
}
|
||||
|
||||
- (instancetype)initWithNode:(ASDisplayNode *)node
|
||||
{
|
||||
if (!(self = [super initWithNibName:nil bundle:nil])) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
ASDisplayNodeAssertNotNil(node, @"Node must not be nil");
|
||||
ASDisplayNodeAssertTrue(!node.layerBacked);
|
||||
_node = node;
|
||||
|
||||
_automaticallyAdjustRangeModeBasedOnViewEvents = NO;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (_displayTraitsContext != nil) {
|
||||
ASDisplayTraitsClearDisplayContext(self.node);
|
||||
_displayTraitsContext = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)loadView
|
||||
{
|
||||
ASDisplayNodeAssertTrue(!_node.layerBacked);
|
||||
|
||||
// Apple applies a frame and autoresizing masks we need. Allocating a view is not
|
||||
// nearly as expensive as adding and removing it from a hierarchy, and fortunately
|
||||
// we can avoid that here. Enabling layerBacking on a single node in the hierarchy
|
||||
// will have a greater performance benefit than the impact of this transient view.
|
||||
[super loadView];
|
||||
UIView *view = self.view;
|
||||
CGRect frame = view.frame;
|
||||
UIViewAutoresizing autoresizingMask = view.autoresizingMask;
|
||||
|
||||
// We have what we need, so now create and assign the view we actually want.
|
||||
view = _node.view;
|
||||
_node.frame = frame;
|
||||
_node.autoresizingMask = autoresizingMask;
|
||||
self.view = view;
|
||||
}
|
||||
|
||||
- (void)viewWillLayoutSubviews
|
||||
{
|
||||
[super viewWillLayoutSubviews];
|
||||
[_node measureWithSizeRange:[self nodeConstrainedSize]];
|
||||
}
|
||||
|
||||
- (void)viewDidLayoutSubviews
|
||||
{
|
||||
if (_ensureDisplayed && self.neverShowPlaceholders) {
|
||||
_ensureDisplayed = NO;
|
||||
[self.node recursivelyEnsureDisplaySynchronously:YES];
|
||||
}
|
||||
[super viewDidLayoutSubviews];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
_ensureDisplayed = YES;
|
||||
[_node measureWithSizeRange:[self nodeConstrainedSize]];
|
||||
[_node recursivelyFetchData];
|
||||
|
||||
[self updateCurrentRangeModeWithModeIfPossible:ASLayoutRangeModeFull];
|
||||
}
|
||||
|
||||
- (void)viewDidDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewDidDisappear:animated];
|
||||
|
||||
[self updateCurrentRangeModeWithModeIfPossible:ASLayoutRangeModeMinimum];
|
||||
}
|
||||
|
||||
#pragma mark - Automatic range mode
|
||||
|
||||
- (BOOL)automaticallyAdjustRangeModeBasedOnViewEvents
|
||||
{
|
||||
return _automaticallyAdjustRangeModeBasedOnViewEvents;
|
||||
}
|
||||
|
||||
- (void)setAutomaticallyAdjustRangeModeBasedOnViewEvents:(BOOL)automaticallyAdjustRangeModeBasedOnViewEvents
|
||||
{
|
||||
_automaticallyAdjustRangeModeBasedOnViewEvents = automaticallyAdjustRangeModeBasedOnViewEvents;
|
||||
}
|
||||
|
||||
- (void)updateCurrentRangeModeWithModeIfPossible:(ASLayoutRangeMode)rangeMode
|
||||
{
|
||||
if (!_automaticallyAdjustRangeModeBasedOnViewEvents) { return; }
|
||||
if (![_node conformsToProtocol:@protocol(ASRangeControllerUpdateRangeProtocol)]) { return; }
|
||||
|
||||
id<ASRangeControllerUpdateRangeProtocol> updateRangeNode = (id<ASRangeControllerUpdateRangeProtocol>)_node;
|
||||
[updateRangeNode updateCurrentRangeWithMode:rangeMode];
|
||||
}
|
||||
|
||||
#pragma mark - Layout Helpers
|
||||
|
||||
- (ASSizeRange)nodeConstrainedSize
|
||||
{
|
||||
CGSize viewSize = self.view.bounds.size;
|
||||
return ASSizeRangeMake(viewSize, viewSize);
|
||||
}
|
||||
|
||||
- (ASInterfaceState)interfaceState
|
||||
{
|
||||
return _node.interfaceState;
|
||||
}
|
||||
|
||||
#pragma mark - ASDisplayTraits
|
||||
|
||||
- (ASDisplayTraits)displayTraitsForTraitCollection:(UITraitCollection *)traitCollection
|
||||
{
|
||||
if (self.overrideDisplayTraitsWithTraitCollection) {
|
||||
return self.overrideDisplayTraitsWithTraitCollection(traitCollection);
|
||||
}
|
||||
|
||||
ASDisplayTraits displayTraits = ASDisplayTraitsFromUITraitCollection(traitCollection);
|
||||
displayTraits.displayContext = _displayTraitsContext;
|
||||
return displayTraits;
|
||||
}
|
||||
|
||||
- (ASDisplayTraits)displayTraitsForWindowSize:(CGSize)windowSize
|
||||
{
|
||||
if (self.overrideDisplayTraitsWithWindowSize) {
|
||||
return self.overrideDisplayTraitsWithWindowSize(windowSize);
|
||||
}
|
||||
return self.node.environmentState.displayTraits;
|
||||
}
|
||||
|
||||
- (void)progagateNewDisplayTraits:(ASDisplayTraits)displayTraits
|
||||
{
|
||||
ASEnvironmentState environmentState = self.node.environmentState;
|
||||
ASDisplayTraits oldDisplayTraits = environmentState.displayTraits;
|
||||
|
||||
if (ASDisplayTraitsIsEqualToASDisplayTraits(displayTraits, oldDisplayTraits) == NO) {
|
||||
environmentState.displayTraits = displayTraits;
|
||||
[self.node setEnvironmentState:environmentState];
|
||||
[self.node setNeedsLayout];
|
||||
|
||||
NSArray<id<ASEnvironment>> *children = [self.node children];
|
||||
for (id<ASEnvironment> child in children) {
|
||||
ASEnvironmentStatePropagateDown(child, environmentState.displayTraits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
|
||||
{
|
||||
[super traitCollectionDidChange:previousTraitCollection];
|
||||
|
||||
ASDisplayTraits displayTraits = [self displayTraitsForTraitCollection:self.traitCollection];
|
||||
[self progagateNewDisplayTraits:displayTraits];
|
||||
}
|
||||
|
||||
- (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
|
||||
{
|
||||
[super willTransitionToTraitCollection:newCollection withTransitionCoordinator:coordinator];
|
||||
|
||||
ASDisplayTraits displayTraits = [self displayTraitsForTraitCollection:self.traitCollection];
|
||||
[self progagateNewDisplayTraits:displayTraits];
|
||||
}
|
||||
|
||||
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
|
||||
{
|
||||
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
|
||||
|
||||
ASDisplayTraits displayTraits = [self displayTraitsForWindowSize:size];
|
||||
[self progagateNewDisplayTraits:displayTraits];
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user