Flutter Rive 点击后动画

问题描述 投票:0回答:2

我是 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!),
                ),
              ),
      ),
    );
  }
}

谢谢你

flutter flutter-dependencies flutter-animation
2个回答
2
投票

出现此错误的原因是代码中的以下行:-

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!),
                    ),
                  ),
          ),
        );
      }
    }

输出:-


0
投票

Flutter:修复 Rive 动画控制器类型转换错误

问题

在 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,
                ),
              ),
      ),
    );
  }
}

要点

  1. 正确的输入初始化
// 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');
  1. 错误处理
try {
  // Load and initialize Rive file
} catch (e) {
  print('Error loading Rive file: $e');
}
  1. 零安全
void _lookup() {
  if (trigger != null) {
    trigger!.fire();
  }
}

使用指南

  1. 添加Rive依赖
dependencies:
  rive: ^0.12.4  # Use latest version
  1. 将资产添加到 pubspec.yaml
flutter:
  assets:
    - assets/bird.riv
  1. 在 Rive 中创建状态机
  • 为您的状态机命名(例如“birb”)
  • 创建输入:
    • “查找”触发器
    • “舞蹈”布尔值
  1. 实现互动
GestureDetector(
  onTap: _lookup,      // Single tap to look up
  onDoubleTap: _toggleDance,  // Double tap to toggle dance
  child: Rive(...),
)

常见问题及解决方案

  1. 未找到输入
// Check if input exists
final input = stateMachineController!.findSMI('input_name');
if (input == null) {
  print('Input not found in state machine');
}
  1. 控制器处置
@override
void dispose() {
  stateMachineController?.dispose();
  super.dispose();
}
  1. 加载状态
child: _birdArtboard == null
    ? const CircularProgressIndicator()
    : Rive(artboard: _birdArtboard!),

最佳实践

  1. 类型安全输入管理
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'),
    );
  }
}
  1. 资源管理
// 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));
}
  1. 性能优化
// Use const constructor
const BirdAnimation({Key? key}) : super(key: key);

// Cache artboard
final artboard = file.mainArtboard.instance();

调试技巧

  1. 检查状态机名称
print('Available state machines: ${file.mainArtboard.stateMachineNames}');
  1. 验证输入
stateMachineController?.inputs.forEach((input) {
  print('Input: ${input.name}, Type: ${input.runtimeType}');
});
  1. 监控状态变化
dance?.addListener(() {
  print('Dance state: ${dance!.value}');
});

记住:

  • 使用正确的类型安全方法来访问输入
  • 适当处理 null 情况
  • 完成后丢弃控制器
  • 添加适当的错误处理
  • 彻底测试交互

您希望我更详细地解释任何特定部分吗?

© www.soinside.com 2019 - 2024. All rights reserved.