This commit is contained in:
Yamozha
2021-04-02 02:24:13 +03:00
parent c23950b545
commit 7256d79e2c
31493 changed files with 3036630 additions and 0 deletions

View File

@ -0,0 +1,12 @@
#import <React/RCTConvert.h>
#import "REATransition.h"
@interface RCTConvert (REATransition)
+ (REATransitionType)REATransitionType:(id)json;
+ (REATransitionAnimationType)REATransitionAnimationType:(id)json;
+ (REATransitionInterpolationType)REATransitionInterpolationType:(id)json;
+ (REATransitionPropagationType)REATransitionPropagationType:(id)json;
@end

View File

@ -0,0 +1,37 @@
#import "RCTConvert+REATransition.h"
@implementation RCTConvert (REATransition)
RCT_ENUM_CONVERTER(REATransitionType, (@{
@"none": @(REATransitionTypeNone),
@"group": @(REATransitionTypeGroup),
@"in": @(REATransitionTypeIn),
@"out": @(REATransitionTypeOut),
@"change": @(REATransitionTypeChange),
}), REATransitionTypeNone, integerValue)
RCT_ENUM_CONVERTER(REATransitionAnimationType, (@{
@"none": @(REATransitionAnimationTypeNone),
@"fade": @(REATransitionAnimationTypeFade),
@"scale": @(REATransitionAnimationTypeScale),
@"slide-top": @(REATransitionAnimationTypeSlideTop),
@"slide-bottom": @(REATransitionAnimationTypeSlideBottom),
@"slide-right": @(REATransitionAnimationTypeSlideRight),
@"slide-left": @(REATransitionAnimationTypeSlideLeft)
}), REATransitionAnimationTypeNone, integerValue)
RCT_ENUM_CONVERTER(REATransitionInterpolationType, (@{
@"linear": @(REATransitionInterpolationLinear),
@"easeIn": @(REATransitionInterpolationEaseIn),
@"easeOut": @(REATransitionInterpolationEaseOut),
@"easeInOut": @(REATransitionInterpolationEaseInOut),
}), REATransitionInterpolationLinear, integerValue)
RCT_ENUM_CONVERTER(REATransitionPropagationType, (@{
@"none": @(REATransitionPropagationNone),
@"top": @(REATransitionPropagationTop),
@"bottom": @(REATransitionPropagationBottom),
@"left": @(REATransitionPropagationLeft),
@"right": @(REATransitionPropagationRight)
}), REATransitionPropagationNone, integerValue)
@end

View File

@ -0,0 +1,26 @@
#import "REATransition.h"
@interface REATransitionGroup : REATransition
@property (nonatomic) BOOL sequence;
@property (nonatomic) NSArray *transitions;
- (instancetype)initWithConfig:(NSDictionary *)config;
@end
@interface REAVisibilityTransition : REATransition
@property (nonatomic) REATransitionAnimationType animationType;
- (REATransitionAnimation *)appearView:(UIView*)view inParent:(UIView*)parent;
- (REATransitionAnimation *)disappearView:(UIView*)view fromParent:(UIView*)parent;
- (instancetype)initWithConfig:(NSDictionary *)config;
@end
@interface REAInTransition : REAVisibilityTransition
- (instancetype)initWithConfig:(NSDictionary *)config;
@end
@interface REAOutTransition : REAVisibilityTransition
- (instancetype)initWithConfig:(NSDictionary *)config;
@end
@interface REAChangeTransition : REATransition
- (instancetype)initWithConfig:(NSDictionary *)config;
@end

View File

