Animações
Padrões de animação — timing, spring, easing e valores usados no app.
| Componente | Tipo | Valores |
|---|---|---|
| FadeSlide (modal steps) | timing | opacity 0→1 240ms + translateY 60→0 300ms |
| Modal open (SaveToFavorites) | spring | damping 50, stiffness 350, overshootClamping true |
| Modal close | timing | 240ms, toValue 600 (para fora da tela) |
| Picker open | timing | translateY 48→0, 220ms |
| Picker close | timing | translateY 0→48, 180ms |
| Delete TripCard | parallel timing | opacity 1→0 200ms + translateX 0→-500 250ms |
| Swap button | Reanimated withTiming | rotate 0°→180°, 300ms |
| Splash screen fade | timing | opacity 1→0, 350ms |
FadeSlide (modal steps)
Usado para transicionar entre steps do modal multi-etapas. Opacity e translateY em paralelo.
// app/modal.tsx — FadeSlide entre steps
const opacity = useRef(new Animated.Value(0)).current;
const translateY = useRef(new Animated.Value(60)).current;
function animateIn() {
Animated.parallel([
Animated.timing(opacity, {
toValue: 1, duration: 240, useNativeDriver: true,
}),
Animated.timing(translateY, {
toValue: 0, duration: 300, useNativeDriver: true,
}),
]).start();
}
// style
{ opacity, transform: [{ translateY }] }Modal open / close (SaveToFavorites)
Sheet bottom — abertura com spring, fechamento com timing para saída rápida.
// components/SaveToFavoritesModal.tsx
const slideAnim = useRef(new Animated.Value(600)).current;
// Open — spring
Animated.spring(slideAnim, {
toValue: 0,
damping: 50,
stiffness: 350,
overshootClamping: true,
useNativeDriver: true,
}).start();
// Close — timing
Animated.timing(slideAnim, {
toValue: 600,
duration: 240,
useNativeDriver: true,
}).start(() => onClose());
// style
{ transform: [{ translateY: slideAnim }] }Picker (date pickers)
Picker de data/hora. Desliza 48px para entrar e sair.
// Picker open
Animated.timing(pickerAnim, {
toValue: 0, duration: 220, useNativeDriver: true,
}).start();
// Picker close
Animated.timing(pickerAnim, {
toValue: 48, duration: 180, useNativeDriver: true,
}).start(() => setShowPicker(false));
// style
{ transform: [{ translateY: pickerAnim }] }Delete TripCard
Animação de saída ao confirmar delete no swipe. Opacity e translateX em paralelo.
// screens/Viagens — TripCard delete
Animated.parallel([
Animated.timing(opacity, {
toValue: 0, duration: 200, useNativeDriver: true,
}),
Animated.timing(translateX, {
toValue: -500, duration: 250, useNativeDriver: true,
}),
]).start(() => onDelete(id));Swap button
Botão de trocar origem/destino. Gira 180° com Reanimated withTiming.
// components/SwapButton — Reanimated
import { useSharedValue, withTiming, useAnimatedStyle } from 'react-native-reanimated';
const rotation = useSharedValue(0);
function handleSwap() {
rotation.value = withTiming(rotation.value + 180, { duration: 300 });
onSwap();
}
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ rotate: `${rotation.value}deg` }],
}));Splash screen fade
Fade out da splash screen ao terminar o carregamento inicial.
// app/_layout.tsx — splash fade out
const splashOpacity = useRef(new Animated.Value(1)).current;
function hideSplash() {
Animated.timing(splashOpacity, {
toValue: 0,
duration: 350,
useNativeDriver: true,
}).start(() => setSplashVisible(false));
}