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

使用Rive实现动画时触发空值校验异常求助

解决Rive动画切换状态时的空值校验异常

问题现象

触发空值校验异常:

════════ Exception caught by widgets library ═══════════════════════════════════
Null check operator used on a null value

使用Rive实现Flutter Dash动画,切换Waving和Flying状态时触发上述异常。

异常原因

  1. 异步加载未完成时的空断言:initState中异步加载Rive资源,build方法执行时资源可能还未加载完毕,此时artboard、isWaving等变量仍为null,直接使用!空断言会触发异常。
  2. 状态参数名称拼写错误:代码中使用isFlyng,但动画实际的状态参数应为isFlying(缺少字母i),导致controller.findSMI('isFlyng')返回null,后续调用isFlyng!.value触发异常。
  3. 空值未做安全处理:所有状态变量和artboard均直接使用!断言,未处理null情况。

解决方案

修正后的代码

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:rive/rive.dart';
import '../../configs/assets/assets_path.dart';
import '../../widgets/cs_app_bar.dart';
import '../../widgets/cs_button_home.dart';

class HomeView extends StatefulWidget {
  const HomeView({super.key});

  @override
  State<HomeView> createState() => _HomeViewState();
}

class _HomeViewState extends State<HomeView> {
  Artboard? artboard;
  SMIBool? isWaving;
  SMIBool? isWiking;
  SMIBool? isFlying; // 修正拼写错误

  @override
  void initState() {
    super.initState();
    loadRiveAnimation();
  }

  Future<void> loadRiveAnimation() async {
    try {
      final data = await rootBundle.load('assets/flutter-dash.riv');
      final file = RiveFile.import(data);
      final art = file.mainArtboard;
      final controller = StateMachineController.fromArtboard(art, 'State Machine 1');
      if (controller != null) {
        art.addController(controller);
        isWaving = controller.findSMI('isWaving') as SMIBool?;
        isWiking = controller.findSMI('isWiking') as SMIBool?;
        isFlying = controller.findSMI('isFlying') as SMIBool?; // 匹配动画实际参数名
      }
      setState(() => artboard = art);
    } catch (e) {
      debugPrint('加载Rive动画失败: $e');
    }
  }

  void toggleWaving(bool newValue) {
    if (isWaving != null) {
      setState(() => isWaving!.value = newValue);
    }
  }

  void toggleWiking(bool novoValue) {
    if (isWiking != null) {
      setState(() => isWiking!.value = novoValue);
    }
  }

  void toggleFlying(bool newValue) {
    if (isFlying != null) {
      setState(() => isFlying!.value = newValue);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: const CsAppBar(
        title: 'Testes',
      ),
      body: ListView(
        children: [
          SizedBox(
            height: 300,
            width: 400,
            child: artboard != null 
                ? Rive(artboard: artboard!) 
                : const Center(child: CircularProgressIndicator()), // 加载中占位符
          ),
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              const Text('Waving'),
              Switch(
                value: isWaving?.value ?? false, // 空值时默认显示关闭状态
                onChanged: toggleWaving,
              ),
            ],
          ),
          const SizedBox(height: 12),
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              const Text('Wiking'),
              Switch(
                value: isWiking?.value ?? false,
                onChanged: toggleWiking,
              ),
            ],
          ),
          const SizedBox(height: 12),
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              const Text('Flying'), // 修正显示文本
              Switch(
                value: isFlying?.value ?? false,
                onChanged: toggleFlying,
              ),
            ],
          ),
          const SizedBox(height: 12),
        ],
      ),
    );
  }
}

关键优化点

  • 异步加载优化:将加载逻辑抽为单独的异步方法,用await提升代码可读性,同时捕获加载异常并打印日志。
  • 空安全处理:
    • artboard未初始化时显示CircularProgressIndicator占位符,避免直接渲染未就绪的Rive组件。
    • Switch的value使用?.value ?? false处理空值,默认显示关闭状态。
    • 状态切换方法中先判断变量是否为null,再执行赋值操作,避免空断言异常。
  • 拼写修正:将isFlyng改为isFlying,匹配Rive动画中的实际状态参数名称。

内容的提问来源于stack exchange,提问作者user22228636

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 02:44:57