赞
踩
感觉官方的案例对我这种level的开发者来说感觉的真的很晦涩,也没什么像样的中文文档,所以做了些尝试,大致理解了一些基本的使用方式。有些较为复杂的素材琢磨不明白,然后把自己所知的做一个总结吧。
首先是通过RiveAnimation组件加载的三种方式,分别可以通过asset资源文件、网络url和本地文件进行动画加载。
以及通过RiveAnimationController控制动画的暂停与播放。
还有一种加载方法是通过直接加载文件并解析转化成RivaFile类型,获取一个所谓artboard的画板,然后通过这个画板获取一个StateMachineController的状态器,接下来在状态其中通过findSMI和findInput方法获取到可执行的动画。动画的名称通过rive网站的editor打开自己查看,这里接似懂非懂了,见得的动画基本按照编辑器里的名称来就可以,有些复杂类型的小游戏实在是没明白怎么加载,按常规动画那套搞我没搞出来。有明白的可以指教下。主要还是findSMI可以找到SMITrigger这种类型的动画控制器,过过调用其实例的fire方法执行动画,还有findInput方法获得的SMIInput实例,通过传入泛型,double、bool等控制数值发生变化来触动动画的执行。具体的可以看下下面的一些案例,效果和代码都贴出来了,仅供参考,互相学习。
Flitter rive加载组件 rive: ^0.9.1
Rive素材
下面的代码分别演示Rive加载动画文件的三种方式。
-
- import 'dart:io';
-
- import 'dart:typed_data';
-
- import 'package:flutter/material.dart';
-
- import 'package:flutter/services.dart';
-
- import 'package:path_provider/path_provider.dart';
-
- import 'package:rive/rive.dart';
-
- ///author: wangzhong
-
- ///create: 2022-11-23 23:19
-
- ///Description: Rive动画的基本本使用,三种加载方式asset加载、network网络url加载、file文件加载
-
- class SimpleAnimationExample extends StatefulWidget {
-
- @override
-
- State<StatefulWidget> createState() {
-
- return _SimepleAnimationExampleState();
-
- }
-
- }
-
- class _SimepleAnimationExampleState extends State<SimpleAnimationExample> {
-
- String pathRive = '';
-
- @override
-
- void initState() {
-
- super.initState();
-
- getFile().then((value) {
-
- setState(() {
-
- pathRive = value;
-
- });
-
- });
-
- }
-
- Future<String> getFile() async {
-
- ByteData bytes = await rootBundle.load("asset/rive/ferris-wheel.riv");
-
- String fileName = "ferris-wheel.riv";
-
- String dir = (await getApplicationSupportDirectory()).path;
-
- String filePath = "$dir/$fileName";
-
- ByteBuffer buffer = bytes.buffer;
-
- File file = await File(filePath).writeAsBytes(buffer.asUint8List());
-
- return file.path;
-
- }
-
- @override
-
- Widget build(BuildContext context) {
-
- return Scaffold(
-
- appBar: AppBar(
-
- title: Text('SimpleAnimationExample'),
-
- ),
-
- body: Column(
-
- children: [
-
- Expanded(
-
- child: RiveAnimation.asset(
-
- 'asset/rive/halloween-ghost.riv',
-
- fit: BoxFit.cover,
-
- ),
-
- ),
-
- Expanded(
-
- child: RiveAnimation.network(
-
- 'https://public.rive.app/community/runtime-files/3605-7541-payfit-summit-2022.riv'),
-
- ),
-
- Expanded(
-
- child: Center(
-
- child: pathRive.isEmpty
-
- ? Icon(Icons.confirmation_num_outlined)
-
- : RiveAnimation.file(
-
- pathRive,
-
- fit: BoxFit.cover,
-
- ),
-
- ),
-
- )
-
- ],
-
- ),
-
- );
-
- }
-
- }
-
-
- import 'package:flutter/material.dart';
-
- import 'package:rive/rive.dart';
-
-
-
- ///author: wangzhong
-
- ///create: 2022-11-24 08:50
-
- ///Description: 动画播放暂停控制
-
- class PlayPauseAnimationExample extends StatefulWidget {
-
- PlayPauseAnimationExample({Key? key}) : super(key: key);
-
-
-
- @override
-
- _PlayPauseAnimationExampleState createState() =>
-
- _PlayPauseAnimationExampleState();
-
- }
-
-
-
- class _PlayPauseAnimationExampleState extends State<PlayPauseAnimationExample> {
-
- late RiveAnimationController _controller;
-
-
-
- /// Toggles between play and pause animation states
-
- void _togglePlay() =>
-
- setState(() => _controller.isActive = !_controller.isActive);
-
-
-
- /// Tracks if the animation is playing by whethe r controller is running
-
- bool get isPlaying => _controller.isActive;
-
-
-
- @override
-
- void initState() {
-
- // TODO: implement initState
-
- _controller = SimpleAnimation('Timeline 1');
-
- super.initState();
-
- }
-
-
-
- @override
-
- void dispose() {
-
- // TODO: implement dispose
-
- _controller.dispose();
-
- super.dispose();
-
- }
-
-
-
- @override
-
- Widget build(BuildContext context) {
-
- return Scaffold(
-
- appBar: AppBar(
-
- title: Text('PlayPauseAnimationExample'),
-
- ),
-
- body: Center(
-
- child: RiveAnimation.asset(
-
- 'asset/rive/ferris-wheel.riv',
-
- controllers: [_controller],
-
- onInit: (state) => setState(() => print(state)),
-
- )),
-
- floatingActionButton: FloatingActionButton(
-
- onPressed: () => _togglePlay(),
-
- tooltip: isPlaying ? 'Pause' : 'Play',
-
- child: Icon(
-
- isPlaying ? Icons.pause : Icons.play_arrow,
-
- ),
-
- ),
-
- );
-
- }
-
- }
-
- import 'package:flutter/material.dart';
-
- import 'package:rive/rive.dart';
-
- ///author: wangzhong
-
- ///create: 2022-11-24 20:59
-
- ///Description: 动画中执行单次动作
-
- class PlayOneShotExample extends StatefulWidget {
-
- PlayOneShotExample({Key? key}) : super(key: key);
-
- @override
-
- _PlayOneShotExampleState createState() => _PlayOneShotExampleState();
-
- }
-
- class _PlayOneShotExampleState extends State<PlayOneShotExample> {
-
- late RiveAnimationController _controller;
-
- /// Is the animation currently playing?
-
- bool _isPlaying = false;
-
- @override
-
- void initState() {
-
- super.initState();
-
- _controller = OneShotAnimation(
-
- 'bounce',
-
- autoplay: false,
-
- onStop: () => setState(() => _isPlaying = false),
-
- onStart: () => setState(() => _isPlaying = true),
-
- );
-
- }
-
- @override
-
- Widget build(BuildContext context) {
-
- return Scaffold(
-
- appBar: AppBar(
-
- title: Text('PlayOneShotExample'),
-
- // titleTextStyle: TextStyle(fontSize: 20,color: Colors.black),
-
- ),
-
- body: Center(
-
- child: RiveAnimation.network(
-
- 'https://cdn.rive.app/animations/vehicles.riv',
-
- animations: const ['idle', 'curves'],
-
- controllers: [_controller],
-
- ),
-
- ),
-
- floatingActionButton: FloatingActionButton(
-
- // disable the button while playing the animation
-
- onPressed: () => _isPlaying ? null : _controller.isActive = true,
-
- tooltip: 'Bounce',
-
- child: const Icon(Icons.arrow_upward),
-
- ),
-
- );
-
- }
-
- }
-
-
- import 'package:flutter/material.dart';
-
- import 'package:rive/rive.dart';
-
- import 'package:yhm_app/utils/rive_speed_controller.dart';
-
-
-
- ///author: wangzhong
-
- ///create: 2022-11-25 11:40
-
- ///Description: 动画速度控制
-
- class SpeedControllExample extends StatefulWidget {
-
- SpeedControllExample({Key? key}) : super(key: key);
-
-
-
- @override
-
- _SpeedControllExampleState createState() => _SpeedControllExampleState();
-
- }
-
-
-
- class _SpeedControllExampleState extends State<SpeedControllExample> {
-
- late RiveSpeedController speedController;
-
-
-
- @override
-
- void initState() {
-
- // TODO: implement initState
-
- speedController = RiveSpeedController('Timeline 1', speedMultiplier: 1);
-
- super.initState();
-
- }
-
-
-
- @override
-
- Widget build(BuildContext context) {
-
- return Scaffold(
-
- appBar: AppBar(
-
- title: Text('SpeedControllExample'),
-
- // titleTextStyle: TextStyle(fontSize: 20,color: Colors.black),
-
- ),
-
- body: Container(
-
- child: Column(
-
- children: [
-
- Expanded(
-
- child: RiveAnimation.asset(
-
- 'asset/rive/ferris-wheel.riv',
-
- fit: BoxFit.cover,
-
- // animations: const ['Timeline 1'],
-
- controllers: [speedController],
-
- )),
-
- ],
-
- ),
-
- ),
-
- floatingActionButton: FloatingActionButton(
-
- onPressed: () {
-
- setState(() {
-
- if (speedController.speedMultiplier > 9) {
-
- speedController.speedMultiplier = 0;
-
- }
-
- speedController.speedMultiplier++;
-
- });
-
- },
-
- child: Text('x${speedController.speedMultiplier}'),
-
- ),
-
- );
-
- }
-
- }
-
-
-
- // class RiveSpeedController extends SimpleAnimation {
-
- // final double speedMultiplier;
-
- //
-
- // RiveSpeedController(
-
- // String animationName, {
-
- // double mix = 1,
-
- // this.speedMultiplier = 1,
-
- // }) : super(animationName, mix: mix);
-
- //
-
- // @override
-
- // void apply(RuntimeArtboard artboard, double elapsedSeconds) {
-
- // if (instance == null || !instance!.keepGoing) {
-
- // isActive = false;
-
- // }
-
- // instance!
-
- // ..animation.apply(instance!.time, coreContext: artboard, mix: mix)
-
- // ..advance(elapsedSeconds * speedMultiplier);
-
- // }
-
- // }
- import 'dart:math';
-
-
-
- import 'package:flutter/material.dart';
-
- import 'package:flutter/services.dart';
-
- import 'package:rive/rive.dart';
-
-
-
- ///author: wangzhong
-
- ///create: 2022-11-26 17:40
-
- ///Description: xxxx
-
- class DownloadProgressExample extends StatefulWidget {
-
- DownloadProgressExample({Key? key}) : super(key: key);
-
-
-
- @override
-
- _DownloadProgressExampleState createState() =>
-
- _DownloadProgressExampleState();
-
- }
-
-
-
- class _DownloadProgressExampleState extends State<DownloadProgressExample> {
-
- // SMIInput<bool> start;
-
- // SMIInput<double> progeress;
-
-
-
- Artboard? _riveArtboard;
-
-
-
- // SMIInput<bool>? _start;
-
- SMITrigger? _start;
-
- SMIInput<double>? _progress;
-
-
-
- @override
-
- void initState() {
-
- rootBundle.load('asset/rive/liquid_download.riv').then(
-
- (data) async {
-
- // Load the RiveFile from the binary data.
-
- final file = RiveFile.import(data);
-
-
-
- // The artboard is the root of the animation and gets drawn in the
-
- // Rive widget.
-
- final artboard = file.mainArtboard;
-
- var controller =
-
- StateMachineController.fromArtboard(artboard, 'Download');
-
- if (controller != null) {
-
- artboard.addController(controller);
-
- _start = controller.findSMI('Download');
-
- _progress = controller.findInput('Progress');
-
- print(_start);
-
- print(_progress);
-
- }
-
- setState(() => _riveArtboard = artboard);
-
- },
-
- );
-
- super.initState();
-
- }
-
-
-
- @override
-
- Widget build(BuildContext context) {
-
- final ThemeData theme = Theme.of(context);
-
-
-
- return Scaffold(
-
- appBar: AppBar(
-
- title: Text('DownloadProgressExample'),
-
- // titleTextStyle: TextStyle(fontSize: 20,color: Colors.black),
-
- ),
-
- body: Container(
-
- child: Column(
-
- children: [
-
- Expanded(
-
- child: _riveArtboard == null
-
- ? SizedBox()
-
- : GestureDetector(
-
- onTap: () {
-
- _start?.fire();
-
- // _start?.value = true;
-
- },
-
- child: Rive(artboard: _riveArtboard!))),
-
- _riveArtboard == null
-
- ? SizedBox()
-
- : SliderTheme(
-
- data: theme.sliderTheme.copyWith(
-
- activeTrackColor: Colors.deepPurple,
-
- inactiveTrackColor: Colors.blue.withAlpha(55),
-
- activeTickMarkColor:
-
- theme.colorScheme.onSurface.withOpacity(0.7),
-
- inactiveTickMarkColor:
-
- theme.colorScheme.surface.withOpacity(0.7),
-
- overlayColor:
-
- theme.colorScheme.onSurface.withOpacity(0.12),
-
- thumbColor: Colors.deepPurple,
-
- valueIndicatorColor: Colors.deepPurpleAccent,
-
- thumbShape: _CustomThumbShape(),
-
- valueIndicatorShape: _CustomValueIndicatorShape(),
-
- valueIndicatorTextStyle: theme.accentTextTheme.bodyText2!
-
- .copyWith(color: theme.colorScheme.onSurface),
-
- ),
-
- child: Slider(
-
- value: _progress!.value,
-
- min: 0,
-
- max: 100,
-
- divisions: 10,//加上这个属性才会显示label
-
- activeColor: Colors.orangeAccent,
-
- inactiveColor: Colors.green.withAlpha(99),
-
- thumbColor: Colors.deepPurpleAccent,
-
- label: _progress!.value.toStringAsFixed(2),
-
- onChanged: (value) {
-
- setState(() {
-
- _progress?.value = value;
-
- });
-
- })),
-
- SizedBox(
-
- height: 30,
-
- )
-
- ],
-
- ),
-
- ),
-
- );
-
- }
-
- }
-
-
-
- class _CustomThumbShape extends SliderComponentShape {
-
- static const double _thumbSize = 4.0;
-
- static const double _disabledThumbSize = 3.0;
-
-
-
- @override
-
- Size getPreferredSize(bool isEnabled, bool isDiscrete) {
-
- return isEnabled
-
- ? const Size.fromRadius(_thumbSize)
-
- : const Size.fromRadius(_disabledThumbSize);
-
- }
-
-
-
- static final Animatable<double> sizeTween = Tween<double>(
-
- begin: _disabledThumbSize,
-
- end: _thumbSize,
-
- );
-
-
-
- @override
-
- void paint(PaintingContext context, Offset center,
-
- {required Animation<double> activationAnimation,
-
- required Animation<double> enableAnimation,
-
- required bool isDiscrete,
-
- required TextPainter labelPainter,
-
- required RenderBox parentBox,
-
- required SliderThemeData sliderTheme,
-
- required TextDirection textDirection,
-
- required double value,
-
- required double textScaleFactor,
-
- required Size sizeWithOverflow}) {
-
- final Canvas canvas = context.canvas;
-
- final ColorTween colorTween = ColorTween(
-
- begin: sliderTheme.disabledThumbColor,
-
- end: sliderTheme.thumbColor,
-
- );
-
- final double size = _thumbSize * sizeTween.evaluate(enableAnimation);
-
- final Path thumbPath = _downTriangle(size, center);
-
- canvas.drawPath(thumbPath,
-
- Paint()..color = colorTween.evaluate(enableAnimation) ?? Colors.blue);
-
- }
-
- }
-
-
-
- Path _upTriangle(double size, Offset thumbCenter) =>
-
- _downTriangle(size, thumbCenter, invert: true);
-
-
-
- Path _downTriangle(double size, Offset thumbCenter, {bool invert = false}) {
-
- final Path thumbPath = Path();
-
- final double height = sqrt(3.0) / 2.0;
-
- final double centerHeight = size * height / 3.0;
-
- final double halfSize = size / 2.0;
-
- final double sign = invert ? -1.0 : 1.0;
-
- thumbPath.moveTo(
-
- thumbCenter.dx - halfSize, thumbCenter.dy + sign * centerHeight);
-
- thumbPath.lineTo(thumbCenter.dx, thumbCenter.dy - 2.0 * sign * centerHeight);
-
- thumbPath.lineTo(
-
- thumbCenter.dx + halfSize, thumbCenter.dy + sign * centerHeight);
-
- thumbPath.close();
-
- return thumbPath;
-
- }
-
-
-
- class _CustomValueIndicatorShape extends SliderComponentShape {
-
- static const double _indicatorSize = 4.0;
-
- static const double _disabledIndicatorSize = 3.0;
-
- static const double _slideUpHeight = 30.0;
-
-
-
- @override
-
- Size getPreferredSize(bool isEnabled, bool isDiscrete) {
-
- return Size.fromRadius(isEnabled ? _indicatorSize : _disabledIndicatorSize);
-
- }
-
-
-
- static final Animatable<double> sizeTween = Tween<double>(
-
- begin: _disabledIndicatorSize,
-
- end: _indicatorSize,
-
- );
-
-
-
- @override
-
- void paint(PaintingContext context, Offset center,
-
- {required Animation<double> activationAnimation,
-
- required Animation<double> enableAnimation,
-
- required bool isDiscrete,
-
- required TextPainter labelPainter,
-
- required RenderBox parentBox,
-
- required SliderThemeData sliderTheme,
-
- required TextDirection textDirection,
-
- required double value,
-
- required double textScaleFactor,
-
- required Size sizeWithOverflow}) {
-
- final Canvas canvas = context.canvas;
-
- final ColorTween enableColor = ColorTween(
-
- begin: sliderTheme.disabledThumbColor,
-
- end: sliderTheme.valueIndicatorColor,
-
- );
-
- final Tween<double> slideUpTween = Tween<double>(
-
- begin: 0.0,
-
- end: _slideUpHeight,
-
- );
-
- final double size = _indicatorSize * sizeTween.evaluate(enableAnimation);
-
- final Offset slideUpOffset =
-
- Offset(0.0, -slideUpTween.evaluate(activationAnimation));
-
- final Path thumbPath = _upTriangle(size, center + slideUpOffset);
-
- final Color paintColor = enableColor
-
- .evaluate(enableAnimation)
-
- ?.withAlpha((255.0 * activationAnimation.value).round()) ??
-
- Colors.black;
-
- canvas.drawPath(
-
- thumbPath,
-
- Paint()..color = paintColor,
-
- );
-
- canvas.drawLine(
-
- center,
-
- center + slideUpOffset,
-
- Paint()
-
- ..color = paintColor
-
- ..style = PaintingStyle.stroke
-
- ..strokeWidth = 2.0);
-
- labelPainter.paint(
-
- canvas,
-
- center +
-
- slideUpOffset +
-
- Offset(-labelPainter.width / 2.0, -labelPainter.height - 4.0));
-
- }
-
- }
- import 'package:flutter/material.dart';
-
- import 'package:flutter/services.dart';
-
- import 'package:rive/rive.dart';
-
-
-
- ///author: wangzhong
-
- ///create: 2022-11-26 17:51
-
- ///Description: xxxx
-
- class MoreTypeStateChangeExample extends StatefulWidget {
-
- MoreTypeStateChangeExample({Key? key}) : super(key: key);
-
-
-
- @override
-
- _MoreTypeStateChangeExampleState createState() =>
-
- _MoreTypeStateChangeExampleState();
-
- }
-
-
-
- class _MoreTypeStateChangeExampleState
-
- extends State<MoreTypeStateChangeExample> {
-
- Artboard? _riveWomenArtboard;
-
- SMIInput<double>? _levelInput;
-
-
-
- Artboard? _riveMenArtboard;
-
- SMITrigger? _crossInput;
-
- SMITrigger? _jabInput;
-
- SMITrigger? _kickInput;
-
-
-
- SMIInput<bool>? _runInput;
-
- SMIInput<double>? _turnInput;
-
-
-
- @override
-
- void initState() {
-
- rootBundle.load('asset/rive/skills.riv').then(
-
- (data) async {
-
- // Load the RiveFile from the binary data.
-
- final file = RiveFile.import(data);
-
-
-
- // The artboard is the root of the animation and gets drawn in the
-
- // Rive widget.
-
- final artboard = file.mainArtboard;
-
- var controller =
-
- StateMachineController.fromArtboard(artboard, 'Designer\'s Test');
-
- if (controller != null) {
-
- artboard.addController(controller);
-
- _levelInput = controller.findInput('Level');
-
- }
-
- setState(() => _riveWomenArtboard = artboard);
-
- },
-
- );
-
-
-
- rootBundle.load('asset/rive/character-controller.riv').then(
-
- (data) async {
-
- // Load the RiveFile from the binary data.
-
- final file = RiveFile.import(data);
-
- // The artboard is the root of the animation and gets drawn in the
-
- // Rive widget.
-
- final artboard = file.mainArtboard;
-
- var controller =
-
- StateMachineController.fromArtboard(artboard, 'State Machine 1');
-
- if (controller != null) {
-
- artboard.addController(controller);
-
- _crossInput = controller.findSMI('crossPunch');
-
- _jabInput = controller.findSMI('jabPunch');
-
- _kickInput = controller.findSMI('sideKick');
-
- _runInput = controller.findInput('isRunning');
-
- _turnInput = controller.findInput('xDir');
-
- }
-
- setState(() => _riveMenArtboard = artboard);
-
- },
-
- );
-
-
-
- super.initState();
-
- }
-
-
-
- @override
-
- Widget build(BuildContext context) {
-
- return Scaffold(
-
- appBar: AppBar(
-
- title: Text('MoreTypeStateChangeExample'),
-
- // titleTextStyle: TextStyle(fontSize: 20,color: Colors.black),
-
- ),
-
- body: Container(
-
- child: Column(
-
- children: [
-
- Expanded(
-
- child: _riveWomenArtboard == null
-
- ? SizedBox()
-
- : Rive(
-
- artboard: _riveWomenArtboard!,
-
- )),
-
- Padding(
-
- padding: const EdgeInsets.all(20),
-
- child: Row(
-
- children: [
-
- Expanded(
-
- child: ElevatedButton(
-
- onPressed: () {
-
- _levelInput?.change(0);
-
- },
-
- child: Text('baby')),
-
- ),
-
- Padding(
-
- padding: const EdgeInsets.symmetric(
-
- horizontal: 10, vertical: 20),
-
- child: ElevatedButton(
-
- onPressed: () {
-
- _levelInput?.change(1);
-
- },
-
- child: Text('younger')),
-
- ),
-
- Expanded(
-
- child: ElevatedButton(
-
- onPressed: () {
-
- _levelInput?.change(2);
-
- },
-
- child: Text('old people')),
-
- ),
-
- ],
-
- ),
-
- ),
-
- Expanded(
-
- child: _riveMenArtboard == null
-
- ? SizedBox()
-
- : Rive(
-
- artboard: _riveMenArtboard!,
-
- ),
-
- ),
-
- Row(
-
- children: [
-
- Expanded(
-
- child: ElevatedButton(
-
- onPressed: () {
-
- _crossInput?.fire();
-
- },
-
- child: Text('cross')),
-
- ),
-
- Expanded(
-
- child: Padding(
-
- padding: const EdgeInsets.symmetric(horizontal: 10),
-
- child: ElevatedButton(
-
- onPressed: () {
-
- _jabInput?.fire();
-
- },
-
- child: Text('jab')),
-
- ),
-
- ),
-
- Expanded(
-
- child: ElevatedButton(
-
- onPressed: () {
-
- _kickInput?.fire();
-
- },
-
- child: Text('kick')),
-
- ),
-
- Expanded(
-
- child: Padding(
-
- padding: const EdgeInsets.symmetric(horizontal: 10),
-
- child: ElevatedButton(
-
- onPressed: () {
-
- bool? flag = _runInput?.value;
-
- _runInput?.value = !flag!;
-
- },
-
- child: Text('run')),
-
- ),
-
- ),
-
- ],
-
- ),
-
- Padding(
-
- padding: const EdgeInsets.only(bottom: 20),
-
- child: Row(
-
- children: [
-
- Expanded(
-
- child: ElevatedButton(
-
- onPressed: () {
-
- print(_turnInput);
-
- _turnInput?.change(-1);
-
- },
-
- child: Text('turn left')),
-
- ),
-
- Expanded(
-
- child: Padding(
-
- padding: const EdgeInsets.symmetric(horizontal: 10),
-
- child: ElevatedButton(
-
- onPressed: () {
-
- _turnInput?.value = 1;
-
- },
-
- child: Text('turn right')),
-
- ),
-
- ),
-
- ],
-
- ),
-
- ),
-
- ],
-
- ),
-
- ),
-
- );
-
- }
-
- }
如上图所示,状态切换,点击方块时,圆圈会做出一个亮暗的变化,模仿了一个开关灯的操作。
在rive平台编辑器上看到的在这组动画中有Inputs中有开关,Listener中有监听
- Expanded(
-
- child: GestureDetector(
-
- // onTap: _hitSwitch,
-
- child: RiveAnimation.asset(
-
- 'asset/rive/light_switch.riv',
-
- stateMachines: ['Switch'],
-
- ),
-
- ),
-
- ),
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。