深入理解 Reanimated 布局动画:从 Participant 组件内部结构到 Animated.View 的接入改造

发布时间:2026/9/16 0:44:13

深入理解 Reanimated 布局动画:从 Participant 组件内部结构到 Animated.View 的接入改造 深入理解 Reanimated 布局动画从 Participant 组件内部结构到 Animated.View 的接入改造【免费下载链接】react-native-reanimatedReact Natives Animated library reimplemented项目地址: https://gitcode.com/GitHub_Trending/re/react-native-reanimated导读在 React Native 中组件的挂载与卸载默认是瞬间完成的——新增一个列表项它立即出现在界面上移除一个列表项它在下一帧直接消失。react-native-reanimated 从 v2.3.0 开始引入的Layout Animations布局动画正是为了解决这一痛点它允许你为组件的「进入entering」「退出exiting」以及「布局位置变化layout」三类场景接入预设动画让列表增删、弹窗显隐等交互变得平滑自然。本文以 Reanimated 官方教程中的参与者Participant列表为例剖析待动画化组件的内部结构_participantInternals.md并以此为起点逐步完成从普通View到Animated.View的改造最终叠加entering、layout、exiting三类动画。读完本文你将掌握哪些组件可以被布局动画驱动、为什么必须使用 Reanimated 提供的动画组件、以及如何用LightSpeedInLeft、LightSpeedOutRight、Layout.springify()在真实列表场景中落地。一、教程背景准备动画化的 Participant 列表官方教程见 animated_list.mdx基于一个已有的「参与者列表」界面用户可以通过底部输入框添加参与者姓名也可以点击每个列表项上的红色 Remove 按钮将其删除。列表由ScrollView承载通过participantList.map(...)渲染出多个Participant组件ScrollView style{[{ width: 100% }]} {participantList.map((participant) ( Participant key{participant.id} name{participant.name} onRemove{() removeParticipant(participant.id)} / ))} /ScrollView列表数据层的完整逻辑完整代码见 _fullCode.md如下const [inputValue, setInputValue] useState(); const [participantList, setParticipantList] useStateEventParticipant[]([]); const addParticipant () { setParticipantList( [{ name: inputValue, id: Date.now().toString() }].concat(participantList) ); setInputValue(); }; const removeParticipant (id: string) { setParticipantList( participantList.filter((participant) participant.id ! id) ); };可以看到新参与者通过concat插入到数组头部因此会出现在列表最上方删除时通过filter按id过滤对应行会被移除key{participant.id}使用Date.now().toString()生成唯一 id保证 React 能正确识别每一个列表项。在没有布局动画时插入与删除都是「闪现」式的新项瞬间出现、被删项瞬间消失其余项瞬间上移/下移填补空位。这正是后续要改造的体验痛点。二、Participant 组件内部结构解析关联文档核心Participant组件负责渲染单个列表项它是我们后续所有动画的载体。其内部结构见 _participantInternals.md非常简单——只包含一个根View、一行姓名文本和一个红色删除按钮function Participant({ name, onRemove, }: { name: string; onRemove: () void; }) { return ( View style{[styles.participantView]} Text{name}/Text Button titleRemove colorred onPress{onRemove} / /View ); }拆解该组件的职责部分说明根Viewstyles.participantView列表项的容器负责整行的布局与样式是布局动画要挂载的位置Text展示参与者姓名nameButton红色Remove触发onRemove回调从列表中删除当前项2.1 为什么动画必须加在根 View 上教程明确指出Participant 组件被包在一个 View 组件中这正是我们添加动画的位置。原因在于布局动画需要作用于「一个独立、可整体感知自身几何变化」的视图节点进入/退出动画需要视图从初始状态如屏幕外偏移 倾斜 透明过渡到最终状态或反向过渡这要求动画作用在代表整个列表项的单个视图上布局动画当列表项因兄弟节点增删而改变位置或尺寸时动画需要驱动该视图的originX/originY/width/height从旧值过渡到新值。如果把动画拆散到内部的Text或Button上整个列表项的进入/退出/位移就会失去整体性效果割裂且难以维护。2.2 可动画化的组件边界Animated.View 与 createAnimatedComponent这是整个教程中最重要的技术约束我们只能对由 Reanimated 提供的组件如Animated.View或通过createAnimatedComponent包装过的自定义组件施加布局动画。普通 React Native 的View不具备 Reanimated 的动画挂载点传入entering/exiting/layout属性不会产生任何效果。从当前仓库源码 Animated.ts 可以看到Reanimated 的Animated命名空间导出了一组内置动画组件export { ReanimatedFlatList as FlatList } from ./component/FlatList; export { AnimatedImage as Image } from ./component/Image; export { AnimatedScrollView as ScrollView } from ./component/ScrollView; export { AnimatedText as Text } from ./component/Text; export { AnimatedView as View } from ./component/View; export { createAnimatedComponent } from ./createAnimatedComponent;也就是说常用基础组件View、Text、Image、ScrollView、FlatList都有对应的Animated.*版本可直接使用对于自定义组件或第三方组件则需要通过createAnimatedComponent由 src/index.ts 对外导出包装后使用例如const AnimatedCustomView createAnimatedComponent(CustomView);。在本文的列表场景中Participant的根元素是基础View因此最直接的做法就是用Animated.View替换它。三、Step 1将 View 替换为 Animated.View改造的第一步见 _step1.md是引入Animated并将根View换成Animated.Viewimport Animated from react-native-reanimated; function Participant({ name, onRemove, }: { name: string; onRemove: () void; }) { return ( Animated.View style{[styles.participantView]} Text{name}/Text Button titleRemove colorred onPress{onRemove} / /Animated.View ); }这一步本身不会产生可见的动画它的意义在于为组件打开接收 Reanimated 布局动画属性的通道。替换之后Animated.View实例就能识别并处理entering、exiting、layout三个专有属性。样式styles.participantView保持不变因此界面上没有任何视觉回归。四、Step 2添加进入动画 entering有了Animated.View之后就可以叠加进入动画见 _step2.md。Reanimated 内置了大量预设的进入动画如FadeIn、SlideInRight、ZoomIn、BounceIn等这里教程选择视觉效果强烈的LightSpeedInLeftimport Animated, {LightSpeedInLeft} from react-native-reanimated; function Participant({ name, onRemove, }: { name: string; onRemove: () void; }) { return ( Animated.View entering{LightSpeedInLeft} style{[styles.participantView]} Text{name}/Text Button titleRemove colorred onPress{onRemove} / /Animated.View ); }效果每当新参与者被添加到列表组件挂载时它会带着「从左侧高速飞入 倾斜摆动 透明度渐变」的复合效果出现而不是瞬间闪现。4.1 LightSpeed 系列动画的底层实现LightSpeedInLeft并非黑盒魔法它在当前仓库源码 Lightspeed.ts 中定义继承自ComplexAnimationBuilder其build()方法返回一个在 UI 线程运行的 worklet核心动画编排如下return (values: EntryExitAnimationsValues) { worklet; return { animations: { opacity: delayFunction( delay, withTiming(targetValues?.opacity ?? 1, { duration }) ), transform: [ { translateX: delayFunction( delay, animation(targetTranslateX, { ...config, duration: duration * 0.7 }) ), }, { skewX: delayFunction( delay, withSequence( withTiming(-10deg, { duration: duration * 0.7 }), withTiming(5deg, { duration: duration * 0.15 }), withTiming(targetSkewX, { duration: duration * 0.15 }) ) ), }, ], }, initialValues: { opacity: initialValues?.opacity ?? 0, transform: pickTransformValues( [{ translateX: -values.windowWidth }, { skewX: 45deg }], initialValues ), }, }; };从这段实现可以读出几个关键细节初始状态translateX从-windowWidth屏幕宽度之外的左侧开始skewX初始为45degopacity从 0 开始位移动画水平位移在 70% 的时长内完成主要行程营造高速冲刺感倾斜动画用withSequence串联三段withTiming-10deg → 5deg → 0deg分别占用 70% / 15% / 15% 的时长产生「冲过头再回正」的摆动回弹效果透明度与位移同步从 0 过渡到 1。同一文件还定义了LightSpeedInRight、LightSpeedOutLeft、LightSpeedOutRight等系列动画方向相反、编排对称。这也解释了为什么教程标题强调「组件内部结构」——动画的全部初始值与关键帧编排都建立在列表项这个单一视图的几何信息之上。五、Step 3添加布局过渡 layout接下来为列表项添加布局过渡动画见 _step3.md。这一步解决的是「兄弟项移动」的动画当某个参与者被删除后它下方的所有列表项会向上移动填补空位当新项插入时原有项会向下让位。默认情况下这些位移是瞬间完成的通过layout属性可以让它们平滑过渡import Animated, { LightSpeedInLeft, Layout } from react-native-reanimated; function Participant({ name, onRemove, }: { name: string; onRemove: () void; }) { return ( Animated.View entering{LightSpeedInLeft} layout{Layout.springify()} style{[styles.participantView]} Text{name}/Text Button titleRemove colorred onPress{onRemove} / /Animated.View ); }这里的Layout是线性过渡LinearTransition的别名。查看源码 LinearTransition.ts 末尾/** deprecated Please use {link LinearTransition} instead. */ export const Layout LinearTransition;LinearTransition的build()会返回一个 worklet它基于布局前后快照对originX、originY、width、height四个几何量做插值过渡return (values) { worklet; return { initialValues: { originX: values.currentOriginX, originY: values.currentOriginY, width: values.currentWidth, height: values.currentHeight, }, animations: { originX: delayFunction(delay, animation(values.targetOriginX, config)), originY: delayFunction(delay, animation(values.targetOriginY, config)), width: delayFunction(delay, animation(values.targetWidth, config)), height: delayFunction(delay, animation(values.targetHeight, config)), }, }; };也就是说布局动画的实质是「记录当前位置/尺寸 → 在下一帧得知目标位置/尺寸 → 让几何属性平滑变化」。5.1 链式修饰器springify 与更多定制手段Layout.springify()中的springify是一个链式修饰器modifier来自基类AnimationConfigBuilder实现于 ComplexAnimationBuilder.ts。其核心实现springify(duration?: number): this { this.durationV duration; this.type withSpring as AnimationFunction; return this; }它做了两件事将底层动画函数替换为withSpring弹簧动画使过渡带有一点弹性过冲可选地传入一个以毫秒为单位的duration来约束弹簧时长。同一个基类还提供了一系列可链式组合的修饰器例如duration(milliseconds)设置动画时长delay(milliseconds)设置动画延迟easing(easingFunction)自定义缓动曲线dampingRatio(ratio)/damping(damping)/stiffness(stiffness)/mass(mass)调整弹簧物理参数withCallback(callback)动画结束时回调rotate(degree)、randomDelay()等。这些修饰器同样作用于entering/exiting预设动画例如LightSpeedInLeft.springify()或LightSpeedInLeft.duration(500)这正是源码注释中所说的「You can modify the behavior by chaining methods like.springify()or.duration(500)」。六、Step 4添加退出动画 exiting最后一步为列表项添加退出动画见 _step4.md。与进入动画对称Reanimated 也提供了丰富的预设退出动画教程选用LightSpeedOutRightimport Animated, { LightSpeedInLeft, LightSpeedOutRight, Layout } from react-native-reanimated; function Participant({ name, onRemove, }: { name: string; onRemove: () void; }) { return ( Animated.View entering{LightSpeedInLeft} exiting{LightSpeedOutRight} layout{Layout.springify()} style{[styles.participantView]} Text{name}/Text Button titleRemove colorred onPress{onRemove} / /Animated.View ); }至此Animated.View上同时挂载了三类动画属性取值触发时机动画效果enteringLightSpeedInLeft组件挂载添加参与者从左侧高速飞入伴随倾斜摆动与淡入layoutLayout.springify()兄弟项增删导致位置变化弹性平滑移动到新位置exitingLightSpeedOutRight组件卸载删除参与者向右高速飞出伴随倾斜摆动与淡出6.1 退出动画的底层编排LightSpeedOutRight与进入动画方向相反初始状态是当前静止位置translateX: 0、skewX: 0deg、opacity: 1动画目标是translateX: windowWidth飞出屏幕右侧、skewX: -45deg、opacity: 0。从 Lightspeed.ts 的实现可见其编排与LightSpeedInLeft完全对称return (values: EntryExitAnimationsValues) { worklet; return { animations: { opacity: delayFunction(delay, animation(targetValues?.opacity ?? 0, config)), transform: animateTransformToValues( [{ translateX: values.windowWidth }, { skewX: -45deg }], targetValues, animationAndConfig, delayFunction, delay ), }, initialValues: { opacity: initialValues?.opacity ?? 1, transform: pickTransformValues( [{ translateX: 0 }, { skewX: 0deg }], initialValues ), }, }; };值得注意的工程细节exiting 动画完成后组件才会真正从视图树中移除。这意味着 React Native 的卸载过程不会打断退出动画动画播放完毕后再销毁原生视图从而避免「动画刚播一帧就被卸载」的闪烁问题。七、完整代码与进阶阅读将以上四步汇总即得到完整的动画化列表。数据层完整实现可参考 fullCode.md。整个改造过程仅需三个要点用Animated.View作为动画载体、为增删改挂载entering/exiting/layout三个属性、用链式修饰器微调动画手感。如果想进一步深入当前仓库与文档还提供了以下素材预设动画全集进入/退出动画的完整清单与参数说明见 EntryAnimations.md 与 ExitAnimations.md布局过渡与自定义动画LayoutTransitions.md 讲解线性、序列、跳跃等过渡方案CustomAnimations.md 介绍如何手写动画KeyframeAnimations.md 则支持基于关键帧的编排概念总览布局动画的设计动机与适用范围见 layout_animations.md源码位置LightSpeed系列在 defaultAnimations/Lightspeed.ts线性过渡在 defaultTransitions/LinearTransition.ts链式修饰器基类在 animationBuilder/ComplexAnimationBuilder.ts。八、小结回顾整条改造链路_participantInternals.md这一节虽然只展示了一个看似普通的View包裹结构但它承载了布局动画的全部前提动画必须作用在单一根视图上才能保证列表项整体进入/退出/移动的一致性普通组件不具备动画能力必须换成Animated.*内置组件或经createAnimatedComponent包装的组件在此基础上entering、layout、exiting三个属性分别接管组件的出现、位移与消失配合springify、duration等链式修饰器即可精细控制动画手感。通过源码我们可以看到这些预设动画本质上都是在 UI 线程运行的 worklet它们读取视图的几何快照windowWidth、currentOriginX/Y、targetOriginX/Y等用withTiming、withSpring、withSequence组合出复杂的运动轨迹。理解了这个机制你不仅会使用现成预设还能基于 CustomAnimations.md 构建属于自己的布局动画。【免费下载链接】react-native-reanimatedReact Natives Animated library reimplemented项目地址: https://gitcode.com/GitHub_Trending/re/react-native-reanimated创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/16 0:39:13

