mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-22 18:26:12 +08:00
[flutter] Bounds type and controllable parent sizing.
This commit is contained in:
parent
c8e2032b1c
commit
86f68ecf04
@ -50,13 +50,13 @@ class SimpleAnimation extends StatelessWidget {
|
|||||||
reportLeaks();
|
reportLeaks();
|
||||||
final controller = SpineWidgetController((controller) {
|
final controller = SpineWidgetController((controller) {
|
||||||
// Set the walk animation on track 0, let it loop
|
// Set the walk animation on track 0, let it loop
|
||||||
// controller.animationState?.setAnimationByName(0, "walk", true);
|
controller.animationState?.setAnimationByName(0, "animation", true);
|
||||||
});
|
});
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: const Text('Spineboy')),
|
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/skeleton.json", "assets/skeleton.atlas", controller, alignment: Alignment.centerLeft, fit: BoxFit.none),
|
||||||
body: SpineWidget.asset("assets/spineboy-pro.skel", "assets/spineboy.atlas", controller)
|
// 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: 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"),
|
// body: const SpineWidget.http("https://marioslab.io/dump/spineboy/spineboy-pro.json", "https://marioslab.io/dump/spineboy/spineboy.atlas"),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -42,35 +42,83 @@ class SpineWidgetController {
|
|||||||
|
|
||||||
enum AssetType { Asset, File, Http, Raw }
|
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 {
|
class SpineWidget extends StatefulWidget {
|
||||||
|
final AssetType _assetType;
|
||||||
final String? skeletonFile;
|
final String? skeletonFile;
|
||||||
final String? atlasFile;
|
final String? atlasFile;
|
||||||
final SkeletonData? skeletonData;
|
final SkeletonData? skeletonData;
|
||||||
final Atlas? atlas;
|
final Atlas? atlas;
|
||||||
final SpineWidgetController controller;
|
final SpineWidgetController controller;
|
||||||
final BoxFit? fit;
|
final BoxFit fit;
|
||||||
final Alignment? alignment;
|
final Alignment alignment;
|
||||||
final AssetType _assetType;
|
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,
|
: _assetType = AssetType.Asset,
|
||||||
atlas = null,
|
fit = fit ?? BoxFit.contain,
|
||||||
skeletonData = null;
|
alignment = alignment ?? Alignment.center,
|
||||||
|
boundsProvider = boundsProvider ?? const SetupPoseBounds(),
|
||||||
|
sizedByBounds = sizedByBounds ?? false,
|
||||||
|
skeletonData = null,
|
||||||
|
atlas = null;
|
||||||
|
|
||||||
const SpineWidget.file(this.skeletonFile, this.atlasFile, this.controller, {this.fit, this.alignment, super.key})
|
const SpineWidget.file(this.skeletonFile, this.atlasFile, this.controller, {BoxFit? fit, Alignment? alignment, BoundsProvider? boundsProvider, bool? sizedByBounds, super.key})
|
||||||
: _assetType = AssetType.File,
|
: _assetType = AssetType.File,
|
||||||
atlas = null,
|
fit = fit ?? BoxFit.contain,
|
||||||
skeletonData = null;
|
alignment = alignment ?? Alignment.center,
|
||||||
|
boundsProvider = boundsProvider ?? const SetupPoseBounds(),
|
||||||
|
sizedByBounds = sizedByBounds ?? false,
|
||||||
|
skeletonData = null,
|
||||||
|
atlas = null;
|
||||||
|
|
||||||
const SpineWidget.http(this.skeletonFile, this.atlasFile, this.controller, {this.fit, this.alignment, super.key})
|
const SpineWidget.http(this.skeletonFile, this.atlasFile, this.controller, {BoxFit? fit, Alignment? alignment, BoundsProvider? boundsProvider, bool? sizedByBounds, super.key})
|
||||||
: _assetType = AssetType.Http,
|
: _assetType = AssetType.Http,
|
||||||
atlas = null,
|
fit = fit ?? BoxFit.contain,
|
||||||
skeletonData = null;
|
alignment = alignment ?? Alignment.center,
|
||||||
|
boundsProvider = boundsProvider ?? const SetupPoseBounds(),
|
||||||
|
sizedByBounds = sizedByBounds ?? false,
|
||||||
|
skeletonData = null,
|
||||||
|
atlas = null;
|
||||||
|
|
||||||
const SpineWidget.raw(this.skeletonData, this.atlas, this.controller, {this.fit, this.alignment, super.key})
|
const SpineWidget.raw(this.skeletonData, this.atlas, this.controller, {BoxFit? fit, Alignment? alignment, BoundsProvider? boundsProvider, bool? sizedByBounds, super.key})
|
||||||
: _assetType = AssetType.Raw,
|
: _assetType = AssetType.Raw,
|
||||||
atlasFile = null,
|
fit = fit ?? BoxFit.contain,
|
||||||
skeletonFile = null;
|
alignment = alignment ?? Alignment.center,
|
||||||
|
boundsProvider = boundsProvider ?? const SetupPoseBounds(),
|
||||||
|
sizedByBounds = sizedByBounds ?? false,
|
||||||
|
skeletonFile = null,
|
||||||
|
atlasFile = null;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<SpineWidget> createState() => _SpineWidgetState();
|
State<SpineWidget> createState() => _SpineWidgetState();
|
||||||
@ -131,7 +179,7 @@ class _SpineWidgetState extends State<SpineWidget> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (skeletonDrawable != null) {
|
if (skeletonDrawable != null) {
|
||||||
print("Skeleton loaded, rebuilding painter");
|
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 {
|
} else {
|
||||||
print("Skeleton not loaded yet");
|
print("Skeleton not loaded yet");
|
||||||
return const SizedBox();
|
return const SizedBox();
|
||||||
@ -147,38 +195,46 @@ class _SpineWidgetState extends State<SpineWidget> {
|
|||||||
|
|
||||||
class _SpineRenderObjectWidget extends LeafRenderObjectWidget {
|
class _SpineRenderObjectWidget extends LeafRenderObjectWidget {
|
||||||
final SkeletonDrawable _skeletonDrawable;
|
final SkeletonDrawable _skeletonDrawable;
|
||||||
final SpineWidgetController _controller;
|
|
||||||
final BoxFit _fit;
|
final BoxFit _fit;
|
||||||
final Alignment _alignment;
|
final Alignment _alignment;
|
||||||
|
final BoundsProvider _boundsProvider;
|
||||||
|
final bool _sizedByBounds;
|
||||||
|
|
||||||
_SpineRenderObjectWidget(this._skeletonDrawable, this._controller, BoxFit? fit, Alignment? alignment) :
|
_SpineRenderObjectWidget(this._skeletonDrawable, this._fit, this._alignment, this._boundsProvider, this._sizedByBounds);
|
||||||
_fit = fit ?? BoxFit.contain,
|
|
||||||
_alignment = alignment ?? Alignment.center;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
RenderObject createRenderObject(BuildContext context) {
|
RenderObject createRenderObject(BuildContext context) {
|
||||||
return _SpineRenderObject(_skeletonDrawable, _controller, _fit, _alignment);
|
return _SpineRenderObject(_skeletonDrawable, _fit, _alignment, _boundsProvider, _sizedByBounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void updateRenderObject(BuildContext context, covariant _SpineRenderObject renderObject) {
|
void updateRenderObject(BuildContext context, covariant _SpineRenderObject renderObject) {
|
||||||
renderObject.skeletonDrawable = _skeletonDrawable;
|
renderObject.skeletonDrawable = _skeletonDrawable;
|
||||||
|
renderObject.fit = _fit;
|
||||||
|
renderObject.alignment = _alignment;
|
||||||
|
renderObject.boundsProvider = _boundsProvider;
|
||||||
|
renderObject.sizedByBounds = _sizedByBounds;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SpineRenderObject extends RenderBox {
|
class _SpineRenderObject extends RenderBox {
|
||||||
SkeletonDrawable _skeletonDrawable;
|
SkeletonDrawable _skeletonDrawable;
|
||||||
SpineWidgetController _controller;
|
|
||||||
double _deltaTime = 0;
|
double _deltaTime = 0;
|
||||||
final Stopwatch _stopwatch = Stopwatch();
|
final Stopwatch _stopwatch = Stopwatch();
|
||||||
BoxFit _fit;
|
BoxFit _fit;
|
||||||
Alignment _alignment;
|
Alignment _alignment;
|
||||||
|
BoundsProvider _boundsProvider;
|
||||||
|
bool _sizedByBounds;
|
||||||
Bounds _bounds;
|
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) {
|
_skeletonDrawable = skeletonDrawable;
|
||||||
return drawable.skeleton.getBounds();
|
_bounds = _boundsProvider.computeBounds(_skeletonDrawable);
|
||||||
|
markNeedsLayout();
|
||||||
|
markNeedsPaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
BoxFit get fit => _fit;
|
BoxFit get fit => _fit;
|
||||||
@ -186,6 +242,7 @@ class _SpineRenderObject extends RenderBox {
|
|||||||
set fit(BoxFit fit) {
|
set fit(BoxFit fit) {
|
||||||
if (fit != _fit) {
|
if (fit != _fit) {
|
||||||
_fit = fit;
|
_fit = fit;
|
||||||
|
markNeedsLayout();
|
||||||
markNeedsPaint();
|
markNeedsPaint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -195,20 +252,34 @@ class _SpineRenderObject extends RenderBox {
|
|||||||
set alignment(Alignment alignment) {
|
set alignment(Alignment alignment) {
|
||||||
if (alignment != _alignment) {
|
if (alignment != _alignment) {
|
||||||
_alignment = alignment;
|
_alignment = alignment;
|
||||||
|
markNeedsLayout();
|
||||||
markNeedsPaint();
|
markNeedsPaint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
set skeletonDrawable(SkeletonDrawable skeletonDrawable) {
|
BoundsProvider get boundsProvider => _boundsProvider;
|
||||||
if (_skeletonDrawable == skeletonDrawable) return;
|
|
||||||
|
|
||||||
_skeletonDrawable = skeletonDrawable;
|
set boundsProvider(BoundsProvider boundsProvider) {
|
||||||
_bounds = _computeBounds(_skeletonDrawable);
|
if (boundsProvider != _boundsProvider) {
|
||||||
markNeedsPaint();
|
_boundsProvider = boundsProvider;
|
||||||
|
_bounds = boundsProvider.computeBounds(_skeletonDrawable);
|
||||||
|
markNeedsLayout();
|
||||||
|
markNeedsPaint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get sizedByBounds => _sizedByBounds;
|
||||||
|
|
||||||
|
set sizedByBounds(bool sizedByBounds) {
|
||||||
|
if (sizedByBounds != _sizedByBounds) {
|
||||||
|
_sizedByBounds = _sizedByBounds;
|
||||||
|
markNeedsLayout();
|
||||||
|
markNeedsPaint();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool get sizedByParent => true;
|
bool get sizedByParent => !_sizedByBounds;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool get isRepaintBoundary => true;
|
bool get isRepaintBoundary => true;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user