@ -0,0 +1,308 @@
#import <React/RCTViewManager.h>
#import "REAAllTransitions.h"
#import "RCTConvert+REATransition.h"
@interface REASnapshotRemover : NSObject <CAAnimationDelegate>
@end
@implementation REASnapshotRemover {
UIView *_view;
}
- (instancetype)initWithView:(UIView *)view;
{
self = [super init];
if (self) {
_view = view;
}
return self;
}
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
[_view removeFromSuperview];
}
@end
@implementation REATransitionGroup
- (instancetype)initWithConfig:(NSDictionary *)config
{
if (self = [super initWithConfig:config]) {
_sequence = [RCTConvert BOOL:config[@"sequence"]];
NSArray *transitions = [RCTConvert NSArray:config[@"transitions"]];
NSMutableArray<REATransition*> *inflated = [NSMutableArray new];
for (NSDictionary *transitionConfig in transitions) {
[inflated addObject:[REATransition inflate:transitionConfig]];
inflated.lastObject.parent = self;
}
_transitions = inflated;
}
return self;
}
- (instancetype)init
{
if (self = [super init]) {
_transitions = [NSMutableArray new];
}
return self;
}
- (NSArray<REATransitionAnimation *> *)animationsForTransitioning:(NSMutableDictionary<NSNumber *,REATransitionValues *> *)startValues
endValues:(NSMutableDictionary<NSNumber *,REATransitionValues *> *)endValues
forRoot:(UIView *)root
{
CFTimeInterval delay = self.delay;
NSMutableArray *animations = [NSMutableArray new];
for (REATransition *transition in _transitions) {
NSArray *subanims = [transition animationsForTransitioning:startValues endValues:endValues forRoot:root];
CFTimeInterval finishTime = CACurrentMediaTime();
for (REATransitionAnimation *anim in subanims) {
[anim delayBy:delay];
finishTime = MAX(finishTime, anim.finishTime);
}
[animations addObjectsFromArray:subanims];
if (_sequence) {
delay = finishTime - CACurrentMediaTime();
}
}
return animations;
}
@end
@implementation REAVisibilityTransition
- (instancetype)initWithConfig:(NSDictionary *)config
{
if (self = [super initWithConfig:config]) {
_animationType = [RCTConvert REATransitionAnimationType:config[@"animation"]];
}
return self;
}
- (REATransitionAnimation *)appearView:(UIView *)view
inParent:(UIView *)parent
forRoot:(UIView *)root
{
return nil;
}
- (REATransitionAnimation *)disappearView:(UIView *)view
fromParent:(UIView *)parent
forRoot:(UIView *)root
{
return nil;
}
- (REATransitionAnimation *)animationForTransitioning:(REATransitionValues *)startValues
endValues:(REATransitionValues *)endValues
forRoot:(UIView *)root
{
BOOL isViewAppearing = (startValues == nil);
if (isViewAppearing && !IS_LAYOUT_ONLY(endValues.view)) {
NSNumber *parentKey = endValues.reactParent.reactTag;
REATransitionValues *parentStartValues = [self findStartValuesForKey:parentKey];
REATransitionValues *parentEndValues = [self findEndValuesForKey:parentKey];
BOOL isParentAppearing = (parentStartValues == nil && parentEndValues != nil);
if (!isParentAppearing) {
return [self appearView:endValues.view inParent:endValues.parent forRoot:root];
}
}
if (endValues == nil && !IS_LAYOUT_ONLY(startValues.view) && startValues.reactParent.window != nil) {
startValues.view.center = startValues.centerInReactParent;
return [self disappearView:startValues.view fromParent:startValues.reactParent forRoot:root];
}
return nil;
}
@end
@implementation REAInTransition
- (instancetype)initWithConfig:(NSDictionary *)config
{
if (self = [super initWithConfig:config]) {
}
return self;
}
- (REATransitionAnimation *)appearView:(UIView *)view
inParent:(UIView *)parent
forRoot:(UIView *)root
{
CABasicAnimation *animation;
switch (self.animationType) {
case REATransitionAnimationTypeNone:
return nil;
case REATransitionAnimationTypeFade: {
CGFloat finalOpacity = view.layer.opacity;
animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
animation.fromValue = @(0.0f);
animation.toValue = @(finalOpacity);
break;
}
case REATransitionAnimationTypeScale: {
CATransform3D finalTransform = view.layer.transform;
animation = [CABasicAnimation animationWithKeyPath:@"transform"];
animation.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.0, 0.0, 0)];
animation.toValue = [NSValue valueWithCATransform3D:finalTransform];
break;
}
case REATransitionAnimationTypeSlideTop:
case REATransitionAnimationTypeSlideBottom:
case REATransitionAnimationTypeSlideLeft:
case REATransitionAnimationTypeSlideRight: {
CGPoint finalPosition = view.layer.position;
CGPoint startPosition = finalPosition;
switch (self.animationType) {
case REATransitionAnimationTypeSlideTop:
startPosition.y -= root.frame.size.height;
break;
case REATransitionAnimationTypeSlideBottom:
startPosition.y += root.frame.size.height;
break;
case REATransitionAnimationTypeSlideLeft:
startPosition.x -= root.frame.size.width;
break;
case REATransitionAnimationTypeSlideRight:
startPosition.x += root.frame.size.width;
break;
}
animation = [CABasicAnimation animationWithKeyPath:@"position"];
animation.fromValue = @(startPosition);
animation.toValue = @(finalPosition);
break;
}
}
animation.fillMode = kCAFillModeBackwards;
return [REATransitionAnimation transitionWithAnimation:animation layer:view.layer andKeyPath:animation.keyPath];
}
@end
@implementation REAOutTransition
- (instancetype)initWithConfig:(NSDictionary *)config
{
if (self = [super initWithConfig:config]) {
}
return self;
}
- (REATransitionAnimation *)disappearView:(UIView *)view
fromParent:(UIView *)parent
forRoot:(UIView *)root
{
if (self.animationType == REATransitionAnimationTypeNone) {
return nil;
}
// Add view back to parent temporarily in order to take snapshot
[parent addSubview:view];
UIView *snapshotView = [view snapshotViewAfterScreenUpdates:NO];
[view removeFromSuperview];
snapshotView.frame = view.frame;
[parent addSubview:snapshotView];
CALayer *snapshot = snapshotView.layer;
CABasicAnimation *animation;
switch (self.animationType) {
case REATransitionAnimationTypeFade: {
CGFloat fromValue = snapshot.opacity;
snapshot.opacity = 0.0f;
animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
animation.fromValue = @(fromValue);
animation.toValue = @(0.0f);
break;
}
case REATransitionAnimationTypeScale: {
CATransform3D fromValue = snapshot.transform;
snapshot.transform = CATransform3DMakeScale(0.001, 0.001, 0.001);
animation = [CABasicAnimation animationWithKeyPath:@"transform"];
animation.fromValue = [NSValue valueWithCATransform3D:fromValue];
animation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.001, 0.001, 0.001)];
break;
}
case REATransitionAnimationTypeSlideTop:
case REATransitionAnimationTypeSlideBottom:
case REATransitionAnimationTypeSlideLeft:
case REATransitionAnimationTypeSlideRight: {
CGPoint startPosition = snapshot.position;
CGPoint finalPosition = startPosition;
switch (self.animationType) {
case REATransitionAnimationTypeSlideTop:
finalPosition.y -= root.frame.size.height;
break;
case REATransitionAnimationTypeSlideBottom:
finalPosition.y += root.frame.size.height;
break;
case REATransitionAnimationTypeSlideLeft:
finalPosition.x -= root.frame.size.width;
break;
case REATransitionAnimationTypeSlideRight:
finalPosition.x += root.frame.size.width;
break;
}
snapshot.position = finalPosition;
animation = [CABasicAnimation animationWithKeyPath:@"position"];
animation.fromValue = @(startPosition);
animation.toValue = @(finalPosition);
break;
}
}
animation.fillMode = kCAFillModeBackwards;
animation.delegate = [[REASnapshotRemover alloc] initWithView:snapshotView];
return [REATransitionAnimation transitionWithAnimation:animation layer:snapshot andKeyPath:animation.keyPath];
}
@end
@implementation REAChangeTransition
- (REATransitionAnimation *)animationForTransitioning:(REATransitionValues *)startValues
endValues:(REATransitionValues *)endValues
forRoot:(UIView *)root
{
if (startValues == nil || endValues == nil || endValues.view.window == nil) {
return nil;
}
BOOL animatePosition = !CGPointEqualToPoint(startValues.center, endValues.center);
BOOL animateBounds = !CGRectEqualToRect(startValues.bounds, endValues.bounds);
if (!animatePosition && !animateBounds) {
return nil;
}
CALayer *layer = endValues.view.layer;
CAAnimationGroup *group = [CAAnimationGroup animation];
group.fillMode = kCAFillModeBackwards;
NSMutableArray *animations = [NSMutableArray new];
if (animatePosition) {
CGPoint fromValue = layer.presentationLayer.position;
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
animation.fromValue = [NSValue valueWithCGPoint:fromValue];
animation.toValue = [NSValue valueWithCGPoint:endValues.center];
[animations addObject:animation];
}
if (animateBounds) {
CGRect fromValue = layer.presentationLayer.bounds;
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"bounds"];
animation.fromValue = [NSValue valueWithCGRect:fromValue];
animation.toValue = [NSValue valueWithCGRect:endValues.bounds];
[animations addObject:animation];
}
group.animations = animations;
return [REATransitionAnimation transitionWithAnimation:group layer:layer andKeyPath:nil];
}
@end

