Animações

Padrões de animação — timing, spring, easing e valores usados no app.

ComponenteTipoValores
FadeSlide (modal steps)timingopacity 0→1 240ms + translateY 60→0 300ms
Modal open (SaveToFavorites)springdamping 50, stiffness 350, overshootClamping true
Modal closetiming240ms, toValue 600 (para fora da tela)
Picker opentimingtranslateY 48→0, 220ms
Picker closetimingtranslateY 0→48, 180ms
Delete TripCardparallel timingopacity 1→0 200ms + translateX 0→-500 250ms
Swap buttonReanimated withTimingrotate 0°→180°, 300ms
Splash screen fadetimingopacity 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 }] }

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));
}