|
@@ -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();
|
|
|
|
+ }
|
|
}
|
|
}
|