乐闻世界logo
搜索文章和话题

Expo中如何实现动画效果?有哪些常用的动画库?

2月21日 16:03

Expo动画是提升用户体验的重要手段。Expo支持多种动画库和API,从简单的过渡效果到复杂的交互动画都有完善的解决方案。

动画库选择:

  1. React Native Animated API

React Native内置的动画API,适合大多数动画需求。

基础动画:

typescript
import { Animated, Easing } from 'react-native'; function FadeInComponent() { const fadeAnim = useRef(new Animated.Value(0)).current; useEffect(() => { Animated.timing(fadeAnim, { toValue: 1, duration: 1000, easing: Easing.ease, useNativeDriver: true, }).start(); }, []); return ( <Animated.View style={{ opacity: fadeAnim }}> <Text>Fade In</Text> </Animated.View> ); }

插值动画:

typescript
function InterpolationComponent() { const translateX = useRef(new Animated.Value(0)).current; const rotate = translateX.interpolate({ inputRange: [0, 100], outputRange: ['0deg', '180deg'], }); const scale = translateX.interpolate({ inputRange: [0, 100], outputRange: [1, 2], }); return ( <Animated.View style={{ transform: [ { translateX }, { rotate }, { scale }, ], }} > <Text>Animated Box</Text> </Animated.View> ); }

并行和序列动画:

typescript
function ComplexAnimation() { const fadeAnim = useRef(new Animated.Value(0)).current; const scaleAnim = useRef(new Animated.Value(1)).current; const startAnimation = () => { Animated.parallel([ Animated.timing(fadeAnim, { toValue: 1, duration: 500, useNativeDriver: true, }), Animated.spring(scaleAnim, { toValue: 1.5, friction: 5, useNativeDriver: true, }), ]).start(); }; return ( <Animated.View style={{ opacity: fadeAnim, transform: [{ scale: scaleAnim }], }} > <Button title="Animate" onPress={startAnimation} /> </Animated.View> ); }
  1. React Native Reanimated

更强大的动画库,支持手势和复杂动画。

安装:

bash
npx expo install react-native-reanimated

基础动画:

typescript
import Animated, { useSharedValue, useAnimatedStyle, withTiming, withSpring, withSequence, } from 'react-native-reanimated'; function ReanimatedComponent() { const opacity = useSharedValue(0); const scale = useSharedValue(1); const animatedStyle = useAnimatedStyle(() => { return { opacity: opacity.value, transform: [{ scale: scale.value }], }; }); const startAnimation = () => { opacity.value = withTiming(1, { duration: 500 }); scale.value = withSpring(1.5); }; return ( <Animated.View style={animatedStyle}> <Button title="Animate" onPress={startAnimation} /> </Animated.View> ); }

手势动画:

typescript
import { Gesture, GestureDetector } from 'react-native-gesture-handler'; function GestureComponent() { const translateX = useSharedValue(0); const translateY = useSharedValue(0); const pan = Gesture.Pan() .onUpdate((event) => { translateX.value = event.translationX; translateY.value = event.translationY; }) .onEnd(() => { translateX.value = withSpring(0); translateY.value = withSpring(0); }); const animatedStyle = useAnimatedStyle(() => { return { transform: [ { translateX: translateX.value }, { translateY: translateY.value }, ], }; }); return ( <GestureDetector gesture={pan}> <Animated.View style={animatedStyle}> <Text>Drag me</Text> </Animated.View> </GestureDetector> ); }
  1. Lottie

使用Adobe After Effects创建的复杂动画。

安装:

bash
npx expo install lottie-react-native

使用Lottie动画:

typescript
import LottieView from 'lottie-react-native'; function LottieComponent() { return ( <LottieView source={require('./assets/animation.json')} autoPlay loop style={{ width: 200, height: 200 }} /> ); }

控制Lottie动画:

typescript
function ControlledLottie() { const animationRef = useRef<LottieView>(null); const playAnimation = () => { animationRef.current?.play(); }; const pauseAnimation = () => { animationRef.current?.pause(); }; const resetAnimation = () => { animationRef.current?.reset(); }; return ( <View> <LottieView ref={animationRef} source={require('./assets/animation.json')} style={{ width: 200, height: 200 }} /> <Button title="Play" onPress={playAnimation} /> <Button title="Pause" onPress={pauseAnimation} /> <Button title="Reset" onPress={resetAnimation} /> </View> ); }

常用动画模式:

  1. 淡入淡出
typescript
function FadeInOut() { const opacity = useSharedValue(0); const fadeIn = () => { opacity.value = withTiming(1, { duration: 500 }); }; const fadeOut = () => { opacity.value = withTiming(0, { duration: 500 }); }; const style = useAnimatedStyle(() => ({ opacity: opacity.value, })); return ( <Animated.View style={style}> <Button title="Fade In" onPress={fadeIn} /> <Button title="Fade Out" onPress={fadeOut} /> </Animated.View> ); }
  1. 滑动动画
typescript
function SlideAnimation() { const translateX = useSharedValue(-300); const slideIn = () => { translateX.value = withSpring(0); }; const slideOut = () => { translateX.value = withSpring(-300); }; const style = useAnimatedStyle(() => ({ transform: [{ translateX: translateX.value }], })); return ( <Animated.View style={style}> <Text>Slide Content</Text> </Animated.View> ); }
  1. 缩放动画
typescript
function ScaleAnimation() { const scale = useSharedValue(1); const scaleUp = () => { scale.value = withSpring(1.5); }; const scaleDown = () => { scale.value = withSpring(1); }; const style = useAnimatedStyle(() => ({ transform: [{ scale: scale.value }], })); return ( <Animated.View style={style}> <Text>Scale Content</Text> </Animated.View> ); }
  1. 旋转动画
typescript
function RotateAnimation() { const rotation = useSharedValue(0); const rotate = () => { rotation.value = withTiming(rotation.value + 360, { duration: 1000, easing: Easing.linear, }); }; const style = useAnimatedStyle(() => ({ transform: [{ rotate: `${rotation.value}deg` }], })); return ( <Animated.View style={style}> <Text>Rotate Content</Text> </Animated.View> ); }

性能优化:

  1. 使用原生驱动
typescript
// 使用useNativeDriver提高性能 Animated.timing(value, { toValue: 1, duration: 500, useNativeDriver: true, // 在UI线程运行 }).start();
  1. 避免在动画中使用复杂布局
typescript
// 避免在动画组件中使用flex布局 const style = useAnimatedStyle(() => ({ transform: [{ translateX: translateX.value }], // 避免使用flex相关的属性 }));
  1. 使用shouldComponentUpdate优化
typescript
const AnimatedComponent = React.memo(({ value }) => { const animatedStyle = useAnimatedStyle(() => ({ opacity: value.value, })); return <Animated.View style={animatedStyle} />; });

最佳实践:

  1. 选择合适的动画库

    • 简单动画:React Native Animated
    • 复杂动画和手势:React Native Reanimated
    • 设计师创建的动画:Lottie
  2. 性能优先

    • 使用原生驱动
    • 避免在动画中使用复杂布局
    • 使用useMemo和useCallback优化
  3. 用户体验

    • 提供流畅的过渡效果
    • 避免过度动画
    • 考虑性能较差的设备
  4. 可访问性

    • 为动画提供替代方案
    • 尊重用户的减少动画偏好
    • 提供动画控制选项

通过合理使用动画,可以显著提升Expo应用的用户体验和交互质量。

标签:Expo