查看: 99|回复: 0

鸿蒙 RNOH Animated 动画适配与性能优化

[复制链接]
发表于 半小时前 | 显示全部楼层 |阅读模式
React Native 的 Animated 是内置声明式动画库,核心概念并不多:Animated.Value、timing/spring/decay、interpolate 以及组合动画。但在鸿蒙上,它的表现与 iOS/Android 存在差异。原文基于 React Native 0.84 + RNOH 0.84.1,测试设备为 HarmonyOS 6.0,并说明示例代码已在鸿蒙设备上测试通过。不同版本之间可能存在差异,实际开发应以真机结果为准。

Animated 能做什么

Animated 提供声明式动画 API,不需要手动管理动画帧;支持 timing、spring、decay 三种动画类型;支持 sequence、parallel、stagger、loop 组合方式;支持 interpolate 插值运算;支持 useNativeDriver 原生动画驱动。常见使用场景包括页面过渡、列表项入场、按钮反馈、加载状态和手势驱动动画。

核心工作流

基本流程是:创建 Animated.Value 初始值,将 Value 绑定到 Animated 组件样式,调用 timing/spring/decay 驱动值变化,最后调用 start() 启动动画。典型淡入写法如下:
  1. const fadeAnim = useRef(new Animated.Value(0)).current;
  2. Animated.timing(fadeAnim, {
  3.   toValue: 1,
  4.   duration: 1000,
  5.   useNativeDriver: true,
  6. }).start();
复制代码

在 iOS 上启用 useNativeDriver 可以流畅运行,但在鸿蒙上某些属性可能不生效。遇到动画不显示时,可以先将 useNativeDriver 改为 false 排查。

三种动画类型与参数

timing 按时间变化,常用参数有 toValue、duration、easing、delay、useNativeDriver。Easing 包括 linear、ease、in、out、inOut、bounce、elastic、circle、bezier 等。

spring 使用弹簧物理模型,可以用 friction/tension,也可以用 stiffness/damping/mass。decay 以初始速度开始并逐渐衰减,velocity 必填,deceleration 默认 0.997。例如:
  1. Animated.spring(animValue, {
  2.   toValue: 1,
  3.   friction: 7,
  4.   tension: 40,
  5.   useNativeDriver: true,
  6. }).start();
复制代码

组合动画与 interpolate 插值

sequence 按顺序执行动画,parallel 同时执行多个动画,stagger 依次延迟启动,loop 循环执行,delay 延迟后启动。sequence 完成回调可以拿到 finished 状态。

interpolate 可以把一个数值范围映射到另一个范围,支持 number、带单位的 string,例如 10px、360deg、2rem,也支持 color。extrapolate 可以控制超出范围后的行为,clamp 限制在边界值,extend 允许延伸。鸿蒙上颜色插值可能不生效,替代方案包括使用透明度变化模拟颜色变化、切换不同颜色图片,或用 setNativeProps 直接设置。

useNativeDriver 的边界

useNativeDriver 为 true 时,动画在原生线程执行,不受 JS 线程阻塞影响。支持较好的属性主要是 opacity 和 transform,包括 translateX、translateY、scale、rotate 等。不支持 width、height、backgroundColor、borderRadius、margin、padding;left、top、right、bottom 在部分平台支持。对不支持的属性,需要设置 useNativeDriver: false。

鸿蒙上的关键坑在于:部分在 iOS/Android 上支持原生驱动的属性,在鸿蒙上可能不支持。因此不能只凭平台经验判断,需要在真机上分别测试 true 和 false 的实际表现。

动画组件与事件映射

Animated 默认提供 Animated.View、Animated.Text、Animated.Image、Animated.ScrollView、Animated.FlatList、Animated.SectionList。其他组件可以用 createAnimatedComponent 包装,例如把 Pressable 包成 AnimatedButton 后绑定动画值。

Animated.event 可以把滚动或手势事件直接映射到动画值,配合 scrollEventThrottle=16 使用。但在鸿蒙上,Animated.event 用于 ScrollView 滚动事件时可能不触发。可改为手动 onScroll 处理,确认 scrollEventThrottle 设置正确,并测试 useNativeDriver: false。

Animated.Value 还提供 setValue、setOffset、flattenOffset、__getValue、addListener、removeAllListeners 等方法;ValueXY 则用于 x/y 二维动画。

鸿蒙上的典型坑与处理

1. useNativeDriver 支持不完整:动画不显示时,先尝试 useNativeDriver: false。

2. 动画卡顿:减少同时执行的复杂动画,使用 InteractionManager.runAfterInteractions 延迟非关键动画,并在 useNativeDriver true/false 之间做性能测试。

3. 颜色插值可能失效:用透明度变化、图片切换或 setNativeProps 替代。

4. Animated.event 滚动事件不触发:改为手动 onScroll,检查 scrollEventThrottle,测试非原生驱动。

5. 组件卸载未停止动画:可能造成内存泄漏,需要在 useEffect 清理函数中及时 stop。

实战与性能优化

按钮反馈动画可以用 spring 驱动 scale,按下时到 0.95,松手回到 1。列表入场动画可以用 opacity 和 translateY 插值,配合 index*100 做依次延迟。

性能上优先使用 transform 动画,因为它在 GPU 上执行;避免 marginLeft 等布局属性动画。合理使用 useNativeDriver,避免无限 loop,及时停止动画:
  1. useEffect(() => {
  2.   const animation = Animated.timing(anim, {
  3.     toValue: 1,
  4.     duration: 500,
  5.     useNativeDriver: true,
  6.   }).start();
  7.   return () => animation.stop();
  8. }, []);
复制代码

给鸿蒙开发者的建议

在真机上测试 useNativeDriver,优先使用 transform,避免复杂动画,组件卸载时清理动画,并持续关注 RNOH 更新。原文基于 React Native 0.84 + RNOH 0.84.1、HarmonyOS 6.0,Animated 在鸿蒙上的支持仍在不断完善,很多问题可能已有新的解决方案。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-9-15 10:50 , Processed in 0.023910 second(s), 17 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部