UNPKG

@react-navigation/stack

Version:

Stack navigator component for iOS and Android with animated transitions and gestures

262 lines (253 loc) 6.33 kB
"use strict"; import { Animated, Platform } from 'react-native'; const { add, multiply } = Animated; // Width of the screen in split layout on portrait mode on iPad Mini // Keep in sync with HeaderBackButton.tsx const IPAD_MINI_MEDIUM_WIDTH = 414; /** * Standard UIKit style animation for the header where the title fades into the back button label. */ export function forUIKit({ current, next, direction, layouts }) { const defaultOffset = 100; const leftSpacing = 27 + (Platform.OS === 'ios' && layouts.screen.width >= IPAD_MINI_MEDIUM_WIDTH ? 5 // Additional padding on iPad specified in Header.tsx : 0); // 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 leftLabelOffset = layouts.leftLabel ? (layouts.screen.width - layouts.leftLabel.width) / 2 - leftSpacing : defaultOffset; const titleLeftOffset = layouts.title ? (layouts.screen.width - layouts.title.width) / 2 - leftSpacing : defaultOffset; // 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 multiplier = direction === 'rtl' ? -1 : 1; 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); return { leftButtonStyle: { opacity: progress.interpolate({ inputRange: [0.3, 1, 1.5], outputRange: [0, 1, 0] }) }, leftLabelStyle: { transform: [{ translateX: multiply(multiplier, progress.interpolate({ inputRange: [0, 1, 2], outputRange: [leftLabelOffset, 0, -rightOffset] })) }] }, rightButtonStyle: { opacity: progress.interpolate({ inputRange: [0.3, 1, 1.5], outputRange: [0, 1, 0] }) }, titleStyle: { opacity: progress.interpolate({ inputRange: [0, 0.5, 0.75, 1, 1.5], outputRange: [0, 0, 0.1, 1, 0] }), transform: [{ translateX: multiply(multiplier, progress.interpolate({ inputRange: [0.5, 1, 2], outputRange: [rightOffset, 0, -titleLeftOffset] })) }] }, backgroundStyle: { transform: [{ translateX: multiply(multiplier, progress.interpolate({ inputRange: [0, 1, 2], outputRange: [layouts.screen.width, 0, -layouts.screen.width] })) }] } }; } /** * Simple fade animation for the header elements. */ export function forFade({ current, next }) { 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, 1, 2], outputRange: [0, 1, 0] }); return { leftButtonStyle: { opacity }, rightButtonStyle: { opacity }, titleStyle: { opacity }, backgroundStyle: { opacity: progress.interpolate({ inputRange: [0, 1, 1.9, 2], outputRange: [0, 1, 1, 0] }) } }; } /** * Simple translate animation to translate the header to left. */ export function forSlideLeft({ current, next, direction, layouts: { screen } }) { const isRTL = direction === 'rtl'; 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 translateX = progress.interpolate({ inputRange: [0, 1, 2], outputRange: isRTL ? [-screen.width, 0, screen.width] : [screen.width, 0, -screen.width] }); const transform = [{ translateX }]; return { leftButtonStyle: { transform }, rightButtonStyle: { transform }, titleStyle: { transform }, backgroundStyle: { transform } }; } /** * Simple translate animation to translate the header to right. */ export function forSlideRight({ current, next, direction, layouts: { screen } }) { const isRTL = direction === 'rtl'; 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 translateX = progress.interpolate({ inputRange: [0, 1, 2], outputRange: isRTL ? [screen.width, 0, -screen.width] : [-screen.width, 0, screen.width] }); const transform = [{ translateX }]; return { leftButtonStyle: { transform }, rightButtonStyle: { transform }, titleStyle: { transform }, backgroundStyle: { transform } }; } /** * Simple translate animation to translate the header to slide up. */ export function forSlideUp({ current, next, layouts: { header } }) { 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 = progress.interpolate({ inputRange: [0, 1, 2], outputRange: [-header.height, 0, -header.height] }); const transform = [{ translateY }]; return { leftButtonStyle: { transform }, rightButtonStyle: { transform }, titleStyle: { transform }, backgroundStyle: { transform } }; } export function forNoAnimation() { return {}; } //# sourceMappingURL=HeaderStyleInterpolators.js.map