dress_up.dart 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. ///
  2. /// Spine Runtimes License Agreement
  3. /// Last updated July 28, 2023. Replaces all prior versions.
  4. ///
  5. /// Copyright (c) 2013-2023, Esoteric Software LLC
  6. ///
  7. /// Integration of the Spine Runtimes into software or otherwise creating
  8. /// derivative works of the Spine Runtimes is permitted under the terms and
  9. /// conditions of Section 2 of the Spine Editor License Agreement:
  10. /// http://esotericsoftware.com/spine-editor-license
  11. ///
  12. /// Otherwise, it is permitted to integrate the Spine Runtimes into software or
  13. /// otherwise create derivative works of the Spine Runtimes (collectively,
  14. /// "Products"), provided that each user of the Products must obtain their own
  15. /// Spine Editor license and redistribution of the Products in any form must
  16. /// include this license and copyright notice.
  17. ///
  18. /// THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
  19. /// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. /// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. /// DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
  22. /// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. /// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
  24. /// BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
  25. /// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. /// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
  27. /// SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. ///
  29. import 'package:spine_flutter/raw_image_provider.dart';
  30. import 'package:spine_flutter/spine_flutter.dart';
  31. import 'package:flutter/material.dart';
  32. import 'package:flutter/painting.dart' as painting;
  33. class DressUp extends StatefulWidget {
  34. const DressUp({Key? key}) : super(key: key);
  35. @override
  36. DressUpState createState() => DressUpState();
  37. }
  38. class DressUpState extends State<DressUp> {
  39. static const double thumbnailSize = 200;
  40. late SkeletonDrawable _drawable;
  41. Skin? _customSkin;
  42. final Map<String, RawImageData> _skinImages = {};
  43. final Map<String, bool> _selectedSkins = {};
  44. @override
  45. void initState() {
  46. reportLeaks();
  47. super.initState();
  48. SkeletonDrawable.fromAsset("assets/mix-and-match.atlas", "assets/mix-and-match-pro.skel").then((drawable) async {
  49. _drawable = drawable;
  50. for (var skin in drawable.skeletonData.getSkins()) {
  51. if (skin.getName() == "default") continue;
  52. var skeleton = drawable.skeleton;
  53. skeleton.setSkin(skin);
  54. skeleton.setToSetupPose();
  55. skeleton.updateWorldTransform();
  56. _skinImages[skin.getName()] = await drawable.renderToRawImageData(thumbnailSize, thumbnailSize, 0xffffffff);
  57. _selectedSkins[skin.getName()] = false;
  58. }
  59. _toggleSkin("full-skins/girl");
  60. setState(() {});
  61. });
  62. }
  63. void _toggleSkin(String skinName) {
  64. _selectedSkins[skinName] = !_selectedSkins[skinName]!;
  65. if (_customSkin != null) _customSkin?.dispose();
  66. _customSkin = Skin("custom-skin");
  67. for (var skinName in _selectedSkins.keys) {
  68. if (_selectedSkins[skinName] == true) {
  69. var skin = _drawable.skeletonData.findSkin(skinName);
  70. if (skin != null) _customSkin?.addSkin(skin);
  71. }
  72. }
  73. _drawable.skeleton.setSkin(_customSkin!);
  74. _drawable.skeleton.setToSetupPose();
  75. }
  76. @override
  77. Widget build(BuildContext context) {
  78. final controller = SpineWidgetController(onInitialized: (controller) {
  79. controller.animationState.setAnimationByName(0, "dance", true);
  80. });
  81. return Scaffold(
  82. appBar: AppBar(title: const Text('Dress Up')),
  83. body: _skinImages.isEmpty
  84. ? const SizedBox()
  85. : Row(children: [
  86. SizedBox(
  87. width: thumbnailSize,
  88. child: ListView(
  89. children: _skinImages.keys.map((skinName) {
  90. var rawImageData = _skinImages[skinName]!;
  91. var image = Image(image: RawImageProvider(rawImageData));
  92. var box = SizedBox(width: 200, height: 200, child: image);
  93. return GestureDetector(
  94. onTap: () {
  95. _toggleSkin(skinName);
  96. setState(() {});
  97. },
  98. child: _selectedSkins[skinName] == true
  99. ? box
  100. // Does not work on web.
  101. //: ColorFiltered(colorFilter: const ColorFilter.mode(Colors.grey, painting.BlendMode.saturation,), child: box)
  102. : Container(
  103. foregroundDecoration: const BoxDecoration(
  104. color: Colors.grey,
  105. backgroundBlendMode: painting.BlendMode.saturation,
  106. ),
  107. child: box));
  108. }).toList()),
  109. ),
  110. Expanded(
  111. child: SpineWidget.fromDrawable(
  112. _drawable,
  113. controller,
  114. boundsProvider: SkinAndAnimationBounds(skins: ["full-skins/girl"]),
  115. ))
  116. ]));
  117. }
  118. @override
  119. void dispose() {
  120. super.dispose();
  121. _drawable.dispose();
  122. _customSkin?.dispose();
  123. }
  124. }