mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-15 11:31:37 +08:00
[flutter] Add SpineWidgetController.pause/resume/isPlaying. Can be used to stop frame updates entirely.
This commit is contained in:
parent
147439fe95
commit
455189c000
@ -10,7 +10,6 @@ class PlayPauseAnimation extends StatefulWidget {
|
||||
|
||||
class PlayPauseAnimationState extends State<PlayPauseAnimation> {
|
||||
late SpineWidgetController controller;
|
||||
late bool isPlaying;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -18,12 +17,14 @@ class PlayPauseAnimationState extends State<PlayPauseAnimation> {
|
||||
controller = SpineWidgetController(onInitialized: (controller) {
|
||||
controller.animationState.setAnimationByName(0, "flying", true);
|
||||
});
|
||||
isPlaying = true;
|
||||
}
|
||||
|
||||
void _togglePlay() {
|
||||
isPlaying = !isPlaying;
|
||||
controller.animationState.setTimeScale(isPlaying ? 1 : 0);
|
||||
if (controller.isPlaying) {
|
||||
controller.pause();
|
||||
} else {
|
||||
controller.resume();
|
||||
}
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
@ -41,7 +42,7 @@ class PlayPauseAnimationState extends State<PlayPauseAnimation> {
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: _togglePlay,
|
||||
child: Icon(isPlaying ? Icons.pause : Icons.play_arrow),
|
||||
child: Icon(controller.isPlaying ? Icons.pause : Icons.play_arrow),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@ -14,9 +14,7 @@ class SimpleAnimation extends StatelessWidget {
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('Simple Animation')),
|
||||
body: SpineWidget.fromAsset("assets/spineboy.atlas", "assets/spineboy-pro.skel", controller),
|
||||
// body: SpineWidget.file( "/Users/badlogic/workspaces/spine-runtimes/examples/spineboy/export/spineboy.atlas", "/Users/badlogic/workspaces/spine-runtimes/examples/spineboy/export/spineboy-pro.skel", controller),
|
||||
// body: const SpineWidget.http("https://marioslab.io/dump/spineboy/spineboy.atlas", "https://marioslab.io/dump/spineboy/spineboy-pro.json"),
|
||||
body: SpineWidget.fromAsset("assets/spineboy.atlas", "assets/spineboy-pro.skel", controller)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,9 +28,15 @@ import 'spine_flutter.dart';
|
||||
/// The underlying [Atlas], [SkeletonData], [Skeleton], [AnimationStateData], [AnimationState], and [SkeletonDrawable]
|
||||
/// can be accessed through their respective getters to inspect and/or modify the skeleton and its associated data. Accessing
|
||||
/// this data is only allowed if the [SpineWidget] and its data have been initialized and have not been disposed yet.
|
||||
///
|
||||
/// By default, the widget updates and renders the skeleton every frame. The [pause] method can be used to pause updating
|
||||
/// and rendering the skeleton. The [resume] method resumes updating and rendering the skeleton. The [isPlaying] getter
|
||||
/// reports the current state.
|
||||
class SpineWidgetController {
|
||||
SkeletonDrawable? _drawable;
|
||||
double _offsetX = 0, _offsetY = 0, _scaleX = 1, _scaleY = 1;
|
||||
bool _isPlaying = true;
|
||||
_SpineRenderObject? _renderObject = null;
|
||||
final void Function(SpineWidgetController controller)? onInitialized;
|
||||
final void Function(SpineWidgetController controller)? onBeforeUpdateWorldTransforms;
|
||||
final void Function(SpineWidgetController controller)? onAfterUpdateWorldTransforms;
|
||||
@ -92,6 +98,10 @@ class SpineWidgetController {
|
||||
_scaleY = scaleY;
|
||||
}
|
||||
|
||||
void _setRenderObject(_SpineRenderObject? renderObject) {
|
||||
_renderObject = renderObject;
|
||||
}
|
||||
|
||||
/// Transforms the coordinates given in the [SpineWidget] coordinate system in [position] to
|
||||
/// the skeleton coordinate system. See the `ik_following.dart` example how to use this
|
||||
/// to move a bone based on user touch input.
|
||||
@ -100,6 +110,23 @@ class SpineWidgetController {
|
||||
var y = position.dy;
|
||||
return Offset(x / _scaleX - _offsetX, y / _scaleY - _offsetY);
|
||||
}
|
||||
|
||||
/// Pauses updating and rendering the skeleton.
|
||||
void pause() {
|
||||
_isPlaying = false;
|
||||
}
|
||||
|
||||
/// Resumes updating and rendering the skeleton.
|
||||
void resume() {
|
||||
_isPlaying = true;
|
||||
_renderObject?._stopwatch.reset();
|
||||
_renderObject?._stopwatch.start();
|
||||
_renderObject?._scheduleFrame();
|
||||
}
|
||||
|
||||
bool get isPlaying {
|
||||
return _isPlaying;
|
||||
}
|
||||
}
|
||||
|
||||
enum _AssetType { asset, file, http, drawable }
|
||||
@ -391,6 +418,7 @@ class _SpineRenderObject extends RenderBox {
|
||||
Alignment _alignment;
|
||||
Bounds _bounds;
|
||||
bool _sizedByBounds;
|
||||
bool _disposed = false;
|
||||
|
||||
_SpineRenderObject(this._skeletonDrawable, this._controller, this._fit, this._alignment, this._bounds, this._sizedByBounds);
|
||||
|
||||
@ -493,22 +521,39 @@ class _SpineRenderObject extends RenderBox {
|
||||
void attach(rendering.PipelineOwner owner) {
|
||||
super.attach(owner);
|
||||
_stopwatch.start();
|
||||
SchedulerBinding.instance.scheduleFrameCallback(_beginFrame);
|
||||
_controller._setRenderObject(this);
|
||||
}
|
||||
|
||||
@override
|
||||
void detach() {
|
||||
_stopwatch.stop();
|
||||
super.detach();
|
||||
_controller._setRenderObject(null);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
void _scheduleFrame() {
|
||||
SchedulerBinding.instance.scheduleFrameCallback(_beginFrame);
|
||||
}
|
||||
|
||||
void _beginFrame(Duration duration) {
|
||||
if (_disposed) return;
|
||||
_deltaTime = _stopwatch.elapsedTicks / _stopwatch.frequency;
|
||||
_stopwatch.reset();
|
||||
_stopwatch.start();
|
||||
_controller.onBeforeUpdateWorldTransforms?.call(_controller);
|
||||
_skeletonDrawable.update(_deltaTime);
|
||||
_controller.onAfterUpdateWorldTransforms?.call(_controller);
|
||||
markNeedsPaint();
|
||||
if (_controller.isPlaying) {
|
||||
_controller.onBeforeUpdateWorldTransforms?.call(_controller);
|
||||
_skeletonDrawable.update(_deltaTime);
|
||||
_controller.onAfterUpdateWorldTransforms?.call(_controller);
|
||||
markNeedsPaint();
|
||||
_scheduleFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void _setCanvasTransform(Canvas canvas, Offset offset) {
|
||||
@ -568,6 +613,5 @@ class _SpineRenderObject extends RenderBox {
|
||||
_controller.onAfterPaint?.call(_controller, canvas, commands);
|
||||
|
||||
canvas.restore();
|
||||
SchedulerBinding.instance.scheduleFrameCallback(_beginFrame);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user