Skip to content

Commit

Permalink
Implement rotate animation for shared element transition
Browse files Browse the repository at this point in the history
  • Loading branch information
yogevbd authored Apr 21, 2020
1 parent da0fd19 commit 5d9e910
Show file tree
Hide file tree
Showing 12 changed files with 64 additions and 6 deletions.
2 changes: 2 additions & 0 deletions lib/ios/ElementBaseTransition.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#import "DisplayLinkAnimation.h"
#import "RNNInterpolator.h"

#define DEGREES_TO_RADIANS(angle) ((angle) / 180.0 * M_PI)

@interface ElementBaseTransition : NSObject <DisplayLinkAnimation>

- (instancetype)initWithView:(UIView *)view startDelay:(NSTimeInterval)startDelay duration:(NSTimeInterval)duration interpolation:(Text *)interpolation;
Expand Down
2 changes: 2 additions & 0 deletions lib/ios/FloatTransition.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

- (instancetype)initWithView:(UIView *)view transitionDetails:(TransitionDetailsOptions *)transitionDetails;

- (instancetype)initWithView:(UIView *)view fromFloat:(CGFloat)from toFloat:(CGFloat)to startDelay:(NSTimeInterval)startDelay duration:(NSTimeInterval)duration interpolation:(Text *)interpolation;

@property (readonly) CGFloat initialValue;
@property (nonatomic) CGFloat from;
@property (nonatomic) CGFloat to;
Expand Down
7 changes: 7 additions & 0 deletions lib/ios/FloatTransition.m
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ - (instancetype)initWithView:(UIView *)view transitionDetails:(TransitionDetails
return self;
}

- (instancetype)initWithView:(UIView *)view fromFloat:(CGFloat)from toFloat:(CGFloat)to startDelay:(NSTimeInterval)startDelay duration:(NSTimeInterval)duration interpolation:(Text *)interpolation {
self = [super initWithView:view startDelay:startDelay duration:duration interpolation:interpolation];
self.from = from;
self.to = to;
return self;
}

- (instancetype)initWithView:(UIView *)view from:(Double*)from to:(Double*)to startDelay:(NSTimeInterval)startDelay duration:(NSTimeInterval)duration interpolation:(Text *)interpolation {
self = [super initWithView:view startDelay:startDelay duration:duration interpolation:interpolation];
_initialValue = self.initialValue;
Expand Down
2 changes: 2 additions & 0 deletions lib/ios/RNNViewLocation.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

@property (nonatomic) CGRect fromFrame;
@property (nonatomic) CGRect toFrame;
@property (nonatomic) CGFloat fromAngle;
@property (nonatomic) CGFloat toAngle;

- (instancetype)initWithFromElement:(UIView*)fromElement toElement:(UIView*)toElement;

Expand Down
13 changes: 10 additions & 3 deletions lib/ios/RNNViewLocation.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,25 @@ - (instancetype)initWithFromElement:(UIView *)fromElement toElement:(UIView *)to
self = [super init];
self.fromFrame = [self convertViewFrame:fromElement];
self.toFrame = [self convertViewFrame:toElement];
self.fromAngle = [self getViewAngle:fromElement];
self.toAngle = [self getViewAngle:toElement];
return self;
}

- (CGRect)convertViewFrame:(UIView *)view {
UIView* topMostView = [self topMostView:view];
CGRect frame = [view.superview convertRect:view.frame toView:nil];
CGPoint center = [view.superview convertPoint:view.center toView:nil];
CGFloat safeAreaTopOffset = [self safeAreaOffsetForView:view inView:topMostView];
frame.origin.y += safeAreaTopOffset;

center.y += safeAreaTopOffset;
CGRect frame = CGRectMake(center.x - view.bounds.size.width / 2, center.y - view.bounds.size.height / 2, view.bounds.size.width, view.bounds.size.height);
return frame;
}

- (CGFloat)getViewAngle:(UIView *)view {
CGFloat radians = atan2f(view.transform.b, view.transform.a);
return radians;
}

