Skip to content
This repository has been archived by the owner on Feb 8, 2020. It is now read-only.

Commit

Permalink
feat: add iOS modal presentation style
Browse files Browse the repository at this point in the history
  • Loading branch information
satya164 committed Aug 18, 2019
1 parent 1fb33c8 commit 838732d
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 3 deletions.
55 changes: 54 additions & 1 deletion packages/stack/src/TransitionConfigs/CardStyleInterpolators.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { I18nManager } from 'react-native';
import Animated from 'react-native-reanimated';
import { CardInterpolationProps, CardInterpolatedStyle } from '../types';
import { getStatusBarHeight } from 'react-native-safe-area-view';

const { cond, multiply, interpolate } = Animated;
const { cond, add, multiply, interpolate } = Animated;

/**
* Standard iOS-style slide in from the right.
Expand Down Expand Up @@ -71,6 +72,58 @@ export function forVerticalIOS({
};
}

/**
* Standard iOS-style modal animation in iOS 13.
*/
export function forModalPresentationIOS({
index,
progress: { current, next },
layouts: { screen },
}: CardInterpolationProps): CardInterpolatedStyle {
const topOffset = 10;
const statusBarHeight = getStatusBarHeight(screen.width > screen.height);
const aspectRatio = screen.height / screen.width;

const progress = add(current, next ? next : 0);

const translateY = interpolate(progress, {
inputRange: [0, 1, 2],
outputRange: [
screen.height,
index === 0 ? 0 : topOffset,
(index === 0 ? statusBarHeight : 0) - topOffset * aspectRatio,
],
});

const overlayOpacity = interpolate(progress, {
inputRange: [0, 1, 2],
outputRange: [0, 0.3, 1],
});

const scale = interpolate(progress, {
inputRange: [0, 1, 2],
outputRange: [1, 1, screen.width ? 1 - (topOffset * 2) / screen.width : 1],
});

const borderRadius =
index === 0
? interpolate(progress, {
inputRange: [0, 1, 2],
outputRange: [0, 0, 10],
})
: 10;

return {
cardStyle: {
borderTopLeftRadius: borderRadius,
borderTopRightRadius: borderRadius,
marginTop: index === 0 ? 0 : statusBarHeight,
transform: [{ translateY }, { scale }],
},
overlayStyle: { opacity: overlayOpacity },
};
}

/**
* Standard Android-style fade in from the bottom for Android Oreo.
*/
Expand Down
12 changes: 12 additions & 0 deletions packages/stack/src/TransitionConfigs/TransitionPresets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
forVerticalIOS,
forWipeFromBottomAndroid,
forFadeFromBottomAndroid,
forModalPresentationIOS,
} from './CardStyleInterpolators';
import { forNoAnimation, forFade } from './HeaderStyleInterpolators';
import {
Expand Down Expand Up @@ -38,6 +39,17 @@ export const ModalSlideFromBottomIOS: TransitionPreset = {
headerStyleInterpolator: forNoAnimation,
};

// Standard iOS modal presentation style (introduced in iOS 13)
export const ModalPresentationIOS: TransitionPreset = {
direction: 'vertical',
transitionSpec: {
open: TransitionIOSSpec,
close: TransitionIOSSpec,
},
cardStyleInterpolator: forModalPresentationIOS,
headerStyleInterpolator: forNoAnimation,
};

// Standard Android navigation transition when opening or closing an Activity on Android < 9
export const FadeFromBottomAndroid: TransitionPreset = {
direction: 'vertical',
Expand Down
1 change: 1 addition & 0 deletions packages/stack/src/types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ export type TransitionSpec =
| { timing: 'timing'; config: TimingConfig };

export type CardInterpolationProps = {
index: number;
progress: {
current: Animated.Node<number>;
next?: Animated.Node<number>;
Expand Down
14 changes: 12 additions & 2 deletions packages/stack/src/views/Stack/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import StackGestureContext from '../../utils/StackGestureContext';
import PointerEventsView from './PointerEventsView';

type Props = ViewProps & {
index: number;
active: boolean;
closing?: boolean;
transparent?: boolean;
Expand Down Expand Up @@ -404,11 +405,13 @@ export default class Card extends React.Component<Props> {
private getInterpolatedStyle = memoize(
(
styleInterpolator: CardStyleInterpolator,
index: number,
current: Animated.Node<number>,
next: Animated.Node<number> | undefined,
layout: Layout
) =>
styleInterpolator({
index,
progress: {
current,
next,
Expand Down Expand Up @@ -460,6 +463,7 @@ export default class Card extends React.Component<Props> {

render() {
const {
index,
active,
transparent,
layout,
Expand All @@ -481,7 +485,13 @@ export default class Card extends React.Component<Props> {
cardStyle,
overlayStyle,
shadowStyle,
} = this.getInterpolatedStyle(styleInterpolator, current, next, layout);
} = this.getInterpolatedStyle(
styleInterpolator,
index,
current,
next,
layout
);

const handleGestureEvent =
direction === 'vertical'
Expand Down Expand Up @@ -509,7 +519,7 @@ export default class Card extends React.Component<Props> {
onHandlerStateChange={handleGestureEvent}
{...this.gestureActivationCriteria()}
>
<Animated.View style={[StyleSheet.absoluteFill, cardStyle]}>
<Animated.View style={[styles.container, cardStyle]}>
{shadowEnabled && !transparent ? (
<Animated.View
style={[styles.shadow, shadowStyle]}
Expand Down
2 changes: 2 additions & 0 deletions packages/stack/src/views/Stack/StackItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export default class StackItem extends React.PureComponent<Props> {

render() {
const {
index,
layout,
active,
focused,
Expand Down Expand Up @@ -110,6 +111,7 @@ export default class StackItem extends React.PureComponent<Props> {

return (
<Card
index={index}
active={active}
transparent={cardTransparent}
direction={direction}
Expand Down

0 comments on commit 838732d

Please sign in to comment.