Files
react-navigation/packages/stack/src/TransitionConfigs/CardStyleInterpolators.tsx
Gheorghe Pinzaru 6e51f596fa fix: ios presentation modal cuts the topOffset on the bottom (#7943)
* Add padding bottom to ios presentation modal

Because of the translateY moving the screen out to the bottom of view by 10 pt, these 10pt are hidden under the screen, or steal this size from the safe area. To avoid cutting elements, the size of the screen could be decreased by the `topOffset` using padding on the bottom. Fixes #7856

* Update packages/stack/src/TransitionConfigs/CardStyleInterpolators.tsx

Co-Authored-By: Serhii Vecherenko <SDSLeon999@gmail.com>

Co-authored-by: Satyajit Sahoo <satyajit.happy@gmail.com>
Co-authored-by: Serhii Vecherenko <SDSLeon999@gmail.com>
2020-04-18 01:13:34 +02:00

320 lines
7.0 KiB
TypeScript

import { Animated } from 'react-native';
import { isIphoneX } from 'react-native-iphone-x-helper';
import conditional from '../utils/conditional';
import {
StackCardInterpolationProps,
StackCardInterpolatedStyle,
} from '../types';
const { add, multiply } = Animated;
/**
* Standard iOS-style slide in from the right.
*/
export function forHorizontalIOS({
current,
next,
inverted,
layouts: { screen },
}: StackCardInterpolationProps): StackCardInterpolatedStyle {
const translateFocused = multiply(
current.progress.interpolate({
inputRange: [0, 1],
outputRange: [screen.width, 0],
extrapolate: 'clamp',
}),
inverted
);
const translateUnfocused = next
? multiply(
next.progress.interpolate({
inputRange: [0, 1],
outputRange: [0, screen.width * -0.3],
extrapolate: 'clamp',
}),
inverted
)
: 0;
const overlayOpacity = current.progress.interpolate({
inputRange: [0, 1],
outputRange: [0, 0.07],
extrapolate: 'clamp',
});
const shadowOpacity = current.progress.interpolate({
inputRange: [0, 1],
outputRange: [0, 0.3],
extrapolate: 'clamp',
});
return {
cardStyle: {
transform: [
// Translation for the animation of the current card
{ translateX: translateFocused },
// Translation for the animation of the card on top of this
{ translateX: translateUnfocused },
],
},
overlayStyle: { opacity: overlayOpacity },
shadowStyle: { shadowOpacity },
};
}
/**
* Standard iOS-style slide in from the bottom (used for modals).
*/
export function forVerticalIOS({
current,
inverted,
layouts: { screen },
}: StackCardInterpolationProps): StackCardInterpolatedStyle {
const translateY = multiply(
current.progress.interpolate({
inputRange: [0, 1],
outputRange: [screen.height, 0],
extrapolate: 'clamp',
}),
inverted
);
return {
cardStyle: {
transform: [
// Translation for the animation of the current card
{ translateY },
],
},
};
}
/**
* Standard iOS-style modal animation in iOS 13.
*/
export function forModalPresentationIOS({
index,
current,
next,
inverted,
layouts: { screen },
insets,
}: StackCardInterpolationProps): StackCardInterpolatedStyle {
const isLandscape = screen.width > screen.height;
const topOffset = isLandscape ? 0 : 10;
const statusBarHeight = insets.top;
const aspectRatio = screen.height / screen.width;
const progress = add(
current.progress.interpolate({
inputRange: [0, 1],
outputRange: [0, 1],
extrapolate: 'clamp',
}),
next
? next.progress.interpolate({
inputRange: [0, 1],
outputRange: [0, 1],
extrapolate: 'clamp',
})
: 0
);
const translateY = multiply(
progress.interpolate({
inputRange: [0, 1, 2],
outputRange: [
screen.height,
index === 0 ? 0 : topOffset,
(index === 0 ? statusBarHeight : 0) - topOffset * aspectRatio,
],
}),
inverted
);
const overlayOpacity = progress.interpolate({
inputRange: [0, 1, 1.0001, 2],
outputRange: [0, 0.3, 1, 1],
});
const scale = isLandscape
? 1
: progress.interpolate({
inputRange: [0, 1, 2],
outputRange: [
1,
1,
screen.width ? 1 - (topOffset * 2) / screen.width : 1,
],
});
const borderRadius = isLandscape
? 0
: index === 0
? progress.interpolate({
inputRange: [0, 1, 1.0001, 2],
outputRange: [0, 0, isIphoneX() ? 38 : 0, 10],
})
: 10;
return {
cardStyle: {
overflow: 'hidden',
borderTopLeftRadius: borderRadius,
borderTopRightRadius: borderRadius,
marginTop: index === 0 ? 0 : statusBarHeight,
marginBottom: index === 0 ? 0 : topOffset,
transform: [{ translateY }, { scale }],
},
overlayStyle: { opacity: overlayOpacity },
};
}
/**
* Standard Android-style fade in from the bottom for Android Oreo.
*/
export function forFadeFromBottomAndroid({
current,
inverted,
layouts: { screen },
closing,
}: StackCardInterpolationProps): StackCardInterpolatedStyle {
const translateY = multiply(
current.progress.interpolate({
inputRange: [0, 1],
outputRange: [screen.height * 0.08, 0],
extrapolate: 'clamp',
}),
inverted
);
const opacity = conditional(
closing,
current.progress,
current.progress.interpolate({
inputRange: [0, 0.5, 0.9, 1],
outputRange: [0, 0.25, 0.7, 1],
})
);
return {
cardStyle: {
opacity,
transform: [{ translateY }],
},
};
}
/**
* Standard Android-style reveal from the bottom for Android Pie.
*/
export function forRevealFromBottomAndroid({
current,
next,
inverted,
layouts: { screen },
}: StackCardInterpolationProps): StackCardInterpolatedStyle {
const containerTranslateY = multiply(
current.progress.interpolate({
inputRange: [0, 1],
outputRange: [screen.height, 0],
extrapolate: 'clamp',
}),
inverted
);
const cardTranslateYFocused = multiply(
current.progress.interpolate({
inputRange: [0, 1],
outputRange: [screen.height * (95.9 / 100) * -1, 0],
extrapolate: 'clamp',
}),
inverted
);
const cardTranslateYUnfocused = next
? multiply(
next.progress.interpolate({
inputRange: [0, 1],
outputRange: [0, screen.height * (2 / 100) * -1],
extrapolate: 'clamp',
}),
inverted
)
: 0;
const overlayOpacity = current.progress.interpolate({
inputRange: [0, 0.36, 1],
outputRange: [0, 0.1, 0.1],
extrapolate: 'clamp',
});
return {
containerStyle: {
overflow: 'hidden',
transform: [{ translateY: containerTranslateY }],
},
cardStyle: {
transform: [
{ translateY: cardTranslateYFocused },
{ translateY: cardTranslateYUnfocused },
],
},
overlayStyle: { opacity: overlayOpacity },
};
}
/**
* Standard Android-style reveal from the bottom for Android Q.
*/
export function forScaleFromCenterAndroid({
current,
next,
closing,
}: StackCardInterpolationProps): StackCardInterpolatedStyle {
const progress = add(
current.progress.interpolate({
inputRange: [0, 1],
outputRange: [0, 1],
extrapolate: 'clamp',
}),
next
? next.progress.interpolate({
inputRange: [0, 1],
outputRange: [0, 1],
extrapolate: 'clamp',
})
: 0
);
const opacity = progress.interpolate({
inputRange: [0, 0.8, 1, 1.2, 2],
outputRange: [0, 0.5, 1, 0.33, 0],
});
const scale = conditional(
closing,
current.progress.interpolate({
inputRange: [0, 1],
outputRange: [0.9, 1],
extrapolate: 'clamp',
}),
progress.interpolate({
inputRange: [0, 1, 2],
outputRange: [0.85, 1, 1.1],
})
);
return {
containerStyle: {
opacity,
transform: [{ scale }],
},
};
}
export function forNoAnimation(): StackCardInterpolatedStyle {
return {};
}