使用Rive实现动画时触发空值校验异常求助
解决Rive动画切换状态时的空值校验异常
问题现象
触发空值校验异常:
════════ Exception caught by widgets library ═══════════════════════════════════ Null check operator used on a null value
使用Rive实现Flutter Dash动画,切换Waving和Flying状态时触发上述异常。
异常原因
- 异步加载未完成时的空断言:
initState中异步加载Rive资源,build方法执行时资源可能还未加载完毕,此时artboard、isWaving等变量仍为null,直接使用!空断言会触发异常。 - 状态参数名称拼写错误:代码中使用
isFlyng,但动画实际的状态参数应为isFlying(缺少字母i),导致controller.findSMI('isFlyng')返回null,后续调用isFlyng!.value触发异常。 - 空值未做安全处理:所有状态变量和
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
相关产品推荐
相关产品推荐