基于MATLAB的汽车车型识别系统设计与实现

1. 项目概述汽车车型识别系统是计算机视觉领域的一个经典应用场景。这个基于MATLAB开发的系统,能够通过图像处理技术自动识别车辆的品牌和型号。在实际应用中,这类系统可以用于智能停车场管理、交通流量统计、4S店客户分析等多个场景。我最初开发这个系统…

2026/9/16 0:39:13

微信小程序毕设源码从导入到答辩:避坑指南与实战拆解

简介:面向微信小程序开发学习与期末毕设场景,这份模仿设计社区风格的小程序前端源码,特别适合前端入门者与高校学生参照完成课程设计或毕业设计项目。包体一共包含四十二个文件,其中十八个图片素材负责界面视觉呈现,七…

2026/9/16 1:24:15

MVCC原理与实战:ReadView、undo链及长事务排查

多版本并发控制(MVCC)这六个字,但凡做过后端开发或者数据库运维的人都见过。面经里它是高频八股,生产环境里它却是各种疑难杂症的病根:明明没有死锁,事务却一直报锁等待超时;明明数据量没涨多少…

2026/9/16 1:24:15

多模态图神经网络实现药物相互作用预测实战

简介:面向深度学习毕业设计、课程设计与期末大作业场景,这份压缩包提供了一套基于多模态图神经网络(Decagon)的药物相互作用预测完整实现。项目以图结构建模药物节点与相互作用边,融合药物化学结构、生物信息等多模态数…

