Selaa lähdekoodia

[flutter] Fixed dress-up example.

Mario Zechner 2 vuotta sitten
vanhempi
commit
410f30d485

+ 64 - 16
spine-flutter/example/lib/dress_up.dart

@@ -2,8 +2,9 @@ import 'dart:math';
 import 'dart:ui' as ui;
 import 'dart:ui' as ui;
 
 
 import 'package:flutter/material.dart';
 import 'package:flutter/material.dart';
+import 'package:flutter/painting.dart' as painting;
 import 'package:spine_flutter/spine_flutter.dart';
 import 'package:spine_flutter/spine_flutter.dart';
-import 'package:flutter/rendering.dart' as rendering;
+import 'package:raw_image_provider/raw_image_provider.dart';
 
 
 class DressUp extends StatefulWidget {
 class DressUp extends StatefulWidget {
   const DressUp({Key? key}) : super(key: key);
   const DressUp({Key? key}) : super(key: key);
@@ -14,11 +15,15 @@ class DressUp extends StatefulWidget {
 
 
 class DressUpState extends State<DressUp> {
 class DressUpState extends State<DressUp> {
   static const double thumbnailSize = 200;
   static const double thumbnailSize = 200;
+  late SpineWidgetController _controller;
   SkeletonDrawable? _drawable;
   SkeletonDrawable? _drawable;
-  final List<Image> _skinImages = [];
+  Skin? _customSkin;
+  final Map<String, RawImageData> _skinImages = {};
+  final Map<String, bool> _selectedSkins = {};
 
 
   @override
   @override
   void initState() {
   void initState() {
+    reportLeaks();
     super.initState();
     super.initState();
     SkeletonDrawable.fromAsset("assets/mix-and-match-pro.skel", "assets/mix-and-match.atlas").then((drawable) async {
     SkeletonDrawable.fromAsset("assets/mix-and-match-pro.skel", "assets/mix-and-match.atlas").then((drawable) async {
       for (var skin in drawable.skeletonData.getSkins()) {
       for (var skin in drawable.skeletonData.getSkins()) {
@@ -38,19 +43,42 @@ class DressUpState extends State<DressUp> {
           ..color = ui.Color(bgColor)
           ..color = ui.Color(bgColor)
           ..style = PaintingStyle.fill;
           ..style = PaintingStyle.fill;
         canvas.drawRect(const Rect.fromLTWH(0, 0, thumbnailSize, thumbnailSize), paint);
         canvas.drawRect(const Rect.fromLTWH(0, 0, thumbnailSize, thumbnailSize), paint);
+        canvas.translate(thumbnailSize / 2, thumbnailSize / 2);
         canvas.scale(scale, scale);
         canvas.scale(scale, scale);
-        canvas.translate(-bounds.x + bounds.width / 2, -bounds.y);
+        canvas.translate(-(bounds.x + bounds.width / 2), -(bounds.y + bounds.height / 2));
         canvas.drawRect(Rect.fromLTRB(-5, -5, 5, -5), paint..color = Colors.red);
         canvas.drawRect(Rect.fromLTRB(-5, -5, 5, -5), paint..color = Colors.red);
         drawable.renderToCanvas(canvas);
         drawable.renderToCanvas(canvas);
 
 
-        var imageData = await (await recorder.endRecording().toImage(thumbnailSize.toInt(), thumbnailSize.toInt())).toByteData(format: ui.ImageByteFormat.png);
-        _skinImages.add(Image.memory(imageData!.buffer.asUint8List(), fit: BoxFit.contain));
+        var rawImageData = (await (await recorder.endRecording().toImage(thumbnailSize.toInt(), thumbnailSize.toInt())).toByteData(format: ui.ImageByteFormat.rawRgba))!.buffer.asUint8List();
+        _skinImages[skin.getName()] = (RawImageData(rawImageData, thumbnailSize.toInt(), thumbnailSize.toInt()));
+        _selectedSkins[skin.getName()] = false;
       }
       }
       _drawable = drawable;
       _drawable = drawable;
-      setState(() {});
+      _controller = SpineWidgetController((controller) {
+        controller.animationState.setAnimationByName(0, "dance", true);
+      });
+      setState(() {
+        _selectedSkins["full-skins/girl"] = true;
+        drawable.skeleton.setSkinByName("full-skins/girl");
+        drawable.skeleton.setToSetupPose();
+      });
     });
     });
   }
   }
 
 
+  void _toggleSkin(String skinName) {
+    _selectedSkins[skinName] = !_selectedSkins[skinName]!;
+    if (_customSkin != null) _customSkin?.dispose();
+    _customSkin = Skin("custom-skin");
+    for (var skinName in _selectedSkins.keys) {
+      if (_selectedSkins[skinName] == true) {
+        var skin = _controller.skeletonData.findSkin(skinName);
+        if (skin != null) _customSkin?.addSkin(skin);
+      }
+    }
+    _controller.skeleton.setSkin(_customSkin!);
+    _controller.skeleton.setToSetupPose();
+  }
+
   @override
   @override
   Widget build(BuildContext context) {
   Widget build(BuildContext context) {
     return Scaffold(
     return Scaffold(
@@ -58,16 +86,36 @@ class DressUpState extends State<DressUp> {
         body: _skinImages.isEmpty
         body: _skinImages.isEmpty
             ? const SizedBox()
             ? const SizedBox()
             : Row(
             : Row(
-            children: [
-              Expanded(
-                  child:ListView(
-                      children: _skinImages.map((image) {
-                        return SizedBox(width: 200, height: 200, child: image);
-                      }).toList()
-                  )
-              ),
-            ]
-        )
+                  children: [
+                    Container(width: thumbnailSize, child:
+                      ListView(
+                          children: _skinImages.keys.map((skinName) {
+                            var rawImageData = _skinImages[skinName]!;
+                            var image = Image(image: RawImageProvider(rawImageData));
+                            var box = SizedBox(width: 200, height: 200, child: image);
+                            return GestureDetector(
+                                onTap: () {
+                                  _toggleSkin(skinName);
+                                  setState(() {});
+                                },
+                                child: _selectedSkins[skinName] == true
+                                      ? box
+                                      : ColorFiltered(colorFilter: ColorFilter.mode(Colors.grey, painting.BlendMode.saturation,), child: box)
+                            );
+                          }).toList()
+                      ),
+                    ),
+                    Expanded(
+                      child: SpineWidget.drawable(_drawable, _controller, boundsProvider: SkinAndAnimationBounds(["full-skins/girl"]),)
+                    )
+                  ]
+              )
     );
     );
   }
   }
+
+  @override
+  void dispose() {
+    super.dispose();
+    _drawable?.dispose();
+  }
 }
 }

+ 6 - 0
spine-flutter/example/lib/skins.dart

@@ -76,4 +76,10 @@ class SkinsState extends State<Skins> {
         )
         )
     );
     );
   }
   }
