This repository has been archived by the owner on Feb 25, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 196
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
40 changed files
with
1,655 additions
and
4,541 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
import Animated from 'react-native-reanimated'; | ||
import { CardInterpolationProps, CardInterpolatedStyle } from '../types'; | ||
|
||
const { cond, multiply, interpolate } = Animated; | ||
|
||
/** | ||
* Standard iOS-style slide in from the right. | ||
*/ | ||
export function forHorizontalIOS({ | ||
positions: { current, next }, | ||
layout, | ||
}: CardInterpolationProps): CardInterpolatedStyle { | ||
const translateFocused = interpolate(current, { | ||
inputRange: [0, 1], | ||
outputRange: [layout.width, 0], | ||
}); | ||
const translateUnfocused = next | ||
? interpolate(next, { | ||
inputRange: [0, 1], | ||
outputRange: [0, multiply(layout.width, -0.3)], | ||
}) | ||
: 0; | ||
|
||
const opacity = interpolate(current, { | ||
inputRange: [0, 1], | ||
outputRange: [0, 0.07], | ||
}); | ||
|
||
const shadowOpacity = interpolate(current, { | ||
inputRange: [0, 1], | ||
outputRange: [0, 0.3], | ||
}); | ||
|
||
return { | ||
cardStyle: { | ||
backgroundColor: '#eee', | ||
transform: [ | ||
// Translation for the animation of the current card | ||
{ translateX: translateFocused }, | ||
// Translation for the animation of the card on top of this | ||
{ translateX: translateUnfocused }, | ||
], | ||
shadowOpacity, | ||
}, | ||
overlayStyle: { opacity }, | ||
}; | ||
} | ||
|
||
/** | ||
* Standard iOS-style slide in from the bottom (used for modals). | ||
*/ | ||
export function forVerticalIOS({ | ||
positions: { current }, | ||
layout, | ||
}: CardInterpolationProps): CardInterpolatedStyle { | ||
const translateY = interpolate(current, { | ||
inputRange: [0, 1], | ||
outputRange: [layout.height, 0], | ||
}); | ||
|
||
return { | ||
cardStyle: { | ||
backgroundColor: '#eee', | ||
transform: [ | ||
// Translation for the animation of the current card | ||
{ translateY }, | ||
], | ||
}, | ||
}; | ||
} | ||
|
||
/** | ||
* Standard Android-style fade in from the bottom for Android Oreo. | ||
*/ | ||
export function forFadeFromBottomAndroid({ | ||
positions: { current }, | ||
layout, | ||
closing, | ||
}: CardInterpolationProps): CardInterpolatedStyle { | ||
const translateY = interpolate(current, { | ||
inputRange: [0, 1], | ||
outputRange: [multiply(layout.height, 0.08), 0], | ||
}); | ||
|
||
const opacity = cond( | ||
closing, | ||
current, | ||
interpolate(current, { | ||
inputRange: [0, 0.5, 0.9, 1], | ||
outputRange: [0, 0.25, 0.7, 1], | ||
}) | ||
); | ||
|
||
return { | ||
cardStyle: { | ||
opacity, | ||
transform: [{ translateY }], | ||
}, | ||
}; | ||
} | ||
|
||
/** | ||
* Standard Android-style wipe from the bottom for Android Pie. | ||
*/ | ||
export function forWipeFromBottomAndroid({ | ||
positions: { current, next }, | ||
layout, | ||
}: CardInterpolationProps): CardInterpolatedStyle { | ||
const containerTranslateY = interpolate(current, { | ||
inputRange: [0, 1], | ||
outputRange: [layout.height, 0], | ||
}); | ||
const cardTranslateYFocused = interpolate(current, { | ||
inputRange: [0, 1], | ||
outputRange: [multiply(layout.height, 95.9 / 100, -1), 0], | ||
}); | ||
const cardTranslateYUnfocused = next | ||
? interpolate(next, { | ||
inputRange: [0, 1], | ||
outputRange: [0, multiply(layout.height, 2 / 100, -1)], | ||
}) | ||
: 0; | ||
const overlayOpacity = interpolate(current, { | ||
inputRange: [0, 0.36, 1], | ||
outputRange: [0, 0.1, 0.1], | ||
}); | ||
|
||
return { | ||
containerStyle: { | ||
transform: [{ translateY: containerTranslateY }], | ||
}, | ||
cardStyle: { | ||
transform: [ | ||
{ translateY: cardTranslateYFocused }, | ||
{ translateY: cardTranslateYUnfocused }, | ||
], | ||
}, | ||
overlayStyle: { opacity: overlayOpacity }, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import Animated from 'react-native-reanimated'; | ||
import { HeaderInterpolationProps, HeaderInterpolatedStyle } from '../types'; | ||
|
||
const { interpolate, add } = Animated; | ||
|
||
export function forUIKit({ | ||
positions: { current, next }, | ||
layouts, | ||
}: HeaderInterpolationProps): HeaderInterpolatedStyle { | ||
const leftSpacing = 27; | ||
|
||
// The title and back button title should cross-fade to each other | ||
// When screen is fully open, the title should be in center, and back title should be on left | ||
// When screen is closing, the previous title will animate to back title's position | ||
// And back title will animate to title's position | ||
// We achieve this by calculating the offsets needed to translate title to back title's position and vice-versa | ||
const backTitleOffset = layouts.backTitle | ||
? (layouts.screen.width - layouts.backTitle.width) / 2 - leftSpacing | ||
: undefined; | ||
const titleLeftOffset = layouts.title | ||
? (layouts.screen.width - layouts.title.width) / 2 - leftSpacing | ||
: undefined; | ||
|
||
// When the current title is animating to right, it is centered in the right half of screen in middle of transition | ||
// The back title also animates in from this position | ||
const rightOffset = layouts.screen.width / 4; | ||
|
||
const progress = add(current, next ? next : 0); | ||
|
||
return { | ||
leftButtonStyle: { | ||
opacity: interpolate(progress, { | ||
inputRange: [0.3, 1, 1.5], | ||
outputRange: [0, 1, 0], | ||
}), | ||
}, | ||
backTitleStyle: { | ||
// Title and back title are a bit different width due to title being bold | ||
// Adjusting the letterSpacing makes them coincide better | ||
letterSpacing: backTitleOffset | ||
? interpolate(progress, { | ||
inputRange: [0.3, 1, 2], | ||
outputRange: [0.35, 0, 0], | ||
}) | ||
: 0, | ||
transform: [ | ||
{ | ||
// Avoid translating if we don't have its width | ||
// It means there's no back title set | ||
translateX: backTitleOffset | ||
? interpolate(progress, { | ||
inputRange: [0, 1, 2], | ||
outputRange: [backTitleOffset, 0, -rightOffset], | ||
}) | ||
: 0, | ||
}, | ||
], | ||
}, | ||
titleStyle: { | ||
opacity: interpolate(progress, { | ||
inputRange: [0.4, 1, 1.5], | ||
outputRange: [0, 1, 0], | ||
}), | ||
transform: [ | ||
{ | ||
translateX: titleLeftOffset | ||
? interpolate(progress, { | ||
inputRange: [0.5, 1, 2], | ||
outputRange: [rightOffset, 0, -titleLeftOffset], | ||
}) | ||
: 0, | ||
}, | ||
], | ||
}, | ||
}; | ||
} | ||
|
||
export function forFade({ | ||
positions: { current, next }, | ||
}: HeaderInterpolationProps): HeaderInterpolatedStyle { | ||
const progress = add(current, next ? next : 0); | ||
const opacity = interpolate(progress, { | ||
inputRange: [0, 1, 2], | ||
outputRange: [0, 1, 0], | ||
}); | ||
|
||
return { | ||
leftButtonStyle: { opacity }, | ||
titleStyle: { opacity }, | ||
}; | ||
} | ||
|
||
export function forNoAnimation(): HeaderInterpolatedStyle { | ||
return {}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import { | ||
forHorizontalIOS, | ||
forVerticalIOS, | ||
forWipeFromBottomAndroid, | ||
forFadeFromBottomAndroid, | ||
} from './CardStyleInterpolators'; | ||
import { forUIKit, forNoAnimation } from './HeaderStyleInterpolators'; | ||
import { | ||
TransitionIOSSpec, | ||
WipeFromBottomAndroidSpec, | ||
FadeOutToBottomAndroidSpec, | ||
FadeInFromBottomAndroidSpec, | ||
} from './TransitionSpecs'; | ||
import { TransitionPreset } from '../types'; | ||
import { Platform } from 'react-native'; | ||
|
||
const ANDROID_VERSION_PIE = 28; | ||
|
||
// Standard iOS navigation transition | ||
export const SlideFromRightIOS: TransitionPreset = { | ||
direction: 'horizontal', | ||
headerMode: 'float', | ||
transitionSpec: { | ||
open: TransitionIOSSpec, | ||
close: TransitionIOSSpec, | ||
}, | ||
cardStyleInterpolator: forHorizontalIOS, | ||
headerStyleInterpolator: forUIKit, | ||
}; | ||
|
||
// Standard iOS navigation transition for modals | ||
export const ModalSlideFromBottomIOS: TransitionPreset = { | ||
direction: 'vertical', | ||
headerMode: 'screen', | ||
transitionSpec: { | ||
open: TransitionIOSSpec, | ||
close: TransitionIOSSpec, | ||
}, | ||
cardStyleInterpolator: forVerticalIOS, | ||
headerStyleInterpolator: forNoAnimation, | ||
}; | ||
|
||
// Standard Android navigation transition when opening or closing an Activity on Android < 9 | ||
export const FadeFromBottomAndroid: TransitionPreset = { | ||
direction: 'vertical', | ||
headerMode: 'screen', | ||
transitionSpec: { | ||
open: FadeInFromBottomAndroidSpec, | ||
close: FadeOutToBottomAndroidSpec, | ||
}, | ||
cardStyleInterpolator: forFadeFromBottomAndroid, | ||
headerStyleInterpolator: forNoAnimation, | ||
}; | ||
|
||
// Standard Android navigation transition when opening or closing an Activity on Android >= 9 | ||
export const WipeFromBottomAndroid: TransitionPreset = { | ||
direction: 'vertical', | ||
headerMode: 'screen', | ||
transitionSpec: { | ||
open: WipeFromBottomAndroidSpec, | ||
close: WipeFromBottomAndroidSpec, | ||
}, | ||
cardStyleInterpolator: forWipeFromBottomAndroid, | ||
headerStyleInterpolator: forNoAnimation, | ||
}; | ||
|
||
export const DefaultTransition = Platform.select({ | ||
ios: SlideFromRightIOS, | ||
default: | ||
Platform.OS === 'android' && Platform.Version < ANDROID_VERSION_PIE | ||
? FadeFromBottomAndroid | ||
: WipeFromBottomAndroid, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { Easing } from 'react-native-reanimated'; | ||
import { TransitionSpec } from '../types'; | ||
|
||
export const TransitionIOSSpec: TransitionSpec = { | ||
timing: 'spring', | ||
config: { | ||
stiffness: 1000, | ||
damping: 500, | ||
mass: 3, | ||
overshootClamping: true, | ||
restDisplacementThreshold: 0.01, | ||
restSpeedThreshold: 0.01, | ||
}, | ||
}; | ||
|
||
// See http://androidxref.com/7.1.1_r6/xref/frameworks/base/core/res/res/anim/activity_open_enter.xml | ||
export const FadeInFromBottomAndroidSpec: TransitionSpec = { | ||
timing: 'timing', | ||
config: { | ||
duration: 350, | ||
easing: Easing.out(Easing.poly(5)), | ||
}, | ||
}; | ||
|
||
// See http://androidxref.com/7.1.1_r6/xref/frameworks/base/core/res/res/anim/activity_close_exit.xml | ||
export const FadeOutToBottomAndroidSpec: TransitionSpec = { | ||
timing: 'timing', | ||
config: { | ||
duration: 150, | ||
easing: Easing.in(Easing.linear), | ||
}, | ||
}; | ||
|
||
// See http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/res/res/anim/activity_open_enter.xml | ||
export const WipeFromBottomAndroidSpec: TransitionSpec = { | ||
timing: 'timing', | ||
config: { | ||
duration: 425, | ||
// This is super rough approximation of the path used for the curve by android | ||
// See http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/res/res/interpolator/fast_out_extra_slow_in.xml | ||
easing: Easing.bezier(0.35, 0.45, 0, 1), | ||
}, | ||
}; |
Oops, something went wrong.