Parcourir la source

[flutter] Bounds type and controllable parent sizing.

Mario Zechner il y a 2 ans
Parent
commit
86f68ecf04
2 fichiers modifiés avec 108 ajouts et 37 suppressions
  1. 3 3
      spine-flutter/example/lib/main.dart
  2. 105 34
      spine-flutter/lib/spine_widget.dart

+ 3 - 3
spine-flutter/example/lib/main.dart

@@ -50,13 +50,13 @@ class SimpleAnimation extends StatelessWidget {
     reportLeaks();
     final controller = SpineWidgetController((controller) {
       // Set the walk animation on track 0, let it loop
-      // controller.animationState?.setAnimationByName(0, "walk", true);
+      controller.animationState?.setAnimationByName(0, "animation", true);
     });
 
     return Scaffold(
       appBar: AppBar(title: const Text('Spineboy')),
-      // body: SpineWidget.asset("assets/skeleton.json", "assets/skeleton.atlas", controller, alignment: Alignment.center, fit: BoxFit.none),
-      body: SpineWidget.asset("assets/spineboy-pro.skel", "assets/spineboy.atlas", controller)
+      body: SpineWidget.asset("assets/skeleton.json", "assets/skeleton.atlas", controller, alignment: Alignment.centerLeft, fit: BoxFit.none),
+      // body: SpineWidget.asset("assets/spineboy-pro.skel", "assets/spineboy.atlas", controller, alignment: Alignment.bottomLeft)
       // body: SpineWidget.file("/Users/badlogic/workspaces/spine-runtimes/examples/spineboy/export/spineboy-pro.skel", "/Users/badlogic/workspaces/spine-runtimes/examples/spineboy/export/spineboy.atlas", controller),
       // body: const SpineWidget.http("https://marioslab.io/dump/spineboy/spineboy-pro.json", "https://marioslab.io/dump/spineboy/spineboy.atlas"),
     );

+ 105 - 34
spine-flutter/lib/spine_widget.dart

@@ -42,35 +42,83 @@ class SpineWidgetController {
 
 enum AssetType { Asset, File, Http, Raw }
 
+abstract class BoundsProvider {
+  const BoundsProvider();
+
+  Bounds computeBounds(SkeletonDrawable drawable);
+}
+
+class SetupPoseBounds extends BoundsProvider {
+  const SetupPoseBounds();
+
+  Bounds computeBounds(SkeletonDrawable drawable) {
+    return drawable.skeleton.getBounds();
+  }
+}
+
+class RawBounds extends BoundsProvider {
+  final double x, y, width, height;
+
+  RawBounds(this.x, this.y, this.width, this.height);
+
+  Bounds computeBounds(SkeletonDrawable drawable) {
+    return Bounds(x, y, width, height);
+  }
+}
+
+class ComputedBounds extends BoundsProvider {
+  Bounds computeBounds(SkeletonDrawable drawable) {
+    return Bounds(0, 0, 0, 0);
+  }
+}
+
 class SpineWidget extends StatefulWidget {
+  final AssetType _assetType;
   final String? skeletonFile;
   final String? atlasFile;
   final SkeletonData? skeletonData;
   final Atlas? atlas;
   final SpineWidgetController controller;
-  final BoxFit? fit;
-  final Alignment? alignment;
-  final AssetType _assetType;
+  final BoxFit fit;
+  final Alignment alignment;
+  final BoundsProvider boundsProvider;
+  final bool sizedByBounds;
 
-  const SpineWidget.asset(this.skeletonFile, this.atlasFile, this.controller, {this.fit, this.alignment, super.key})
+  const SpineWidget.asset(this.skeletonFile, this.atlasFile, this.controller, {BoxFit? fit, Alignment? alignment, BoundsProvider? boundsProvider, bool? sizedByBounds, super.key})
       : _assetType = AssetType.Asset,
-        atlas = null,
-        skeletonData = null;
-
-  const SpineWidget.file(this.skeletonFile, this.atlasFile, this.controller, {this.fit, this.alignment, super.key})
+        fit = fit ?? BoxFit.contain,
+        alignment = alignment ?? Alignment.center,
+        boundsProvider = boundsProvider ?? const SetupPoseBounds(),
+        sizedByBounds = sizedByBounds ?? false,
+        skeletonData = null,
+        atlas = null;
+
+  const SpineWidget.file(this.skeletonFile, this.atlasFile, this.controller, {BoxFit? fit, Alignment? alignment, BoundsProvider? boundsProvider, bool? sizedByBounds, super.key})
       : _assetType = AssetType.File,
-        atlas = null,
-        skeletonData = null;
-
-  const SpineWidget.http(this.skeletonFile, this.atlasFile, this.controller, {this.fit, this.alignment, super.key})
+        fit = fit ?? BoxFit.contain,
+        alignment = alignment ?? Alignment.center,
+        boundsProvider = boundsProvider ?? const SetupPoseBounds(),
+        sizedByBounds = sizedByBounds ?? false,
+        skeletonData = null,
+        atlas = null;
+
+  const SpineWidget.http(this.skeletonFile, this.atlasFile, this.controller, {BoxFit? fit, Alignment? alignment, BoundsProvider? boundsProvider, bool? sizedByBounds, super.key})
       : _assetType = AssetType.Http,
-        atlas = null,
-        skeletonData = null;
-
-  const SpineWidget.raw(this.skeletonData, this.atlas, this.controller, {this.fit, this.alignment, super.key})
+        fit = fit ?? BoxFit.contain,
+        alignment = alignment ?? Alignment.center,
+        boundsProvider = boundsProvider ?? const SetupPoseBounds(),
+        sizedByBounds = sizedByBounds ?? false,
+        skeletonData = null,
+        atlas = null;
+
+  const SpineWidget.raw(this.skeletonData, this.atlas, this.controller, {BoxFit? fit, Alignment? alignment, BoundsProvider? boundsProvider, bool? sizedByBounds, super.key})
       : _assetType = AssetType.Raw,
-        atlasFile = null,
-        skeletonFile = null;
+        fit = fit ?? BoxFit.contain,
+        alignment = alignment ?? Alignment.center,
+        boundsProvider = boundsProvider ?? const SetupPoseBounds(),
+        sizedByBounds = sizedByBounds ?? false,
+        skeletonFile = null,
+        atlasFile = null;
 
   @override
   State<SpineWidget> createState() => _SpineWidgetState();
@@ -131,7 +179,7 @@ class _SpineWidgetState extends State<SpineWidget> {
   Widget build(BuildContext context) {
     if (skeletonDrawable != null) {
       print("Skeleton loaded, rebuilding painter");
-      return _SpineRenderObjectWidget(skeletonDrawable!, widget.controller, widget.fit, widget.alignment);
+      return _SpineRenderObjectWidget(skeletonDrawable!, widget.fit, widget.alignment, widget.boundsProvider, widget.sizedByBounds);
     } else {
       print("Skeleton not loaded yet");
       return const SizedBox();
@@ -147,38 +195,46 @@ class _SpineWidgetState extends State<SpineWidget> {
 
 class _SpineRenderObjectWidget extends LeafRenderObjectWidget {
   final SkeletonDrawable _skeletonDrawable;
-  final SpineWidgetController _controller;
   final BoxFit _fit;
   final Alignment _alignment;
+  final BoundsProvider _boundsProvider;
+  final bool _sizedByBounds;
 
-  _SpineRenderObjectWidget(this._skeletonDrawable, this._controller, BoxFit? fit, Alignment? alignment) :
-        _fit = fit ?? BoxFit.contain,
-        _alignment = alignment ?? Alignment.center;
+  _SpineRenderObjectWidget(this._skeletonDrawable, this._fit, this._alignment, this._boundsProvider, this._sizedByBounds);
 
   @override
   RenderObject createRenderObject(BuildContext context) {
-    return _SpineRenderObject(_skeletonDrawable, _controller, _fit, _alignment);
+    return _SpineRenderObject(_skeletonDrawable, _fit, _alignment, _boundsProvider, _sizedByBounds);
   }
 
   @override
   void updateRenderObject(BuildContext context, covariant _SpineRenderObject renderObject) {
     renderObject.skeletonDrawable = _skeletonDrawable;
+    renderObject.fit = _fit;
+    renderObject.alignment = _alignment;
+    renderObject.boundsProvider = _boundsProvider;
+    renderObject.sizedByBounds = _sizedByBounds;
   }
 }
 
 class _SpineRenderObject extends RenderBox {
   SkeletonDrawable _skeletonDrawable;
-  SpineWidgetController _controller;
   double _deltaTime = 0;
   final Stopwatch _stopwatch = Stopwatch();
   BoxFit _fit;
   Alignment _alignment;
+  BoundsProvider _boundsProvider;
+  bool _sizedByBounds;
   Bounds _bounds;
+  _SpineRenderObject(this._skeletonDrawable, this._fit, this._alignment, this._boundsProvider, this._sizedByBounds): _bounds = _boundsProvider.computeBounds(_skeletonDrawable);
 
-  _SpineRenderObject(this._skeletonDrawable, this._controller, this._fit, this._alignment): _bounds = _computeBounds(_skeletonDrawable);
+  set skeletonDrawable(SkeletonDrawable skeletonDrawable) {
+    if (_skeletonDrawable == skeletonDrawable) return;
 
-  static Bounds _computeBounds(SkeletonDrawable drawable) {
-    return drawable.skeleton.getBounds();
+    _skeletonDrawable = skeletonDrawable;
+    _bounds = _boundsProvider.computeBounds(_skeletonDrawable);
+    markNeedsLayout();
+    markNeedsPaint();
   }
 
   BoxFit get fit => _fit;
@@ -186,6 +242,7 @@ class _SpineRenderObject extends RenderBox {
   set fit(BoxFit fit) {
     if (fit != _fit) {
       _fit = fit;
+      markNeedsLayout();
       markNeedsPaint();
     }
   }
@@ -195,20 +252,34 @@ class _SpineRenderObject extends RenderBox {
   set alignment(Alignment alignment) {
     if (alignment != _alignment) {
       _alignment = alignment;
+      markNeedsLayout();
       markNeedsPaint();
     }
   }
 
-  set skeletonDrawable(SkeletonDrawable skeletonDrawable) {
-    if (_skeletonDrawable == skeletonDrawable) return;
+  BoundsProvider get boundsProvider => _boundsProvider;
 
-    _skeletonDrawable = skeletonDrawable;
-    _bounds = _computeBounds(_skeletonDrawable);
-    markNeedsPaint();
+  set boundsProvider(BoundsProvider boundsProvider) {
+    if (boundsProvider != _boundsProvider) {
+      _boundsProvider = boundsProvider;
+      _bounds = boundsProvider.computeBounds(_skeletonDrawable);
+      markNeedsLayout();
+      markNeedsPaint();
+    }
+  }
+
+  bool get sizedByBounds => _sizedByBounds;
+
+  set sizedByBounds(bool sizedByBounds) {
+    if (sizedByBounds != _sizedByBounds) {
+      _sizedByBounds = _sizedByBounds;
+      markNeedsLayout();
+      markNeedsPaint();
+    }
   }
 
   @override
-  bool get sizedByParent => true;
+  bool get sizedByParent => !_sizedByBounds;
 
   @override
   bool get isRepaintBoundary => true;