Parcourir la source

[New]帧动画控件新增控制器/倍数播放

zhipeng il y a 1 an
Parent
commit
b224cec30b
2 fichiers modifiés avec 74 ajouts et 38 suppressions
  1. 70 34
      lib/widget/frame_animation_view.dart
  2. 4 4
      pubspec.lock

+ 70 - 34
lib/widget/frame_animation_view.dart

@@ -14,6 +14,10 @@ class FrameAnimationView extends StatefulWidget {
 
   final int frameRate;
 
+  final FrameAnimationController? controller;
+
+  final double? speed;
+
   final double? width;
 
   final double? height;
@@ -22,16 +26,18 @@ class FrameAnimationView extends StatefulWidget {
       {super.key,
       required this.framePath,
       this.frameRate = 25,
+      this.controller,
+      this.speed,
       this.width,
       this.height});
 
   @override
   State<StatefulWidget> createState() {
-    return _FrameAnimationViewState();
+    return FrameAnimationViewState();
   }
 }
 
-class _FrameAnimationViewState extends State<FrameAnimationView> {
+class FrameAnimationViewState extends State<FrameAnimationView> {
   int _currentFrame = 0;
   Timer? _timer;
   List<File> imageFiles = [];
@@ -40,10 +46,13 @@ class _FrameAnimationViewState extends State<FrameAnimationView> {
   @override
   void initState() {
     super.initState();
+    widget.controller?.bindState(this);
     loadFrameFromAssets()
         .then((_) => initializeImageFiles())
         .then((_) => precacheImageFiles())
-        .then((_) => startAnimation())
+        .then((_) => widget.controller == null || widget.controller!.autoPlay
+            ? startAnimation()
+            : null)
         .catchError((error) => debugPrint('FrameAnimationView error: $error'));
   }
 
@@ -55,8 +64,8 @@ class _FrameAnimationViewState extends State<FrameAnimationView> {
 
   @override
   Widget build(BuildContext context) {
-    if (images.isEmpty || widget.width == null || widget.height == null) {
-      return Container();
+    if (images.isEmpty) {
+      return SizedBox(width: widget.width, height: widget.height);
     }
     return RawImage(
       image: images[_currentFrame],
@@ -108,31 +117,6 @@ class _FrameAnimationViewState extends State<FrameAnimationView> {
     }
   }
 
-  Future<Directory> createCacheDirectory() async {
-    // Get the temporary directory
-    final Directory tempDir = await getTemporaryDirectory();
-
-    // Create a new directory within the temporary directory
-    final Directory cacheDir =
-        Directory('${tempDir.path}/frame_anim_cache');
-
-    // Check if the directory exists, if not, create it
-    if (!await cacheDir.exists()) {
-      await cacheDir.create(recursive: true);
-    }
-
-    // create unique directory by framePath's md5
-    final Directory frameDir = Directory(
-        '${cacheDir.path}/${md5.convert(utf8.encode(widget.framePath)).toString()}');
-
-    // Check if the directory exists, if not, create it
-    if (!await frameDir.exists()) {
-      await frameDir.create(recursive: true);
-    }
-
-    return frameDir;
-  }
-
   Future<void> copyToCache() async {
     // Read AssetManifest.json file
     final String manifestContent =
@@ -170,13 +154,43 @@ class _FrameAnimationViewState extends State<FrameAnimationView> {
     }
   }
 
-  Future<void> startAnimation() async {
+  Future<Directory> createCacheDirectory() async {
+    // Get the temporary directory
+    final Directory tempDir = await getTemporaryDirectory();
+
+    // Create a new directory within the temporary directory
+    final Directory cacheDir = Directory('${tempDir.path}/frame_anim_cache');
+
+    // Check if the directory exists, if not, create it
+    if (!await cacheDir.exists()) {
+      await cacheDir.create(recursive: true);
+    }
+
+    // create unique directory by framePath's md5
+    final Directory frameDir = Directory(
+        '${cacheDir.path}/${md5.convert(utf8.encode(widget.framePath)).toString()}');
+
+    // Check if the directory exists, if not, create it
+    if (!await frameDir.exists()) {
+      await frameDir.create(recursive: true);
+    }
+
+    return frameDir;
+  }
+
+  startAnimation() {
     if (imageFiles.isEmpty) {
       return;
     }
 
-    _timer =
-        Timer.periodic(Duration(milliseconds: 1000 ~/ widget.frameRate), (_) {
+    if (_timer != null && _timer!.isActive) {
+      return;
+    }
+
+    double speed = widget.speed ?? 1.0;
+
+    _timer = Timer.periodic(
+        Duration(milliseconds: 1000 ~/ (widget.frameRate * speed)), (_) {
       setState(() {
         int targetFrame = (_currentFrame + 1) % imageFiles.length;
         _currentFrame =
@@ -185,7 +199,7 @@ class _FrameAnimationViewState extends State<FrameAnimationView> {
     });
   }
 
-  Future<void> initializeImageFiles() async {
+  initializeImageFiles() async {
     final Directory cacheDir = await createCacheDirectory();
 
     imageFiles = cacheDir
@@ -214,3 +228,25 @@ class _FrameAnimationViewState extends State<FrameAnimationView> {
     });
   }
 }
+
+class FrameAnimationController {
+  final bool autoPlay;
+
+  FrameAnimationViewState? _state;
+
+  FrameAnimationController({this.autoPlay = true});
+
+  void play() {
+    _state?.startAnimation();
+  }
+
+  void stop() {
+    _state?._timer?.cancel();
+  }
+
+  bool get isPlaying => _state?._timer?.isActive ?? false;
+
+  void bindState(FrameAnimationViewState state) {
+    _state = state;
+  }
+}

+ 4 - 4
pubspec.lock

@@ -213,10 +213,10 @@ packages:
     dependency: "direct main"
     description:
       name: dio
-      sha256: "0dfb6b6a1979dac1c1245e17cef824d7b452ea29bd33d3467269f9bef3715fb0"
+      sha256: "5598aa796bbf4699afd5c67c0f5f6e2ed542afc956884b9cd58c306966efc260"
       url: "https://pub.dev"
     source: hosted
-    version: "5.6.0"
+    version: "5.7.0"
   dio_web_adapter:
     dependency: transitive
     description:
@@ -695,10 +695,10 @@ packages:
     dependency: "direct main"
     description:
       name: retrofit
-      sha256: "1fceca35cc68d5f14ff70ae830acbf157263b42e1cdfd5b38045ca517535b734"
+      sha256: "479cc534c2d83296dac6ae16933dd77e7a52bb54cf7e75e6eb83ee51928c8465"
       url: "https://pub.dev"
     source: hosted
-    version: "4.2.0"
+    version: "4.3.0"
   retrofit_generator:
     dependency: "direct dev"
     description: