mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-04-24 04:16:00 +08:00
RCTAnimation & RCTLayoutAnimation were decoupled from RCTUIManager
Reviewed By: javache Differential Revision: D5351726 fbshipit-source-id: f13e5cd47483f2d5f9b194c10ae3fb6e99e08d84
This commit is contained in:
committed by
Facebook Github Bot
parent
e7c1cf5b7d
commit
6312d67bcb
38
React/Modules/RCTLayoutAnimation.h
Normal file
38
React/Modules/RCTLayoutAnimation.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright (c) 2015-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.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import <React/RCTAnimationType.h>
|
||||
|
||||
@interface RCTLayoutAnimation : NSObject
|
||||
|
||||
@property (nonatomic, readonly) NSTimeInterval duration;
|
||||
@property (nonatomic, readonly) NSTimeInterval delay;
|
||||
@property (nonatomic, readonly, copy) NSString *property;
|
||||
@property (nonatomic, readonly) CGFloat springDamping;
|
||||
@property (nonatomic, readonly) CGFloat initialVelocity;
|
||||
@property (nonatomic, readonly) RCTAnimationType animationType;
|
||||
|
||||
+ (void)initializeStatics;
|
||||
|
||||
- (instancetype)initWithDuration:(NSTimeInterval)duration
|
||||
delay:(NSTimeInterval)delay
|
||||
property:(NSString *)property
|
||||
springDamping:(CGFloat)springDamping
|
||||
initialVelocity:(CGFloat)initialVelocity
|
||||
animationType:(RCTAnimationType)animationType;
|
||||
|
||||
- (instancetype)initWithDuration:(NSTimeInterval)duration
|
||||
config:(NSDictionary *)config;
|
||||
|
||||
- (void)performAnimations:(void (^)(void))animations
|
||||
withCompletionBlock:(void (^)(BOOL completed))completionBlock;
|
||||
|
||||
@end
|
||||
155
React/Modules/RCTLayoutAnimation.m
Normal file
155
React/Modules/RCTLayoutAnimation.m
Normal file
@@ -0,0 +1,155 @@
|
||||
/**
|
||||
* Copyright (c) 2015-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.
|
||||
*/
|
||||
|
||||
#import "RCTLayoutAnimation.h"
|
||||
|
||||
#import "RCTConvert.h"
|
||||
|
||||
@implementation RCTLayoutAnimation
|
||||
|
||||
static UIViewAnimationCurve _currentKeyboardAnimationCurve;
|
||||
|
||||
static UIViewAnimationOptions UIViewAnimationOptionsFromRCTAnimationType(RCTAnimationType type)
|
||||
{
|
||||
switch (type) {
|
||||
case RCTAnimationTypeLinear:
|
||||
return UIViewAnimationOptionCurveLinear;
|
||||
case RCTAnimationTypeEaseIn:
|
||||
return UIViewAnimationOptionCurveEaseIn;
|
||||
case RCTAnimationTypeEaseOut:
|
||||
return UIViewAnimationOptionCurveEaseOut;
|
||||
case RCTAnimationTypeEaseInEaseOut:
|
||||
return UIViewAnimationOptionCurveEaseInOut;
|
||||
case RCTAnimationTypeKeyboard:
|
||||
// http://stackoverflow.com/questions/18870447/how-to-use-the-default-ios7-uianimation-curve
|
||||
return (UIViewAnimationOptions)(_currentKeyboardAnimationCurve << 16);
|
||||
default:
|
||||
RCTLogError(@"Unsupported animation type %zd", type);
|
||||
return UIViewAnimationOptionCurveEaseInOut;
|
||||
}
|
||||
}
|
||||
|
||||
// Use a custom initialization function rather than implementing `+initialize` so that we can control
|
||||
// when the initialization code runs. `+initialize` runs immediately before the first message is sent
|
||||
// to the class which may be too late for us. By this time, we may have missed some
|
||||
// `UIKeyboardWillChangeFrameNotification`s.
|
||||
+ (void)initializeStatics
|
||||
{
|
||||
#if !TARGET_OS_TV
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(keyboardWillChangeFrame:)
|
||||
name:UIKeyboardWillChangeFrameNotification
|
||||
object:nil];
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
+ (void)keyboardWillChangeFrame:(NSNotification *)notification
|
||||
{
|
||||
#if !TARGET_OS_TV
|
||||
NSDictionary *userInfo = notification.userInfo;
|
||||
_currentKeyboardAnimationCurve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (instancetype)initWithDuration:(NSTimeInterval)duration
|
||||
delay:(NSTimeInterval)delay
|
||||
property:(NSString *)property
|
||||
springDamping:(CGFloat)springDamping
|
||||
initialVelocity:(CGFloat)initialVelocity
|
||||
animationType:(RCTAnimationType)animationType
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_duration = duration;
|
||||
_delay = delay;
|
||||
_property = property;
|
||||
_springDamping = springDamping;
|
||||
_initialVelocity = initialVelocity;
|
||||
_animationType = animationType;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithDuration:(NSTimeInterval)duration
|
||||
config:(NSDictionary *)config
|
||||
{
|
||||
if (!config) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (self = [super init]) {
|
||||
_property = [RCTConvert NSString:config[@"property"]];
|
||||
|
||||
_duration = [RCTConvert NSTimeInterval:config[@"duration"]] ?: duration;
|
||||
if (_duration > 0.0 && _duration < 0.01) {
|
||||
RCTLogError(@"RCTLayoutAnimationGroup expects timings to be in ms, not seconds.");
|
||||
_duration = _duration * 1000.0;
|
||||
}
|
||||
|
||||
_delay = [RCTConvert NSTimeInterval:config[@"delay"]];
|
||||
if (_delay > 0.0 && _delay < 0.01) {
|
||||
RCTLogError(@"RCTLayoutAnimationGroup expects timings to be in ms, not seconds.");
|
||||
_delay = _delay * 1000.0;
|
||||
}
|
||||
|
||||
_animationType = [RCTConvert RCTAnimationType:config[@"type"]];
|
||||
if (_animationType == RCTAnimationTypeSpring) {
|
||||
_springDamping = [RCTConvert CGFloat:config[@"springDamping"]];
|
||||
_initialVelocity = [RCTConvert CGFloat:config[@"initialVelocity"]];
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)performAnimations:(void (^)(void))animations
|
||||
withCompletionBlock:(void (^)(BOOL completed))completionBlock
|
||||
{
|
||||
if (_animationType == RCTAnimationTypeSpring) {
|
||||
[UIView animateWithDuration:_duration
|
||||
delay:_delay
|
||||
usingSpringWithDamping:_springDamping
|
||||
initialSpringVelocity:_initialVelocity
|
||||
options:UIViewAnimationOptionBeginFromCurrentState
|
||||
animations:animations
|
||||
completion:completionBlock];
|
||||
} else {
|
||||
UIViewAnimationOptions options =
|
||||
UIViewAnimationOptionBeginFromCurrentState |
|
||||
UIViewAnimationOptionsFromRCTAnimationType(_animationType);
|
||||
|
||||
[UIView animateWithDuration:_duration
|
||||
delay:_delay
|
||||
options:options
|
||||
animations:animations
|
||||
completion:completionBlock];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(RCTLayoutAnimation *)animation
|
||||
{
|
||||
return
|
||||
_duration == animation.duration &&
|
||||
_delay == animation.delay &&
|
||||
(_property == animation.property || [_property isEqualToString:animation.property]) &&
|
||||
_springDamping == animation.springDamping &&
|
||||
_initialVelocity == animation.initialVelocity &&
|
||||
_animationType == animation.animationType;
|
||||
}
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"<%@: %p; duration: %f; delay: %f; property: %@; springDamping: %f; initialVelocity: %f; animationType: %li;>",
|
||||
NSStringFromClass([self class]), self, _duration, _delay, _property, _springDamping, _initialVelocity, (long)_animationType];
|
||||
}
|
||||
|
||||
@end
|
||||
32
React/Modules/RCTLayoutAnimationGroup.h
Normal file
32
React/Modules/RCTLayoutAnimationGroup.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2015-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.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import <React/RCTBridgeModule.h>
|
||||
|
||||
@class RCTLayoutAnimation;
|
||||
|
||||
@interface RCTLayoutAnimationGroup : NSObject
|
||||
|
||||
@property (nonatomic, readonly) RCTLayoutAnimation *creatingLayoutAnimation;
|
||||
@property (nonatomic, readonly) RCTLayoutAnimation *updatingLayoutAnimation;
|
||||
@property (nonatomic, readonly) RCTLayoutAnimation *deletingLayoutAnimation;
|
||||
|
||||
@property (nonatomic, copy) RCTResponseSenderBlock callback;
|
||||
|
||||
- (instancetype)initWithCreatingLayoutAnimation:(RCTLayoutAnimation *)creatingLayoutAnimation
|
||||
updatingLayoutAnimation:(RCTLayoutAnimation *)updatingLayoutAnimation
|
||||
deletingLayoutAnimation:(RCTLayoutAnimation *)deletingLayoutAnimation
|
||||
callback:(RCTResponseSenderBlock)callback;
|
||||
|
||||
- (instancetype)initWithConfig:(NSDictionary *)config
|
||||
callback:(RCTResponseSenderBlock)callback;
|
||||
|
||||
@end
|
||||
74
React/Modules/RCTLayoutAnimationGroup.m
Normal file
74
React/Modules/RCTLayoutAnimationGroup.m
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Copyright (c) 2015-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.
|
||||
*/
|
||||
|
||||
#import "RCTLayoutAnimationGroup.h"
|
||||
|
||||
#import "RCTLayoutAnimation.h"
|
||||
#import "RCTConvert.h"
|
||||
|
||||
@implementation RCTLayoutAnimationGroup
|
||||
|
||||
- (instancetype)initWithCreatingLayoutAnimation:(RCTLayoutAnimation *)creatingLayoutAnimation
|
||||
updatingLayoutAnimation:(RCTLayoutAnimation *)updatingLayoutAnimation
|
||||
deletingLayoutAnimation:(RCTLayoutAnimation *)deletingLayoutAnimation
|
||||
callback:(RCTResponseSenderBlock)callback
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_creatingLayoutAnimation = creatingLayoutAnimation;
|
||||
_updatingLayoutAnimation = updatingLayoutAnimation;
|
||||
_deletingLayoutAnimation = deletingLayoutAnimation;
|
||||
_callback = callback;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithConfig:(NSDictionary *)config
|
||||
callback:(RCTResponseSenderBlock)callback
|
||||
{
|
||||
if (!config) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (self = [super init]) {
|
||||
NSTimeInterval duration = [RCTConvert NSTimeInterval:config[@"duration"]];
|
||||
|
||||
if (duration > 0.0 && duration < 0.01) {
|
||||
RCTLogError(@"RCTLayoutAnimationGroup expects timings to be in ms, not seconds.");
|
||||
duration = duration * 1000.0;
|
||||
}
|
||||
|
||||
_creatingLayoutAnimation = [[RCTLayoutAnimation alloc] initWithDuration:duration config:config[@"create"]];
|
||||
_updatingLayoutAnimation = [[RCTLayoutAnimation alloc] initWithDuration:duration config:config[@"update"]];
|
||||
_deletingLayoutAnimation = [[RCTLayoutAnimation alloc] initWithDuration:duration config:config[@"delete"]];
|
||||
_callback = callback;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(RCTLayoutAnimationGroup *)layoutAnimation
|
||||
{
|
||||
RCTLayoutAnimation *creatingLayoutAnimation = layoutAnimation.creatingLayoutAnimation;
|
||||
RCTLayoutAnimation *updatingLayoutAnimation = layoutAnimation.updatingLayoutAnimation;
|
||||
RCTLayoutAnimation *deletingLayoutAnimation = layoutAnimation.deletingLayoutAnimation;
|
||||
|
||||
return
|
||||
(_creatingLayoutAnimation == creatingLayoutAnimation || [_creatingLayoutAnimation isEqual:creatingLayoutAnimation]) &&
|
||||
(_updatingLayoutAnimation == updatingLayoutAnimation || [_updatingLayoutAnimation isEqual:updatingLayoutAnimation]) &&
|
||||
(_deletingLayoutAnimation == deletingLayoutAnimation || [_deletingLayoutAnimation isEqual:deletingLayoutAnimation]);
|
||||
}
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"<%@: %p; creatingLayoutAnimation: %@; updatingLayoutAnimation: %@; deletingLayoutAnimation: %@>",
|
||||
NSStringFromClass([self class]), self, [_creatingLayoutAnimation description], [_updatingLayoutAnimation description], [_deletingLayoutAnimation description]];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -59,6 +59,7 @@ RCT_EXTERN NSString *const RCTUIManagerDidRemoveRootViewNotification;
|
||||
*/
|
||||
RCT_EXTERN NSString *const RCTUIManagerRootViewKey;
|
||||
|
||||
@class RCTLayoutAnimationGroup;
|
||||
@class RCTUIManagerObserverCoordinator;
|
||||
|
||||
/**
|
||||
@@ -115,6 +116,13 @@ RCT_EXTERN NSString *const RCTUIManagerRootViewKey;
|
||||
*/
|
||||
- (void)setBackgroundColor:(UIColor *)color forView:(UIView *)view;
|
||||
|
||||
/**
|
||||
* Sets up layout animation which will perform on next layout pass.
|
||||
* The animation will affect only one next layout pass.
|
||||
* Must be called on the main queue.
|
||||
*/
|
||||
- (void)setNextLayoutAnimationGroup:(RCTLayoutAnimationGroup *)layoutAnimationGroup;
|
||||
|
||||
/**
|
||||
* Schedule a block to be executed on the UI thread. Useful if you need to execute
|
||||
* view logic after all currently queued view updates have completed.
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTDefines.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "RCTLayoutAnimation.h"
|
||||
#import "RCTLayoutAnimationGroup.h"
|
||||
#import "RCTLog.h"
|
||||
#import "RCTModuleData.h"
|
||||
#import "RCTModuleMethod.h"
|
||||
@@ -55,160 +57,6 @@ NSString *const RCTUIManagerDidRegisterRootViewNotification = @"RCTUIManagerDidR
|
||||
NSString *const RCTUIManagerDidRemoveRootViewNotification = @"RCTUIManagerDidRemoveRootViewNotification";
|
||||
NSString *const RCTUIManagerRootViewKey = @"RCTUIManagerRootViewKey";
|
||||
|
||||
@interface RCTAnimation : NSObject
|
||||
|
||||
@property (nonatomic, readonly) NSTimeInterval duration;
|
||||
@property (nonatomic, readonly) NSTimeInterval delay;
|
||||
@property (nonatomic, readonly, copy) NSString *property;
|
||||
@property (nonatomic, readonly) CGFloat springDamping;
|
||||
@property (nonatomic, readonly) CGFloat initialVelocity;
|
||||
@property (nonatomic, readonly) RCTAnimationType animationType;
|
||||
|
||||
@end
|
||||
|
||||
static UIViewAnimationCurve _currentKeyboardAnimationCurve;
|
||||
|
||||
@implementation RCTAnimation
|
||||
|
||||
static UIViewAnimationOptions UIViewAnimationOptionsFromRCTAnimationType(RCTAnimationType type)
|
||||
{
|
||||
switch (type) {
|
||||
case RCTAnimationTypeLinear:
|
||||
return UIViewAnimationOptionCurveLinear;
|
||||
case RCTAnimationTypeEaseIn:
|
||||
return UIViewAnimationOptionCurveEaseIn;
|
||||
case RCTAnimationTypeEaseOut:
|
||||
return UIViewAnimationOptionCurveEaseOut;
|
||||
case RCTAnimationTypeEaseInEaseOut:
|
||||
return UIViewAnimationOptionCurveEaseInOut;
|
||||
case RCTAnimationTypeKeyboard:
|
||||
// http://stackoverflow.com/questions/18870447/how-to-use-the-default-ios7-uianimation-curve
|
||||
return (UIViewAnimationOptions)(_currentKeyboardAnimationCurve << 16);
|
||||
default:
|
||||
RCTLogError(@"Unsupported animation type %zd", type);
|
||||
return UIViewAnimationOptionCurveEaseInOut;
|
||||
}
|
||||
}
|
||||
|
||||
// Use a custom initialization function rather than implementing `+initialize` so that we can control
|
||||
// when the initialization code runs. `+initialize` runs immediately before the first message is sent
|
||||
// to the class which may be too late for us. By this time, we may have missed some
|
||||
// `UIKeyboardWillChangeFrameNotification`s.
|
||||
+ (void)initializeStatics
|
||||
{
|
||||
#if !TARGET_OS_TV
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(keyboardWillChangeFrame:)
|
||||
name:UIKeyboardWillChangeFrameNotification
|
||||
object:nil];
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
+ (void)keyboardWillChangeFrame:(NSNotification *)notification
|
||||
{
|
||||
#if !TARGET_OS_TV
|
||||
NSDictionary *userInfo = notification.userInfo;
|
||||
_currentKeyboardAnimationCurve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (instancetype)initWithDuration:(NSTimeInterval)duration dictionary:(NSDictionary *)config
|
||||
{
|
||||
if (!config) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ((self = [super init])) {
|
||||
_property = [RCTConvert NSString:config[@"property"]];
|
||||
|
||||
_duration = [RCTConvert NSTimeInterval:config[@"duration"]] ?: duration;
|
||||
if (_duration > 0.0 && _duration < 0.01) {
|
||||
RCTLogError(@"RCTLayoutAnimation expects timings to be in ms, not seconds.");
|
||||
_duration = _duration * 1000.0;
|
||||
}
|
||||
|
||||
_delay = [RCTConvert NSTimeInterval:config[@"delay"]];
|
||||
if (_delay > 0.0 && _delay < 0.01) {
|
||||
RCTLogError(@"RCTLayoutAnimation expects timings to be in ms, not seconds.");
|
||||
_delay = _delay * 1000.0;
|
||||
}
|
||||
|
||||
_animationType = [RCTConvert RCTAnimationType:config[@"type"]];
|
||||
if (_animationType == RCTAnimationTypeSpring) {
|
||||
_springDamping = [RCTConvert CGFloat:config[@"springDamping"]];
|
||||
_initialVelocity = [RCTConvert CGFloat:config[@"initialVelocity"]];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)performAnimations:(void (^)(void))animations
|
||||
withCompletionBlock:(void (^)(BOOL completed))completionBlock
|
||||
{
|
||||
if (_animationType == RCTAnimationTypeSpring) {
|
||||
|
||||
[UIView animateWithDuration:_duration
|
||||
delay:_delay
|
||||
usingSpringWithDamping:_springDamping
|
||||
initialSpringVelocity:_initialVelocity
|
||||
options:UIViewAnimationOptionBeginFromCurrentState
|
||||
animations:animations
|
||||
completion:completionBlock];
|
||||
|
||||
} else {
|
||||
|
||||
UIViewAnimationOptions options = UIViewAnimationOptionBeginFromCurrentState |
|
||||
UIViewAnimationOptionsFromRCTAnimationType(_animationType);
|
||||
|
||||
[UIView animateWithDuration:_duration
|
||||
delay:_delay
|
||||
options:options
|
||||
animations:animations
|
||||
completion:completionBlock];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface RCTLayoutAnimation : NSObject
|
||||
|
||||
@property (nonatomic, copy) NSDictionary *config;
|
||||
@property (nonatomic, strong) RCTAnimation *createAnimation;
|
||||
@property (nonatomic, strong) RCTAnimation *updateAnimation;
|
||||
@property (nonatomic, strong) RCTAnimation *deleteAnimation;
|
||||
@property (nonatomic, copy) RCTResponseSenderBlock callback;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTLayoutAnimation
|
||||
|
||||
- (instancetype)initWithDictionary:(NSDictionary *)config callback:(RCTResponseSenderBlock)callback
|
||||
{
|
||||
if (!config) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ((self = [super init])) {
|
||||
_config = [config copy];
|
||||
NSTimeInterval duration = [RCTConvert NSTimeInterval:config[@"duration"]];
|
||||
if (duration > 0.0 && duration < 0.01) {
|
||||
RCTLogError(@"RCTLayoutAnimation expects timings to be in ms, not seconds.");
|
||||
duration = duration * 1000.0;
|
||||
}
|
||||
|
||||
_createAnimation = [[RCTAnimation alloc] initWithDuration:duration dictionary:config[@"create"]];
|
||||
_updateAnimation = [[RCTAnimation alloc] initWithDuration:duration dictionary:config[@"update"]];
|
||||
_deleteAnimation = [[RCTAnimation alloc] initWithDuration:duration dictionary:config[@"delete"]];
|
||||
_callback = callback;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTUIManager
|
||||
{
|
||||
// Root views are only mutated on the shadow queue
|
||||
@@ -216,7 +64,7 @@ static UIViewAnimationOptions UIViewAnimationOptionsFromRCTAnimationType(RCTAnim
|
||||
NSMutableArray<RCTViewManagerUIBlock> *_pendingUIBlocks;
|
||||
|
||||
// Animation
|
||||
RCTLayoutAnimation *_layoutAnimation; // Main thread only
|
||||
RCTLayoutAnimationGroup *_layoutAnimationGroup; // Main thread only
|
||||
NSMutableSet<UIView *> *_viewsToBeDeleted; // Main thread only
|
||||
|
||||
NSMutableDictionary<NSNumber *, RCTShadowView *> *_shadowViewRegistry; // RCT thread only
|
||||
@@ -326,7 +174,7 @@ RCT_EXPORT_MODULE()
|
||||
selector:@selector(didReceiveNewContentSizeMultiplier)
|
||||
name:RCTAccessibilityManagerDidUpdateMultiplierNotification
|
||||
object:_bridge.accessibilityManager];
|
||||
[RCTAnimation initializeStatics];
|
||||
[RCTLayoutAnimation initializeStatics];
|
||||
}
|
||||
|
||||
dispatch_queue_t RCTGetUIManagerQueue(void)
|
||||
@@ -559,6 +407,19 @@ BOOL RCTIsUIManagerQueue()
|
||||
[_pendingUIBlocks insertObject:block atIndex:0];
|
||||
}
|
||||
|
||||
- (void)setNextLayoutAnimationGroup:(RCTLayoutAnimationGroup *)layoutAnimationGroup
|
||||
{
|
||||
RCTAssertMainQueue();
|
||||
|
||||
if (_layoutAnimationGroup && ![_layoutAnimationGroup isEqual:layoutAnimationGroup]) {
|
||||
RCTLogWarn(@"Warning: Overriding previous layout animation with new one before the first began:\n%@ -> %@.",
|
||||
[_layoutAnimationGroup description],
|
||||
[layoutAnimationGroup description]);
|
||||
}
|
||||
|
||||
_layoutAnimationGroup = layoutAnimationGroup;
|
||||
}
|
||||
|
||||
- (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTRootShadowView *)rootShadowView
|
||||
{
|
||||
RCTAssert(!RCTIsMainQueue(), @"Should be called on shadow queue");
|
||||
@@ -649,7 +510,7 @@ BOOL RCTIsUIManagerQueue()
|
||||
return ^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
|
||||
|
||||
const RCTFrameData *frameDataArray = (const RCTFrameData *)framesData.bytes;
|
||||
RCTLayoutAnimation *layoutAnimation = uiManager->_layoutAnimation;
|
||||
RCTLayoutAnimationGroup *layoutAnimationGroup = uiManager->_layoutAnimationGroup;
|
||||
|
||||
__block NSUInteger completionsCalled = 0;
|
||||
|
||||
@@ -663,18 +524,18 @@ BOOL RCTIsUIManagerQueue()
|
||||
BOOL isHidden = frameData.isHidden;
|
||||
UIUserInterfaceLayoutDirection layoutDirection = frameData.layoutDirection;
|
||||
BOOL isNew = frameData.isNew;
|
||||
RCTAnimation *updateAnimation = isNew ? nil : layoutAnimation.updateAnimation;
|
||||
RCTLayoutAnimation *updatingLayoutAnimation = isNew ? nil : layoutAnimationGroup.updatingLayoutAnimation;
|
||||
BOOL shouldAnimateCreation = isNew && !frameData.parentIsNew;
|
||||
RCTAnimation *createAnimation = shouldAnimateCreation ? layoutAnimation.createAnimation : nil;
|
||||
RCTLayoutAnimation *creatingLayoutAnimation = shouldAnimateCreation ? layoutAnimationGroup.creatingLayoutAnimation : nil;
|
||||
|
||||
void (^completion)(BOOL) = ^(BOOL finished) {
|
||||
completionsCalled++;
|
||||
if (layoutAnimation.callback && completionsCalled == count) {
|
||||
layoutAnimation.callback(@[@(finished)]);
|
||||
if (layoutAnimationGroup.callback && completionsCalled == count) {
|
||||
layoutAnimationGroup.callback(@[@(finished)]);
|
||||
|
||||
// It's unsafe to call this callback more than once, so we nil it out here
|
||||
// to make sure that doesn't happen.
|
||||
layoutAnimation.callback = nil;
|
||||
layoutAnimationGroup.callback = nil;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -687,7 +548,7 @@ BOOL RCTIsUIManagerQueue()
|
||||
}
|
||||
|
||||
RCTViewManagerUIBlock updateBlock = updateBlocks[reactTag];
|
||||
if (createAnimation) {
|
||||
if (creatingLayoutAnimation) {
|
||||
|
||||
// Animate view creation
|
||||
[view reactSetFrame:frame];
|
||||
@@ -695,17 +556,17 @@ BOOL RCTIsUIManagerQueue()
|
||||
CATransform3D finalTransform = view.layer.transform;
|
||||
CGFloat finalOpacity = view.layer.opacity;
|
||||
|
||||
NSString *property = createAnimation.property;
|
||||
NSString *property = creatingLayoutAnimation.property;
|
||||
if ([property isEqualToString:@"scaleXY"]) {
|
||||
view.layer.transform = CATransform3DMakeScale(0, 0, 0);
|
||||
} else if ([property isEqualToString:@"opacity"]) {
|
||||
view.layer.opacity = 0.0;
|
||||
} else {
|
||||
RCTLogError(@"Unsupported layout animation createConfig property %@",
|
||||
createAnimation.property);
|
||||
creatingLayoutAnimation.property);
|
||||
}
|
||||
|
||||
[createAnimation performAnimations:^{
|
||||
[creatingLayoutAnimation performAnimations:^{
|
||||
if ([property isEqualToString:@"scaleXY"]) {
|
||||
view.layer.transform = finalTransform;
|
||||
} else if ([property isEqualToString:@"opacity"]) {
|
||||
@@ -716,10 +577,10 @@ BOOL RCTIsUIManagerQueue()
|
||||
}
|
||||
} withCompletionBlock:completion];
|
||||
|
||||
} else if (updateAnimation) {
|
||||
} else if (updatingLayoutAnimation) {
|
||||
|
||||
// Animate view update
|
||||
[updateAnimation performAnimations:^{
|
||||
[updatingLayoutAnimation performAnimations:^{
|
||||
[view reactSetFrame:frame];
|
||||
if (updateBlock) {
|
||||
updateBlock(self, viewRegistry);
|
||||
@@ -738,7 +599,7 @@ BOOL RCTIsUIManagerQueue()
|
||||
}
|
||||
|
||||
// Clean up
|
||||
uiManager->_layoutAnimation = nil;
|
||||
uiManager->_layoutAnimationGroup = nil;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -823,10 +684,10 @@ RCT_EXPORT_METHOD(removeSubviewsFromContainerWithID:(nonnull NSNumber *)containe
|
||||
*/
|
||||
- (void)_removeChildren:(NSArray<UIView *> *)children
|
||||
fromContainer:(UIView *)container
|
||||
withAnimation:(RCTLayoutAnimation *)animation
|
||||
withAnimation:(RCTLayoutAnimationGroup *)animation
|
||||
{
|
||||
RCTAssertMainQueue();
|
||||
RCTAnimation *deleteAnimation = animation.deleteAnimation;
|
||||
RCTLayoutAnimation *deletingLayoutAnimation = animation.deletingLayoutAnimation;
|
||||
|
||||
__block NSUInteger completionsCalled = 0;
|
||||
for (UIView *removedChild in children) {
|
||||
@@ -852,15 +713,15 @@ RCT_EXPORT_METHOD(removeSubviewsFromContainerWithID:(nonnull NSNumber *)containe
|
||||
// the view events anyway.
|
||||
removedChild.userInteractionEnabled = NO;
|
||||
|
||||
NSString *property = deleteAnimation.property;
|
||||
[deleteAnimation performAnimations:^{
|
||||
NSString *property = deletingLayoutAnimation.property;
|
||||
[deletingLayoutAnimation performAnimations:^{
|
||||
if ([property isEqualToString:@"scaleXY"]) {
|
||||
removedChild.layer.transform = CATransform3DMakeScale(0.001, 0.001, 0.001);
|
||||
} else if ([property isEqualToString:@"opacity"]) {
|
||||
removedChild.layer.opacity = 0.0;
|
||||
} else {
|
||||
RCTLogError(@"Unsupported layout animation createConfig property %@",
|
||||
deleteAnimation.property);
|
||||
deletingLayoutAnimation.property);
|
||||
}
|
||||
} withCompletionBlock:completion];
|
||||
}
|
||||
@@ -985,10 +846,10 @@ RCT_EXPORT_METHOD(manageChildren:(nonnull NSNumber *)containerTag
|
||||
[self _childrenToRemoveFromContainer:container atIndices:moveFromIndices];
|
||||
|
||||
BOOL isUIViewRegistry = ((id)registry == (id)_viewRegistry);
|
||||
if (isUIViewRegistry && _layoutAnimation.deleteAnimation) {
|
||||
if (isUIViewRegistry && _layoutAnimationGroup.deletingLayoutAnimation) {
|
||||
[self _removeChildren:(NSArray<UIView *> *)permanentlyRemovedChildren
|
||||
fromContainer:(UIView *)container
|
||||
withAnimation:_layoutAnimation];
|
||||
withAnimation:_layoutAnimationGroup];
|
||||
} else {
|
||||
[self _removeChildren:permanentlyRemovedChildren fromContainer:container];
|
||||
}
|
||||
@@ -1587,18 +1448,12 @@ RCT_EXPORT_METHOD(configureNextLayoutAnimation:(NSDictionary *)config
|
||||
withCallback:(RCTResponseSenderBlock)callback
|
||||
errorCallback:(__unused RCTResponseSenderBlock)errorCallback)
|
||||
{
|
||||
RCTLayoutAnimation *currentAnimation = _layoutAnimation;
|
||||
RCTLayoutAnimationGroup *layoutAnimationGroup =
|
||||
[[RCTLayoutAnimationGroup alloc] initWithConfig:config
|
||||
callback:callback];
|
||||
|
||||
if (currentAnimation && ![config isEqualToDictionary:currentAnimation.config]) {
|
||||
RCTLogWarn(@"Warning: Overriding previous layout animation with new one before the first began:\n%@ -> %@.", currentAnimation.config, config);
|
||||
}
|
||||
|
||||
RCTLayoutAnimation *nextLayoutAnimation = [[RCTLayoutAnimation alloc] initWithDictionary:config
|
||||
callback:callback];
|
||||
|
||||
// Set up next layout animation
|
||||
[self addUIBlock:^(RCTUIManager *uiManager, __unused NSDictionary<NSNumber *, UIView *> *viewRegistry) {
|
||||
uiManager->_layoutAnimation = nextLayoutAnimation;
|
||||
[uiManager setNextLayoutAnimationGroup:layoutAnimationGroup];
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user