You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 16:13:40