Flutter中调用setState()后RiveAnimation.asset未更新问题
问题:Flutter切换明暗模式时Rive动画未切换
切换应用明暗模式时,主文件的setState()触发组件重建,其中一个Rive动画组件的代码如下:
RiveAnimation.asset( Theme.of(context).brightness == Brightness.light ? 'assets/RiveAssets/button.riv' : 'assets/RiveAssets/button_dark.riv', controllers: [_btnAnimationController], ),
调试可见这段代码会执行,但运行时Rive动画并未切换。换成Icon或Image组件使用相同的主题判断逻辑,却能正常切换资源。
主文件State组件代码:
class _MyAppState extends State<MyApp> { Brightness brightness = Brightness.dark; void toggleBackgroundColor() { setState(() { brightness = brightness == Brightness.dark ? Brightness.light : Brightness.dark; }); } @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData( brightness: brightness, appBarTheme: const AppBarTheme( color: Colors.transparent, ), ), home: Scaffold( appBar: CustomAppBar(onColorToggle: toggleBackgroundColor), body: OnbodingScreen(), ), ); } }
Rive组件位于OnbodingScreen()内部,问题根源是Rive包的资源缓存机制。
原因分析
RiveAnimation.asset会缓存已加载的动画资源实例,即使传入的asset路径变化,它也会复用之前缓存的实例,不会自动重新加载新的Rive文件,导致主题切换时动画不更新。而Icon/Image组件内部会根据路径变化自动触发资源重新加载,所以能正常工作。
解决方案
方案1:添加Key强制组件重建
给RiveAnimation.asset绑定一个与主题亮度关联的Key,每次亮度变化时,Flutter会识别为新组件并重建,从而加载对应主题的Rive资源:
RiveAnimation.asset( Theme.of(context).brightness == Brightness.light ? 'assets/RiveAssets/button.riv' : 'assets/RiveAssets/button_dark.riv', controllers: [_btnAnimationController], key: ValueKey(Theme.of(context).brightness), // 新增Key绑定亮度 ),
方案2:手动加载Rive资源并监听主题变化
如果不想重建组件,可以手动管理Rive文件的加载,在主题变化时重新加载对应资源:
class _OnbodingScreenState extends State<OnbodingScreen> { RiveFile? _riveFile; final _btnAnimationController = StateMachineController.fromArtboard(...); // 你的动画控制器初始化 @override void didChangeDependencies() { super.didChangeDependencies(); // 主题变化时重新加载资源 _loadMatchingRiveFile(); } Future<void> _loadMatchingRiveFile() async { final assetPath = Theme.of(context).brightness == Brightness.light ? 'assets/RiveAssets/button.riv' : 'assets/RiveAssets/button_dark.riv'; final newFile = await RiveFile.asset(assetPath); if (mounted) { setState(() => _riveFile = newFile); } } @override Widget build(BuildContext context) { return _riveFile != null ? RiveAnimation.direct( _riveFile!, controllers: [_btnAnimationController], ) : const CircularProgressIndicator(); // 加载占位 } }
内容的提问来源于stack exchange,提问作者Gio
相关产品推荐
相关产品推荐