View File

@ -0,0 +1,64 @@
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#import <React/RCTView.h>
#import "REATransitionAnimation.h"
#import "REATransitionValues.h"
// TODO: fix below implementation
#define IS_LAYOUT_ONLY(view) ([view isKindOfClass:[RCTView class]] && view.backgroundColor == nil)
typedef NS_ENUM(NSInteger, REATransitionType) {
REATransitionTypeNone = 0,
REATransitionTypeGroup,
REATransitionTypeIn,
REATransitionTypeOut,
REATransitionTypeChange
};
typedef NS_ENUM(NSInteger, REATransitionAnimationType) {
REATransitionAnimationTypeNone = 0,
REATransitionAnimationTypeFade,
REATransitionAnimationTypeScale,
REATransitionAnimationTypeSlideTop,
REATransitionAnimationTypeSlideBottom,
REATransitionAnimationTypeSlideRight,
REATransitionAnimationTypeSlideLeft,
};
typedef NS_ENUM(NSInteger, REATransitionInterpolationType) {
REATransitionInterpolationLinear = 0,
REATransitionInterpolationEaseIn,
REATransitionInterpolationEaseOut,
REATransitionInterpolationEaseInOut,
};
typedef NS_ENUM(NSInteger, REATransitionPropagationType) {
REATransitionPropagationNone = 0,
REATransitionPropagationTop,
REATransitionPropagationBottom,
REATransitionPropagationLeft,
REATransitionPropagationRight,
};
@interface REATransition : NSObject
@property (nonatomic, weak) REATransition *parent;
@property (nonatomic) CFTimeInterval duration;
@property (nonatomic) CFTimeInterval delay;
@property (nonatomic) REATransitionInterpolationType interpolation;
@property (nonatomic) REATransitionPropagationType propagation;
- (instancetype)initWithConfig:(NSDictionary *)config;
- (CAMediaTimingFunction *)mediaTiming;
- (void)startCaptureInRoot:(UIView *)root;
- (void)playInRoot:(UIView *)root;
- (REATransitionValues *)findStartValuesForKey:(NSNumber *)key;
- (REATransitionValues *)findEndValuesForKey:(NSNumber *)key;
- (REATransitionAnimation *)animationForTransitioning:(REATransitionValues*)startValues
endValues:(REATransitionValues*)endValues
forRoot:(UIView *)root;
- (NSArray<REATransitionAnimation*> *)animationsForTransitioning:(NSMutableDictionary<NSNumber*, REATransitionValues*> *)startValues
endValues:(NSMutableDictionary<NSNumber*, REATransitionValues*> *)endValues
forRoot:(UIView *)root;
+ (REATransition *)inflate:(NSDictionary *)config;
@end

