我是 Rive 的新手,我想在项目中使用它,但我不太清楚如何在点击后为其设置动画,我正在使用 https://editor.rive.app/preview/2063- 4080-flutter-puzzle-hack-project/381484?mode=animate&artboard=birb&animation=birb
我尝试使用此代码,但抛出错误“预期为‘SMITrigger’类型的值,但得到了‘SMIBool’类型之一
我尝试了点击后小鸟向上看
class GlassCard extends StatefulWidget {
const GlassCard({super.key});
@override
State<GlassCard> createState() => _GlassCardState();
}
class _GlassCardState extends State<GlassCard> {
String animation = 'idle';
//animation
Artboard? _birdArtboard;
SMITrigger? trigger;
StateMachineController? stateMachineController;
@override
void initState() {
super.initState();
rootBundle.load('assets/bird.riv').then(
(data) {
final file = RiveFile.import(data);
final artboard = file.mainArtboard;
stateMachineController =
StateMachineController.fromArtboard(artboard, "birb");
if (stateMachineController != null) {
artboard.addController(stateMachineController!);
trigger = stateMachineController!.findSMI('look up');
for (var e in stateMachineController!.inputs) {
debugPrint(e.runtimeType.toString());
debugPrint("name ${e.name} End");
}
trigger = stateMachineController!.inputs.first as SMITrigger;
}
setState(() => _birdArtboard = artboard);
},
);
}
void lookup() {
trigger?.fire();
}
@override
Widget build(BuildContext context) {
return Center(
child: SizedBox(
height: 400,
width: 400,
child: _birdArtboard == null
? const SizedBox()
: Center(
child: GestureDetector(
onTap: () {
lookup();
},
child: Rive(artboard: _birdArtboard!),
),
),
),
);
}
}
谢谢你
出现此错误的原因是代码中的以下行:-
trigger = stateMachineController!.inputs.first as SMITrigger;
原因是类型转换无效。
您不需要该线路来运行 rive 输入并与之交互。要与输入交互,您只需为变量使用正确的数据类型。我添加了一个小示例,只需轻按一下小鸟就会向上查找,然后双击即可启用和禁用小鸟的舞蹈。
完整代码:-
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:rive/rive.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'List',
theme: ThemeData(
primarySwatch: Colors.blue,
),
debugShowCheckedModeBanner: false,
home: const GlassCard(),
);
}
}
class GlassCard extends StatefulWidget {
const GlassCard({super.key});
@override
State<GlassCard> createState() => _GlassCardState();
}
class _GlassCardState extends State<GlassCard> {
String animation = 'idle';
Artboard? _birdArtboard;
SMITrigger? trigger;
SMIBool? dance;
StateMachineController? stateMachineController;
@override
void initState() {
super.initState();
rootBundle.load('assets/bird.riv').then(
(data) {
final file = RiveFile.import(data);
final artboard = file.mainArtboard;
stateMachineController =
StateMachineController.fromArtboard(artboard, "birb");
if (stateMachineController != null) {
artboard.addController(stateMachineController!);
trigger = stateMachineController!.findSMI('look up');
dance = stateMachineController!.findSMI('dance');
}
setState(() => _birdArtboard = artboard);
},
);
}
void lookup() {
trigger?.fire();
}
void danceBird() {
dance?.change(!dance!.value);
}
@override
Widget build(BuildContext context) {
return Center(
child: SizedBox(
height: 400,
width: 400,
child: _birdArtboard == null
? const SizedBox()
: Center(
child: GestureDetector(
onTap: () {
lookup();
},
onDoubleTap: () {
danceBird();
},
child: Rive(artboard: _birdArtboard!),
),
),
),
);
}
}
输出:-
在 Flutter 中使用 Rive 动画时,尝试使用以下方法转换输入时可能会遇到错误:
trigger = stateMachineController!.inputs.first as SMITrigger;
出现此错误是因为类型转换无效且不安全。
这是一个完整的工作示例,展示了如何正确处理 Rive 动画输入:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:rive/rive.dart';
class BirdAnimation extends StatefulWidget {
const BirdAnimation({Key? key}) : super(key: key);
@override
State<BirdAnimation> createState() => _BirdAnimationState();
}
class _BirdAnimationState extends State<BirdAnimation> {
Artboard? _birdArtboard;
SMITrigger? trigger;
SMIBool? dance;
StateMachineController? stateMachineController;
@override
void initState() {
super.initState();
_loadRiveFile();
}
Future<void> _loadRiveFile() async {
try {
final data = await rootBundle.load('assets/bird.riv');
final file = RiveFile.import(data);
final artboard = file.mainArtboard;
// Initialize state machine controller
stateMachineController = StateMachineController.fromArtboard(
artboard,
"birb" // Your state machine name
);
if (stateMachineController != null) {
artboard.addController(stateMachineController!);
// Properly find and initialize inputs
trigger = stateMachineController!.findSMI('look up');
dance = stateMachineController!.findSMI('dance');
}
setState(() => _birdArtboard = artboard);
} catch (e) {
print('Error loading Rive file: $e');
}
}
void _lookup() {
if (trigger != null) {
trigger!.fire();
}
}
void _toggleDance() {
if (dance != null) {
dance!.change(!dance!.value);
}
}
@override
void dispose() {
stateMachineController?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Center(
child: SizedBox(
height: 400,
width: 400,
child: _birdArtboard == null
? const CircularProgressIndicator()
: GestureDetector(
onTap: _lookup,
onDoubleTap: _toggleDance,
child: Rive(
artboard: _birdArtboard!,
fit: BoxFit.contain,
),
),
),
);
}
}
// Instead of unsafe casting:
// trigger = stateMachineController!.inputs.first as SMITrigger;
// Use findSMI to safely get inputs:
trigger = stateMachineController!.findSMI('look up');
dance = stateMachineController!.findSMI('dance');
try {
// Load and initialize Rive file
} catch (e) {
print('Error loading Rive file: $e');
}
void _lookup() {
if (trigger != null) {
trigger!.fire();
}
}
dependencies:
rive: ^0.12.4 # Use latest version
flutter:
assets:
- assets/bird.riv
GestureDetector(
onTap: _lookup, // Single tap to look up
onDoubleTap: _toggleDance, // Double tap to toggle dance
child: Rive(...),
)
// Check if input exists
final input = stateMachineController!.findSMI('input_name');
if (input == null) {
print('Input not found in state machine');
}
@override
void dispose() {
stateMachineController?.dispose();
super.dispose();
}
child: _birdArtboard == null
? const CircularProgressIndicator()
: Rive(artboard: _birdArtboard!),
class RiveInputs {
final SMITrigger? lookUp;
final SMIBool? dance;
RiveInputs({this.lookUp, this.dance});
static RiveInputs fromController(StateMachineController controller) {
return RiveInputs(
lookUp: controller.findSMI('look up'),
dance: controller.findSMI('dance'),
);
}
}
// Load file once and reuse
late final Future<RiveFile> _riveFile;
@override
void initState() {
super.initState();
_riveFile = rootBundle.load('assets/bird.riv')
.then((data) => RiveFile.import(data));
}
// Use const constructor
const BirdAnimation({Key? key}) : super(key: key);
// Cache artboard
final artboard = file.mainArtboard.instance();
print('Available state machines: ${file.mainArtboard.stateMachineNames}');
stateMachineController?.inputs.forEach((input) {
print('Input: ${input.name}, Type: ${input.runtimeType}');
});
dance?.addListener(() {
print('Dance state: ${dance!.value}');
});
记住:
您希望我更详细地解释任何特定部分吗?