- (UIView *)topMostView:(UIView *)view {
if ([view isKindOfClass:[RNNReactView class]]) {
return view;
Expand Down
8 changes: 8 additions & 0 deletions lib/ios/ReactNativeNavigation.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,8 @@
50644A2120E11A720026709C /* Constants.m in Sources */ = {isa = PBXBuildFile; fileRef = 50644A1F20E11A720026709C /* Constants.m */; };
506A2B1420973DFD00F43A95 /* RNNErrorHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 506A2B1220973DFD00F43A95 /* RNNErrorHandler.h */; };
506A2B1520973DFD00F43A95 /* RNNErrorHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 506A2B1320973DFD00F43A95 /* RNNErrorHandler.m */; };
506C2532244F0C6B00820F5B /* RotationTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = 506C2530244F0C6B00820F5B /* RotationTransition.h */; };
506C2533244F0C6B00820F5B /* RotationTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 506C2531244F0C6B00820F5B /* RotationTransition.m */; };
506F630D216A599300AD0D0A /* RNNTabBarControllerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 506F630C216A599300AD0D0A /* RNNTabBarControllerTest.m */; };
506F630F216A5AD700AD0D0A /* RNNComponentPresenterTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 506F630E216A5AD700AD0D0A /* RNNComponentPresenterTest.m */; };
50706E6D20CE7CA5003345C3 /* UIImage+tint.h in Headers */ = {isa = PBXBuildFile; fileRef = 50706E6B20CE7CA5003345C3 /* UIImage+tint.h */; };
Expand Down Expand Up @@ -721,6 +723,8 @@
50644A1F20E11A720026709C /* Constants.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Constants.m; sourceTree = "<group>"; };
506A2B1220973DFD00F43A95 /* RNNErrorHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNErrorHandler.h; sourceTree = "<group>"; };
506A2B1320973DFD00F43A95 /* RNNErrorHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNErrorHandler.m; sourceTree = "<group>"; };
506C2530244F0C6B00820F5B /* RotationTransition.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RotationTransition.h; sourceTree = "<group>"; };
506C2531244F0C6B00820F5B /* RotationTransition.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RotationTransition.m; sourceTree = "<group>"; };
506F630C216A599300AD0D0A /* RNNTabBarControllerTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNTabBarControllerTest.m; sourceTree = "<group>"; };
506F630E216A5AD700AD0D0A /* RNNComponentPresenterTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNComponentPresenterTest.m; sourceTree = "<group>"; };
50706E6B20CE7CA5003345C3 /* UIImage+tint.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIImage+tint.h"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1320,6 +1324,8 @@
50AD288723CDB71C00FF3134 /* ElementHorizontalTransition.m */,
5082CC3123CDC3B800FD2B6A /* HorizontalTranslationTransition.h */,
5082CC3223CDC3B800FD2B6A /* HorizontalTranslationTransition.m */,
506C2530244F0C6B00820F5B /* RotationTransition.h */,
506C2531244F0C6B00820F5B /* RotationTransition.m */,
5061B6C523D48449008B9827 /* VerticalRotationTransition.h */,
5061B6C623D48449008B9827 /* VerticalRotationTransition.m */,
5096709923D49B35002224F9 /* DisplayLinkAnimatorDelegate.h */,
Expand Down Expand Up @@ -1812,6 +1818,7 @@
390AD477200F499D00A8250D /* RNNSwizzles.h in Headers */,
5022EDC924054C8A00852BA6 /* BottomTabsPresenterCreator.h in Headers */,
263905B11E4C6F440023D7D3 /* MMDrawerController.h in Headers */,
506C2532244F0C6B00820F5B /* RotationTransition.h in Headers */,
263905B31E4C6F440023D7D3 /* MMDrawerVisualState.h in Headers */,
50451D092042E20600695F00 /* RNNAnimationsOptions.h in Headers */,
50EA541A23AEE1C6006F881A /* AnimatedReactView.h in Headers */,
Expand Down Expand Up @@ -2182,6 +2189,7 @@
50EA541B23AEE1C6006F881A /* AnimatedReactView.m in Sources */,
5095BB732416A3B900C4CD41 /* RNNConvert.m in Sources */,
7BC9346E1E26886E00EFA125 /* RNNControllerFactory.m in Sources */,
506C2533244F0C6B00820F5B /* RotationTransition.m in Sources */,
507F43F91FF525B500D9425B /* RNNSegmentedControl.m in Sources */,
5038A3B2216DF41B009280BC /* UIViewController+RNNOptions.m in Sources */,
50D031352005149000386B3D /* RNNOverlayManager.m in Sources */,
Expand Down
5 changes: 5 additions & 0 deletions lib/ios/RotationTransition.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#import "FloatTransition.h"

