感覺官方的案例對我這種level的開發(fā)者來說感覺的真的很晦澀,也沒什么像樣的中文文檔,所以做了些嘗試,大致理解了一些基本的使用方式。有些較為復雜的素材琢磨不明白,然后把自己所知的做一個總結(jié)吧。
??稻W(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)建站!從網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、響應式網(wǎng)站建設(shè)等網(wǎng)站項目制作,到程序開發(fā),運營維護。創(chuàng)新互聯(lián)建站于2013年成立到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗和運維經(jīng)驗,來保證我們的工作的順利進行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)建站。首先是通過RiveAnimation組件加載的三種方式,分別可以通過asset資源文件、網(wǎng)絡(luò)url和本地文件進行動畫加載。
以及通過RiveAnimationController控制動畫的暫停與播放。
還有一種加載方法是通過直接加載文件并解析轉(zhuǎn)化成RivaFile類型,獲取一個所謂artboard的畫板,然后通過這個畫板獲取一個StateMachineController的狀態(tài)器,接下來在狀態(tài)其中通過findSMI和findInput方法獲取到可執(zhí)行的動畫。動畫的名稱通過rive網(wǎng)站的editor打開自己查看,這里接似懂非懂了,見得的動畫基本按照編輯器里的名稱來就可以,有些復雜類型的小游戲?qū)嵲谑菦]明白怎么加載,按常規(guī)動畫那套搞我沒搞出來。有明白的可以指教下。主要還是findSMI可以找到SMITrigger這種類型的動畫控制器,過過調(diào)用其實例的fire方法執(zhí)行動畫,還有findInput方法獲得的SMIInput實例,通過傳入泛型,double、bool等控制數(shù)值發(fā)生變化來觸動動畫的執(zhí)行。具體的可以看下下面的一些案例,效果和代碼都貼出來了,僅供參考,互相學習。
Flitter rive加載組件 rive: ^0.9.1
rive | Flutter Package
Rive素材
Rive - Community
首先是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網(wǎng)絡(luò)url加載、file文件加載
class SimpleAnimationExample extends StatefulWidget {
? @override
? StatecreateState() {
??? return _SimepleAnimationExampleState();
? }
}
class _SimepleAnimationExampleState extends State{
? String pathRive = '';
? @override
? void initState() {
??? super.initState();
??? getFile().then((value) {
????? setState(() {
??????? pathRive = value;
????? });
??? });
? }
? FuturegetFile() 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{
? 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,
??????? ),
????? ),
??? );
? }
}
動畫中執(zhí)行單次操作?
import 'package:flutter/material.dart';
import 'package:rive/rive.dart';
///author:????????? wangzhong
///create:????????? 2022-11-24 20:59
///Description:???? 動畫中執(zhí)行單次動作
class PlayOneShotExample extends StatefulWidget {
? PlayOneShotExample({Key? key}) : super(key: key);
? @override
? _PlayOneShotExampleState createState() =>_PlayOneShotExampleState();
}
class _PlayOneShotExampleState extends State{
? 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{
? 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{
? // SMIInputstart;
? // SMIInputprogeress;
? Artboard? _riveArtboard;
? // SMIInput? _start;
? SMITrigger? _start;
? SMIInput? _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 AnimatablesizeTween = Tween(
??? begin: _disabledThumbSize,
??? end: _thumbSize,
? );
? @override
? void paint(PaintingContext context, Offset center,
????? {required AnimationactivationAnimation,
????? required AnimationenableAnimation,
????? 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 AnimatablesizeTween = Tween(
??? begin: _disabledIndicatorSize,
??? end: _indicatorSize,
? );
? @override
? void paint(PaintingContext context, Offset center,
????? {required AnimationactivationAnimation,
????? required AnimationenableAnimation,
????? 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 TweenslideUpTween = Tween(
????? 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));
? }
}
狀態(tài)器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{
? Artboard? _riveWomenArtboard;
? SMIInput? _levelInput;
? Artboard? _riveMenArtboard;
? SMITrigger? _crossInput;
? SMITrigger? _jabInput;
? SMITrigger? _kickInput;
? SMIInput? _runInput;
? SMIInput? _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')),
??????????????????? ),
????????????????? ),
??????????????? ],
????????????? ),
??????????? ),
????????? ],
??????? ),
????? ),
??? );
? }
}
如上圖所示,狀態(tài)切換,點擊方塊時,圓圈會做出一個亮暗的變化,模仿了一個開關(guān)燈的操作。
在rive平臺編輯器上看到的在這組動畫中有Inputs中有開關(guān),Listener中有監(jiān)聽
Expanded(
? child: GestureDetector(
??? // onTap: _hitSwitch,
??? child: RiveAnimation.asset(
????? 'asset/rive/light_switch.riv',
????? stateMachines: ['Switch'],
??? ),
? ),
),
你是否還在尋找穩(wěn)定的海外服務器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調(diào)度確保服務器高可用性,企業(yè)級服務器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