+
+  @override
+  void dispose() {
+    super.dispose();
+    _drawable?.dispose();
+  }
 }
 }

+ 14 - 0
spine-flutter/example/pubspec.lock

@@ -36,6 +36,13 @@ packages:
       url: "https://pub.dartlang.org"
       url: "https://pub.dartlang.org"
     source: hosted
     source: hosted
     version: "1.16.0"
     version: "1.16.0"
+  crypto:
+    dependency: transitive
+    description:
+      name: crypto
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "3.0.2"
   cupertino_icons:
   cupertino_icons:
     dependency: "direct main"
     dependency: "direct main"
     description:
     description:
@@ -130,6 +137,13 @@ packages:
       url: "https://pub.dartlang.org"
       url: "https://pub.dartlang.org"
     source: hosted
     source: hosted
     version: "2.1.2"
     version: "2.1.2"
+  raw_image_provider:
+    dependency: "direct main"
+    description:
+      name: raw_image_provider
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.2.0"
   sky_engine:
   sky_engine:
     dependency: transitive
     dependency: transitive
     description: flutter
     description: flutter

+ 2 - 0
spine-flutter/example/pubspec.yaml

@@ -42,6 +42,8 @@ dependencies:
   # Use with the CupertinoIcons class for iOS style icons.
   # Use with the CupertinoIcons class for iOS style icons.
   cupertino_icons: ^1.0.2
   cupertino_icons: ^1.0.2
 
 
+  raw_image_provider: ^0.2.0
+
 dev_dependencies:
 dev_dependencies:
   flutter_test:
   flutter_test:
     sdk: flutter
     sdk: flutter