@interface RotationTransition : FloatTransition

@end
11 changes: 11 additions & 0 deletions lib/ios/RotationTransition.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#import "RotationTransition.h"

@implementation RotationTransition

- (CATransform3D)animateWithProgress:(CGFloat)p {
double degrees = [RNNInterpolator fromFloat:self.from toFloat:self.to precent:p interpolation:self.interpolation];
double rads = DEGREES_TO_RADIANS(degrees);
return CATransform3DMakeRotation(rads, 0, 0, 1);
}

@end
3 changes: 2 additions & 1 deletion lib/ios/SharedElementAnimator.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#import "AnimatedViewFactory.h"
#import "RectTransition.h"
#import "TransformRectTransition.h"
#import "RotationTransition.h"
#import "ColorTransition.h"
#import "AnimatedTextView.h"
#import "TextStorageTransition.h"
Expand Down Expand Up @@ -43,7 +44,7 @@ - (AnimatedReactView *)createAnimatedView:(SharedElementTransitionOptions *)tran
if ([self.view isKindOfClass:AnimatedTextView.class]) {
[animations addObject:[[RectTransition alloc] initWithView:self.view from:self.view.location.fromFrame to:self.view.location.toFrame startDelay:startDelay duration:duration interpolation:interpolation]];
} else {
[animations addObject:[[TransformRectTransition alloc] initWithView:self.view from:self.view.location.fromFrame to:self.view.location.toFrame startDelay:startDelay duration:duration interpolation:interpolation]];
[animations addObject:[[TransformRectTransition alloc] initWithView:self.view fromRect:self.view.location.fromFrame toRect:self.view.location.toFrame fromAngle:self.view.location.fromAngle toAngle:self.view.location.toAngle startDelay:startDelay duration:duration interpolation:interpolation]];
}
}

Expand Down
5 changes: 5 additions & 0 deletions lib/ios/TransformRectTransition.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,9 @@

@interface TransformRectTransition : RectTransition

- (instancetype)initWithView:(UIView *)view fromRect:(CGRect)fromRect toRect:(CGRect)toRect fromAngle:(CGFloat)fromAngle toAngle:(CGFloat)toAngle startDelay:(NSTimeInterval)startDelay duration:(NSTimeInterval)duration interpolation:(Text *)interpolation;

@property (nonatomic, readonly) CGFloat fromAngle;
@property (nonatomic, readonly) CGFloat toAngle;

@end
11 changes: 10 additions & 1 deletion lib/ios/TransformRectTransition.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,16 @@

@implementation TransformRectTransition

- (instancetype)initWithView:(UIView *)view fromRect:(CGRect)fromRect toRect:(CGRect)toRect fromAngle:(CGFloat)fromAngle toAngle:(CGFloat)toAngle startDelay:(NSTimeInterval)startDelay duration:(NSTimeInterval)duration interpolation:(Text *)interpolation {
self = [super initWithView:view from:fromRect to:toRect startDelay:startDelay duration:duration interpolation:interpolation];
_fromAngle = fromAngle;
_toAngle = toAngle;
return self;
}

- (CATransform3D)animateWithProgress:(CGFloat)p {
CGRect toFrame = [RNNInterpolator fromRect:self.from toRect:self.to precent:p interpolation:self.interpolation];
CGFloat toAngle = [RNNInterpolator fromFloat:self.fromAngle toFloat:self.toAngle precent:p interpolation:self.interpolation];

CGFloat scaleX = toFrame.size.width / self.from.size.width;
CGFloat scaleY = toFrame.size.height / self.from.size.height;
Expand All @@ -14,8 +22,9 @@ - (CATransform3D)animateWithProgress:(CGFloat)p {

CATransform3D translate = CATransform3DMakeTranslation(translateX, translateY, 0);
CATransform3D scale = CATransform3DScale(translate, scaleX, scaleY, 0);
CATransform3D rotate = CATransform3DRotate(scale, toAngle, 0, 0, 1);

return scale;
return rotate;
}

@end
1 change: 0 additions & 1 deletion lib/ios/VerticalRotationTransition.m
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#import "VerticalRotationTransition.h"
#define DEGREES_TO_RADIANS(angle) ((angle) / 180.0 * M_PI)

@implementation VerticalRotationTransition

Expand Down

0 comments on commit 5d9e910

Please sign in to comment.