服务端阅读 05月30日 23:22
React Native 中如何正确接入 Lottie 动画?
在 React Native 里接入 Lottie,核心不是把组件渲染出来,而是把安装、资源路径、播放控制和性能边界都处理好。很多项目第一次接入能跑,后面却在 Android 缺资源、iOS 没 pod、列表卡顿、远程 JSON 加载失败上反复踩坑。建议把 Lottie 当成一种需要生命周期管理的原生视图,而不是普通图片组件。安装和基础配置常规项目先安装 lottie-react-native,iOS 再执行 Pod 安装。Expo 项目要确认 SDK 版本支持的 Lottie 版本,不要随意升级到不匹配的包。动画 JSON 可以用本地 require,也可以远程加载;稳定性优先的启动页、支付成功、空状态动画,建议随包发布。npm install lottie-react-nativecd ios && pod installimport LottieView from 'lottie-react-native';import { useEffect, useRef } from 'react';export function LoadingLottie() { const ref = useRef<LottieView>(null); useEffect(() => { ref.current?.play(); return () => ref.current?.reset(); }, []); return ( <LottieView ref={ref} source={require('./assets/loading.json')} autoPlay={false} loop style={{ width: 120, height: 120 }} /> );}播放控制要跟页面状态绑定autoPlay 很方便,但复杂页面不建议到处开。更稳的方式是用 ref 控制 play、pause、reset,并在页面不可见、弹窗关闭或列表项离屏时暂停。进度联动可以用 progress,但频繁从 JS 更新 progress 会有成本,手势场景要特别留意掉帧。function ResultAnimation({ active }: { active: boolean }) { const ref = useRef<LottieView>(null); useEffect(() => { if (active) ref.current?.play(0, 60); else ref.current?.pause(); }, [active]); return <LottieView ref={ref} source={require('./success.json')} loop={false} />;}Android 和 iOS 的边界不完全一样Android 更容易遇到硬件加速、图片资源目录和低端机掉帧问题;iOS 更常见的是 Pod、版本兼容和资源打包问题。不要把一端验证通过当成全端通过,尤其是包含渐变、遮罩、文本图层的动画。上线前至少用一台低端 Android 和一台旧 iPhone 跑真实页面,不要只看模拟器。推荐的组件封装业务里可以封一层轻量组件,把尺寸、循环、错误降级和播放时机收口。这样设计更新动画时,页面不用到处改参数;如果某个版本播放器有兼容问题,也能集中降级。封装不要太厚,保留 source、loop、onAnimationFinish 这类常用能力即可。type Props = { source: object; active: boolean; size?: number };export function AppLottie({ source, active, size = 120 }: Props) { const ref = useRef<LottieView>(null); useEffect(() => { active ? ref.current?.play() : ref.current?.pause(); }, [active]); return <LottieView ref={ref} source={source} style={{ width: size, height: size }} />;}远程加载要有降级和缓存如果业务必须远程下发 JSON,至少要准备加载中占位、失败静态图和版本缓存。接口返回后不要直接相信内容可播放,可以先校验 fr、op、layers 等关键字段,再交给 LottieView。否则一次错误配置就可能让页面出现空白区域,用户不会知道这是动画资源坏了,只会觉得页面没做好。缓存也要有边界。运营动画可以短缓存,关键流程动画最好随 App 版本固定,避免服务端改动影响老客户端。需要灰度时,可以把动画版本号写进配置,出现兼容问题时回滚到上一个 JSON,而不是临时发版。追问本地 JSON 和远程 JSON 应该怎么选?本地 JSON 稳定、首屏可控,适合关键流程和无网也要展示的动画。远程 JSON 灵活,适合运营活动、节日皮肤和可灰度替换的内容,但要处理加载失败、缓存和版本回滚。取舍在于更新频率和可靠性:越关键越本地,越运营越远程。踩坑点是远程 JSON 改了字段后旧 App 播放器不兼容,结果线上动画直接空白。autoPlay 和手动 play() 有什么区别?autoPlay 会在组件挂载后自动开始,写法简单,适合单个静态页面。手动 play() 可以跟页面焦点、弹窗状态、接口完成时机绑定,更适合真实业务。边界是如果组件频繁挂载卸载,autoPlay 可能导致动画重复从头播放,看起来像闪烁。复杂页面里宁愿多写几行生命周期控制,也不要让动画自己乱跑。React Native 列表里使用 Lottie 为什么容易卡?列表滚动时,LottieView 作为原生视图创建成本不低,多个动画同时播放会叠加解析和绘制压力。更稳的做法是默认显示静态首帧,只有选中、曝光或需要强调的 item 才播放。FlatList 参数也要控制窗口大小和初始渲染数量。取舍是视觉动感少一点,但滚动不会被动画拖垮。动态换色应该改 JSON 还是用 colorFilters?如果只有少量主题色,设计导出多份 JSON 最稳,测试成本低。需要运行时跟随品牌色或暗黑模式时,可以用 colorFilters,但前提是图层 keypath 命名稳定。踩坑是设计改了图层名,客户端过滤器失效却不报错。边界是渐变、图片、预合成里的颜色不一定能被简单过滤器覆盖。动画不显示时应该按什么顺序排查?先确认 JSON 能在 LottieFiles 或设计工具里正常预览,再看 RN 资源路径、包版本和平台构建日志。Android 缺图片时检查资源目录,iOS 异常时先确认 pod install 和 clean build。然后再排查样式尺寸,因为 width/height 为 0 也会让你误以为动画坏了。不要一开始就重装依赖,很多问题其实只是路径或容器尺寸。