2026/9/16 1:24:15

Genesis物理引擎实战:轻量级确定性刚体仿真与可复现实验

第一次看到 Genesis 这个名字,是在 GitHub 机器人话题下刷到的。当时刚结束一个强化学习对比实验,被旧引擎的随机性整得头疼:同一份代码跑三遍,三个轨迹,很难判断策略是真的进步还是随机波动。所以当我看到“确定性刚体…

2026/9/16 1:24:15

51单片机循迹小车实战:五路传感器+霍尔测速+蓝牙PID控制

简介:这是一份面向嵌入式初学者与单片机课程实践者的综合性51单片机项目资源,聚焦智能小车核心功能开发——循迹控制、蓝牙遥控与实时测速,解决从硬件驱动到闭环控制的典型工程问题。压缩包共17个文件,含7个C源码(如ma…

2026/9/16 1:24:15

LSTM多维时间序列输入与异常检测实战:从数据切分到阈值设定

前阵子有个做设备状态监测的朋友跑来问我,说他用LSTM做时序预测跑得挺顺,但一到异常检测就懵了——报错信息翻来覆去都是维度对不上,x_train.shape怎么 reshape 都不对。他这个问题特别典型,因为大家习惯了把LSTM当成"预测神…

2026/9/16 1:19:15

常微分方程边值问题求解:打靶法原理、Python实现与调参实践

简介:面向需要处理常微分方程边界值问题的数值计算学习者,这份资源提供了Matlab实现的打靶法(Shooting Method)求解程序。打靶法通过将边界值问题转化为初值问题,配合初始猜测、迭代优化和收敛判断等步骤逼近精确解&am…

2026/9/15 4:54:30

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/16 0:04:09

PHP源码部署实战:从环境配置到运行情侣游戏全攻略

简介:这是一套面向情侣互动场景的PHP完整源码,集成情侣飞行棋、真心话大冒险、情趣骰子等玩法,并内置完整分销制度,可自定义多种返佣比例,源码完全开源无加密,支持微信无感自动授权登录与第三方授权&#x…

2026/9/15 14:22:53

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/15 21:31:11

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/15 11:42:23

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码