View File

@ -0,0 +1,208 @@
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#import <React/RCTConvert.h>
#import <React/RCTViewManager.h>
#import "REATransition.h"
#import "REATransitionValues.h"
#import "RCTConvert+REATransition.h"
#define DEFAULT_PROPAGATION_SPEED 3
@interface REATransitionGroup : REATransition
@property (nonatomic) BOOL sequence;
@property (nonatomic) NSArray *transitions;
- (instancetype)initWithConfig:(NSDictionary *)config;
@end
@interface REAVisibilityTransition : REATransition
@property (nonatomic) REATransitionAnimationType animationType;
- (REATransitionAnimation *)appearView:(UIView*)view inParent:(UIView*)parent;
- (REATransitionAnimation *)disappearView:(UIView*)view fromParent:(UIView*)parent;
- (instancetype)initWithConfig:(NSDictionary *)config;
@end
@interface REAInTransition : REAVisibilityTransition
- (instancetype)initWithConfig:(NSDictionary *)config;
@end
@interface REAOutTransition : REAVisibilityTransition
- (instancetype)initWithConfig:(NSDictionary *)config;
@end
@interface REAChangeTransition : REATransition
- (instancetype)initWithConfig:(NSDictionary *)config;
@end
@implementation REATransition {
__weak UIView *_root;
NSMutableDictionary<NSNumber*, REATransitionValues*> *_startValues;
NSMutableDictionary<NSNumber*, REATransitionValues*> *_endValues;
}
+ (REATransition *)inflate:(NSDictionary *)config
{
REATransitionType type = [RCTConvert REATransitionType:config[@"type"]];
switch (type) {
case REATransitionTypeGroup:
return [[REATransitionGroup alloc] initWithConfig:config];
case REATransitionTypeIn:
return [[REAInTransition alloc] initWithConfig:config];
case REATransitionTypeOut:
return [[REAOutTransition alloc] initWithConfig:config];
case REATransitionTypeChange:
return [[REAChangeTransition alloc] initWithConfig:config];
case REATransitionTypeNone:
default:
RCTLogError(@"Invalid transitioning type %@", config[@"type"]);
}
return nil;
}
- (instancetype)initWithConfig:(NSDictionary *)config
{
if (self = [super init]) {
_duration = [RCTConvert double:config[@"durationMs"]] / 1000.0;
_delay = [RCTConvert double:config[@"delayMs"]] / 1000.0;
_interpolation = [RCTConvert REATransitionInterpolationType:config[@"interpolation"]];
_propagation = [RCTConvert REATransitionPropagationType:config[@"propagation"]];
}
return self;
}
- (void)captureRecursiveIn:(UIView *)view to:(NSMutableDictionary<NSNumber*, REATransitionValues*> *)map forRoot:(UIView *)root
{
NSNumber *tag = view.reactTag;
if (tag != nil) {
map[tag] = [[REATransitionValues alloc] initWithView:view forRoot:root];
for (UIView *subview in view.reactSubviews) {
[self captureRecursiveIn:subview to:map forRoot:root];
}
}
}
- (void)startCaptureInRoot:(UIView *)root
{
_startValues = [NSMutableDictionary new];
[self captureRecursiveIn:root to:_startValues forRoot:root];
}
- (void)playInRoot:(UIView *)root
{
_endValues = [NSMutableDictionary new];
[self captureRecursiveIn:root to:_endValues forRoot:root];
NSArray *animations = [self animationsForTransitioning:_startValues
endValues:_endValues
forRoot:root];
for (REATransitionAnimation *animation in animations) {
[animation play];
}
_startValues = nil;
_endValues = nil;
}
- (REATransitionValues *)findStartValuesForKey:(NSNumber *)key
{
if (_parent != nil) {
return [_parent findStartValuesForKey:key];
}
return _startValues[key];
}
- (REATransitionValues *)findEndValuesForKey:(NSNumber *)key
{
if (_parent != nil) {
return [_parent findEndValuesForKey:key];
}
return _endValues[key];
}
- (CFTimeInterval)propagationDelayForTransitioning:(REATransitionValues *)startValues
endValues:(REATransitionValues *)endValues
forRoot:(UIView *)root
{
if (self.propagation == REATransitionPropagationNone) {
return 0.;
}
REATransitionValues *values = endValues;
if (values == nil) {
values = startValues;
}
double fraction = 0.;
switch (self.propagation) {
case REATransitionPropagationLeft:
fraction = values.centerRelativeToRoot.x / root.layer.bounds.size.width;
break;
case REATransitionPropagationRight:
fraction = 1. - values.centerRelativeToRoot.x / root.layer.bounds.size.width;
break;
case REATransitionPropagationTop:
fraction = values.centerRelativeToRoot.y / root.layer.bounds.size.height;
break;
case REATransitionPropagationBottom:
fraction = 1. - values.centerRelativeToRoot.y / root.layer.bounds.size.height;
break;
}
return _duration * MIN(MAX(0., fraction), 1.) / DEFAULT_PROPAGATION_SPEED;
}
- (CAMediaTimingFunction *)mediaTiming
{
switch (self.interpolation) {
case REATransitionInterpolationLinear:
return [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
case REATransitionInterpolationEaseIn:
return [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
case REATransitionInterpolationEaseOut:
return [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
case REATransitionInterpolationEaseInOut:
return [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
}
}
- (REATransitionAnimation *)animationForTransitioning:(REATransitionValues *)startValues
endValues:(REATransitionValues *)endValues
forRoot:(UIView *)root
{
return nil;
}
- (NSArray<REATransitionAnimation*> *)animationsForTransitioning:(NSMutableDictionary<NSNumber *,REATransitionValues *> *)startValues
endValues:(NSMutableDictionary<NSNumber *,REATransitionValues *> *)endValues
forRoot:(UIView *)root
{
NSMutableArray *animations = [NSMutableArray new];
[startValues enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, REATransitionValues *startValue, BOOL *stop) {
REATransitionValues *endValue = endValues[key];
REATransitionAnimation *animation = [self animationForTransitioning:startValue endValues:endValue forRoot:root];
if (animation != nil) {
animation.animation.timingFunction = self.mediaTiming;
animation.animation.duration = self.duration;
[animation delayBy:self.delay];
CFTimeInterval propagationDelay = [self propagationDelayForTransitioning:startValue endValues:endValue forRoot:root];
[animation delayBy:propagationDelay];
// animation.animation.duration -= propagationDelay;
[animations addObject:animation];
}
}];
[endValues enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, REATransitionValues *endValue, BOOL *stop) {
if (startValues[key] == nil) {
REATransitionAnimation *animation = [self animationForTransitioning:nil endValues:endValue forRoot:root];
if (animation != nil) {
animation.animation.timingFunction = self.mediaTiming;
animation.animation.duration = self.duration;
[animation delayBy:self.delay];
CFTimeInterval propagationDelay = [self propagationDelayForTransitioning:nil endValues:endValue forRoot:root];
[animation delayBy:propagationDelay];
// animation.animation.duration -= propagationDelay;
[animations addObject:animation];
}
}
}];
return animations;
}
@end

View File

@ -0,0 +1,17 @@
#import <Foundation/Foundation.h>
@interface REATransitionAnimation : NSObject
@property (nonatomic) CAAnimation *animation;
@property (nonatomic) CALayer *layer;
@property (nonatomic) NSString *keyPath;
+ (REATransitionAnimation *)transitionWithAnimation:(CAAnimation *)animation
layer:(CALayer *)layer
andKeyPath:(NSString*)keyPath;
- (void)play;
- (void)delayBy:(CFTimeInterval)delay;
- (CFTimeInterval)finishTime;
- (CFTimeInterval)duration;
@end

View File

@ -0,0 +1,81 @@
#import <UIKit/UIKit.h>
#import "REATransitionAnimation.h"
#define DEFAULT_DURATION 0.25
#if TARGET_IPHONE_SIMULATOR
// Based on https://stackoverflow.com/a/13307674
float UIAnimationDragCoefficient(void);
#endif
CGFloat SimAnimationDragCoefficient()
{
#if TARGET_IPHONE_SIMULATOR
if (NSClassFromString(@"XCTest") != nil) {
// UIAnimationDragCoefficient is 10.0 in tests for some reason, but
// we need it to be 1.0.
return 1.0;
} else {
return (CGFloat)UIAnimationDragCoefficient();
}
#else
return 1.0;
#endif
}
@implementation REATransitionAnimation {
NSTimeInterval _delay;
}
+ (REATransitionAnimation *)transitionWithAnimation:(CAAnimation *)animation
layer:(CALayer *)layer
andKeyPath:(NSString*)keyPath;
{
REATransitionAnimation *anim = [REATransitionAnimation new];
anim.animation = animation;
anim.layer = layer;
anim.keyPath = keyPath;
return anim;
}
- (void)play
{
/*
CACurrentMediaTime introduces some kind of delay even if _delay is set to 0
it calls mach_absolute_time() which is based on the last time the device booted
which might cause the delay
*/
if (_delay > 0){
_animation.beginTime = CACurrentMediaTime() + _delay * SimAnimationDragCoefficient();
}
_animation.duration = self.duration * SimAnimationDragCoefficient();
[_layer addAnimation:_animation forKey:_keyPath];
}
- (void)delayBy:(CFTimeInterval)delay
{
if (delay <= 0) {
return;
}
_delay += delay;
}
- (CFTimeInterval)duration
{
if (_animation.duration == 0) {
return DEFAULT_DURATION;
}
return _animation.duration;
}
- (CFTimeInterval)finishTime
{
if (_animation.beginTime == 0) {
return CACurrentMediaTime() + self.duration + _delay;
}
return _animation.beginTime + self.duration + _delay;
}
@end

View File

@ -0,0 +1,9 @@
#import <Foundation/Foundation.h>
#import <React/RCTUIManager.h>
@interface REATransitionManager : NSObject
- (instancetype)initWithUIManager:(RCTUIManager *)uiManager;
- (void)animateNextTransitionInRoot:(nonnull NSNumber *)reactTag withConfig:(NSDictionary *)config;
@end

View File

@ -0,0 +1,62 @@
#import "REATransitionManager.h"
#import <React/RCTUIManager.h>
#import <React/RCTUIManagerObserverCoordinator.h>
#import "REATransition.h"
@interface REATransitionManager () <RCTUIManagerObserver>
@end
@implementation REATransitionManager {
REATransition *_pendingTransition;
UIView *_pendingTransitionRoot;
RCTUIManager *_uiManager;
}
- (instancetype)initWithUIManager:(id)uiManager
{
if (self = [super init]) {
_uiManager = uiManager;
}
return self;
}
- (void)beginTransition:(REATransition *)transition forView:(UIView *)view
{
RCTAssertMainQueue();
if (_pendingTransition != nil) {
return;
}
_pendingTransition = transition;
_pendingTransitionRoot = view;
[transition startCaptureInRoot:view];
}
- (void)uiManagerWillPerformMounting:(RCTUIManager *)manager
{
[manager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *,UIView *> *viewRegistry) {
[_pendingTransition playInRoot:_pendingTransitionRoot];
_pendingTransitionRoot = nil;
_pendingTransition = nil;
}];
}
- (void)animateNextTransitionInRoot:(NSNumber *)reactTag withConfig:(NSDictionary *)config
{
[_uiManager.observerCoordinator addObserver:self];
[_uiManager prependUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *,UIView *> *viewRegistry) {
UIView *view = viewRegistry[reactTag];
NSArray *transitionConfigs = [RCTConvert NSArray:config[@"transitions"]];
for (id transitionConfig in transitionConfigs) {
REATransition *transition = [REATransition inflate:transitionConfig];
[self beginTransition:transition forView:view];
}
}];
__weak id weakSelf = self;
[_uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *,UIView *> *viewRegistry) {
[uiManager.observerCoordinator removeObserver:weakSelf];
}];
}
@end

