mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 06:35:51 +00:00
[Layout Transition] Add default fade in / out layout transition (#2052)
* Add default fade in / out layout transition * Add example for layout transition * Update for recent layout transition API changes * To be able to do a layoutTransition the node needs to be loaded * Rename layoutTransitionDuration to defaultLayoutTransitionDuration * Expose default layout transition duration delay and options * Use `UIViewAnimationOptionBeginFromCurrentState` for initial defaultLayoutTransitionOptions
This commit is contained in:
committed by
Adlai Holler
parent
43370fe6ff
commit
adcc9afb5a
199
examples/ASDKLayoutTransition/Sample/ViewController.m
Normal file
199
examples/ASDKLayoutTransition/Sample/ViewController.m
Normal file
@@ -0,0 +1,199 @@
|
||||
//
|
||||
// ViewController.m
|
||||
// Sample
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#import "ViewController.h"
|
||||
|
||||
#import <AsyncDisplayKit/AsyncDisplayKit.h>
|
||||
|
||||
#pragma mark - TransitionNode
|
||||
|
||||
#define USE_CUSTOM_LAYOUT_TRANSITION 0
|
||||
|
||||
@interface TransitionNode : ASDisplayNode
|
||||
@property (nonatomic, assign) BOOL enabled;
|
||||
@property (nonatomic, strong) ASButtonNode *buttonNode;
|
||||
@property (nonatomic, strong) ASTextNode *textNodeOne;
|
||||
@property (nonatomic, strong) ASTextNode *textNodeTwo;
|
||||
@end
|
||||
|
||||
@implementation TransitionNode
|
||||
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self == nil) { return self; }
|
||||
|
||||
self.usesImplicitHierarchyManagement = YES;
|
||||
|
||||
// Define the layout transition duration for the default transition
|
||||
self.defaultLayoutTransitionDuration = 1.0;
|
||||
|
||||
_enabled = NO;
|
||||
|
||||
// Setup text nodes
|
||||
_textNodeOne = [[ASTextNode alloc] init];
|
||||
_textNodeOne.attributedText = [[NSAttributedString alloc] initWithString:@"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled"];
|
||||
|
||||
_textNodeTwo = [[ASTextNode alloc] init];
|
||||
_textNodeTwo.attributedText = [[NSAttributedString alloc] initWithString:@"It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English."];
|
||||
|
||||
// Setup button
|
||||
NSString *buttonTitle = @"Start Layout Transition";
|
||||
UIFont *buttonFont = [UIFont systemFontOfSize:16.0];
|
||||
UIColor *buttonColor = [UIColor blueColor];
|
||||
|
||||
_buttonNode = [[ASButtonNode alloc] init];
|
||||
[_buttonNode setTitle:buttonTitle withFont:buttonFont withColor:buttonColor forState:ASControlStateNormal];
|
||||
|
||||
// Note: Currently we have to set all the button properties to the same one as for ASControlStateNormal. Otherwise
|
||||
// if the button is involved in the layout transition it would break the transition as it does a layout pass
|
||||
// while changing the title. This needs and will be fixed in the future!
|
||||
[_buttonNode setTitle:buttonTitle withFont:buttonFont withColor:buttonColor forState:ASControlStateHighlighted];
|
||||
|
||||
|
||||
// Some debug colors
|
||||
_textNodeOne.backgroundColor = [UIColor orangeColor];
|
||||
_textNodeTwo.backgroundColor = [UIColor greenColor];
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)didLoad
|
||||
{
|
||||
[super didLoad];
|
||||
|
||||
[self.buttonNode addTarget:self action:@selector(buttonPressed:) forControlEvents:ASControlNodeEventTouchDown];
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
- (void)buttonPressed:(id)sender
|
||||
{
|
||||
self.enabled = !self.enabled;
|
||||
|
||||
[self transitionLayoutAnimated:YES measurementCompletion:nil];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Layout
|
||||
|
||||
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize
|
||||
{
|
||||
ASTextNode *nextTextNode = self.enabled ? self.textNodeTwo : self.textNodeOne;
|
||||
nextTextNode.flexGrow = YES;
|
||||
nextTextNode.flexShrink = YES;
|
||||
|
||||
ASStackLayoutSpec *horizontalStackLayout = [ASStackLayoutSpec horizontalStackLayoutSpec];
|
||||
horizontalStackLayout.children = @[nextTextNode];
|
||||
|
||||
self.buttonNode.alignSelf = ASStackLayoutAlignSelfCenter;
|
||||
|
||||
ASStackLayoutSpec *verticalStackLayout = [ASStackLayoutSpec verticalStackLayoutSpec];
|
||||
verticalStackLayout.spacing = 10.0;
|
||||
verticalStackLayout.children = @[horizontalStackLayout, self.buttonNode];
|
||||
|
||||
return [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsMake(15.0, 15.0, 15.0, 15.0) child:verticalStackLayout];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Transition
|
||||
|
||||
#if USE_CUSTOM_LAYOUT_TRANSITION
|
||||
|
||||
- (void)animateLayoutTransition:(id<ASContextTransitioning>)context
|
||||
{
|
||||
ASDisplayNode *fromNode = [[context removedSubnodes] objectAtIndex:0];
|
||||
ASDisplayNode *toNode = [[context insertedSubnodes] objectAtIndex:0];
|
||||
|
||||
ASButtonNode *buttonNode = nil;
|
||||
for (ASDisplayNode *node in [context subnodesForKey:ASTransitionContextToLayoutKey]) {
|
||||
if ([node isKindOfClass:[ASButtonNode class]]) {
|
||||
buttonNode = (ASButtonNode *)node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CGRect toNodeFrame = [context finalFrameForNode:toNode];
|
||||
toNodeFrame.origin.x += (self.enabled ? toNodeFrame.size.width : -toNodeFrame.size.width);
|
||||
toNode.frame = toNodeFrame;
|
||||
toNode.alpha = 0.0;
|
||||
|
||||
CGRect fromNodeFrame = fromNode.frame;
|
||||
fromNodeFrame.origin.x += (self.enabled ? -fromNodeFrame.size.width : fromNodeFrame.size.width);
|
||||
|
||||
// We will use the same transition duration as the default transition
|
||||
[UIView animateWithDuration:self.defaultLayoutTransitionDuration animations:^{
|
||||
toNode.frame = [context finalFrameForNode:toNode];
|
||||
toNode.alpha = 1.0;
|
||||
|
||||
fromNode.frame = fromNodeFrame;
|
||||
fromNode.alpha = 0.0;
|
||||
|
||||
// Update frame of self
|
||||
CGSize fromSize = [context layoutForKey:ASTransitionContextFromLayoutKey].size;
|
||||
CGSize toSize = [context layoutForKey:ASTransitionContextToLayoutKey].size;
|
||||
BOOL isResized = (CGSizeEqualToSize(fromSize, toSize) == NO);
|
||||
if (isResized == YES) {
|
||||
CGPoint position = self.frame.origin;
|
||||
self.frame = CGRectMake(position.x, position.y, toSize.width, toSize.height);
|
||||
}
|
||||
|
||||
buttonNode.frame = [context finalFrameForNode:buttonNode];
|
||||
} completion:^(BOOL finished) {
|
||||
[context completeTransition:finished];
|
||||
}];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#pragma mark - ViewController
|
||||
|
||||
@interface ViewController ()
|
||||
@property (nonatomic, strong) TransitionNode *transitionNode;
|
||||
@end
|
||||
|
||||
@implementation ViewController
|
||||
|
||||
#pragma mark - UIViewController
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
_transitionNode = [TransitionNode new];
|
||||
[self.view addSubnode:_transitionNode];
|
||||
|
||||
// Some debug colors
|
||||
_transitionNode.backgroundColor = [UIColor grayColor];
|
||||
}
|
||||
|
||||
- (void)viewDidLayoutSubviews
|
||||
{
|
||||
[super viewDidLayoutSubviews];
|
||||
|
||||
CGSize size = [self.transitionNode measure:self.view.frame.size];
|
||||
self.transitionNode.frame = CGRectMake(0, 20, size.width, size.height);
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user