View File

@ -0,0 +1,15 @@
#import <UIKit/UIKit.h>
@interface REATransitionValues : NSObject
@property (nonatomic) CGPoint center;
@property (nonatomic) CGRect bounds;
@property (nonatomic) CGPoint centerRelativeToRoot;
@property (nonatomic, retain) UIView *view;
@property (nonatomic, retain) UIView *parent;
@property (nonatomic, retain) UIView *reactParent;
@property (nonatomic) CGPoint centerInReactParent;
- (instancetype)initWithView:(UIView *)view forRoot:(UIView *)root;
@end

View File

@ -0,0 +1,26 @@
#import <React/RCTView.h>
#import <React/RCTViewManager.h>
#import "REATransition.h"
#import "REATransitionValues.h"
@implementation REATransitionValues
- (instancetype)initWithView:(UIView *)view forRoot:(UIView *)root
{
if (self = [super init]) {
_view = view;
_parent = view.superview;
_reactParent = view.reactSuperview;
while (_reactParent != nil && _reactParent != root && IS_LAYOUT_ONLY(_reactParent)) {
_reactParent = _reactParent.reactSuperview;
}
_center = view.center;
_bounds = view.bounds;
_centerRelativeToRoot = [_parent convertPoint:_center toView:root];
_centerInReactParent = [_parent convertPoint:_center toView:_reactParent];
}
return self;
}
@end