浏览代码

[flutter] Refactoring, example selector

Mario Zechner 3 年之前
父节点
当前提交
a986469e07
共有 3 个文件被更改,包括 176 次插入141 次删除
  1. 39 140
      spine-flutter/example/lib/main.dart
  2. 2 1
      spine-flutter/lib/spine_flutter.dart
  3. 135 0
      spine-flutter/lib/spine_widget.dart

+ 39 - 140
spine-flutter/example/lib/main.dart

@@ -1,154 +1,53 @@
 import 'package:flutter/material.dart';
-import 'package:flutter/rendering.dart';
-import 'package:flutter/scheduler.dart';
-import 'package:spine_flutter/spine_flutter.dart' as spine_flutter;
-import 'package:flutter/services.dart' show rootBundle;
 import 'package:spine_flutter/spine_flutter.dart';
 
-void main() {
-  runApp(const MyApp());
-}
-
-class SpineWidget extends StatefulWidget {
-  final String skeletonFile;
-  final String atlasFile;
-
-  const SpineWidget(this.skeletonFile, this.atlasFile, {super.key});
-
-  @override
-  State<SpineWidget> createState() => _SpineWidgetState();
-}
-
-class _SpineWidgetState extends State<SpineWidget> {
-  SpineSkeletonDrawable? skeletonDrawable;
-
-  @override
-  void initState() {
-    super.initState();
-    loadSkeleton(widget.skeletonFile, widget.atlasFile);
-  }
-
-  void loadSkeleton(String skeletonFile, String atlasFile) async {
-    final atlas = await spine_flutter.SpineAtlas.fromAsset(rootBundle, atlasFile);
-    final skeletonData = skeletonFile.endsWith(".json") ?
-    spine_flutter.SpineSkeletonData.fromJson(atlas, await rootBundle.loadString(skeletonFile))
-        : spine_flutter.SpineSkeletonData.fromBinary(atlas, await rootBundle.load(skeletonFile));
-    skeletonDrawable = spine_flutter.SpineSkeletonDrawable(atlas, skeletonData);
-    skeletonDrawable?.update(0.016);
-    setState(() {});
-  }
-
+class ExampleSelector extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
-    if (skeletonDrawable != null) {
-      print("Skeleton loaded, rebuilding painter");
-      return _SpineRenderObjectWidget(skeletonDrawable!);
-    } else {
-      print("Skeleton not loaded yet");
-      return SizedBox();
-    }
-  }
-}
-
-class _SpineRenderObjectWidget extends LeafRenderObjectWidget {
-  final SpineSkeletonDrawable skeletonDrawable;
-  _SpineRenderObjectWidget(this.skeletonDrawable);
-
-  @override
-  RenderObject createRenderObject(BuildContext context) {
-    return _SpineRenderObject(skeletonDrawable);
-  }
-
-  @override
-  void updateRenderObject(BuildContext context, covariant _SpineRenderObject renderObject) {
-    renderObject.skeletonDrawable = skeletonDrawable;
-  }
-}
-
-class _SpineRenderObject extends RenderBox {
-  SpineSkeletonDrawable _skeletonDrawable;
-  double _deltaTime = 0;
-  final Stopwatch _stopwatch = Stopwatch();
-
-  _SpineRenderObject(this._skeletonDrawable);
-
-  set skeletonDrawable(SpineSkeletonDrawable skeletonDrawable) {
-    if (_skeletonDrawable == skeletonDrawable) return;
-
-    // FIXME dispose old drawable here?
-    _skeletonDrawable = skeletonDrawable;
-    markNeedsPaint();
-  }
-
-  @override
-  bool get sizedByParent => true;
-
-  @override
-  bool get isRepaintBoundary => true;
-
-  @override
-  bool hitTestSelf(Offset position) => true;
-
-  @override
-  void performResize() {
-    size = constraints.biggest;
-  }
-
-  @override
-  void attach(PipelineOwner owner) {
-    super.attach(owner);
-    _stopwatch.start();
-  }
-
-  @override
-  void detach() {
-    _stopwatch.stop();
-    super.detach();
-  }
-
-  void _beginFrame(Duration duration) {
-    _deltaTime = _stopwatch.elapsedTicks / _stopwatch.frequency;
-    _stopwatch.reset();
-    _stopwatch.start();
-    markNeedsPaint();
-  }
-
-  @override
-  void paint(PaintingContext context, Offset offset) {
-    print("painting");
-    final Canvas canvas = context.canvas
-      ..save()
-      ..clipRect(offset & size);
-
-    final commands = _skeletonDrawable.render();
-    canvas.save();
-    canvas.translate(offset.dx, offset.dy);
-    for (final cmd in commands) {
-      canvas.drawVertices(cmd.vertices, BlendMode.modulate, _skeletonDrawable.atlas.atlasPagePaints[cmd.atlasPageIndex]);
-    }
-
-    canvas.restore();
-    SchedulerBinding.instance.scheduleFrameCallback(_beginFrame);
+    const spacer = SizedBox(height: 10);
+
+    return Scaffold(
+        appBar: AppBar(title: const Text('Spine Examples')),
+        body: Center(
+          child: Column(
+            mainAxisSize: MainAxisSize.min,
+            children: [
+              ElevatedButton(
+                child: const Text('Spineboy'),
+                onPressed: () {
+                  Navigator.push(
+                    context,
+                    MaterialPageRoute<void>(
+                      builder: (context) => const Spineboy(),
+                    ),
+                  );
+                },
+              ),
+              spacer
+            ]
+          )
+        )
+    );
   }
 }
 
-class MyApp extends StatefulWidget {
-  const MyApp({Key? key}) : super(key: key);
-
-  @override
-  _MyAppState createState() => _MyAppState();
-}
-
-class _MyAppState extends State<MyApp> {
-  @override
-  void initState() {
-    super.initState();
-  }
+class Spineboy extends StatelessWidget {
+  const Spineboy({Key? key}) : super(key: key);
 
   @override
   Widget build(BuildContext context) {
-    return const MaterialApp(
-      home: SpineWidget("assets/spineboy-pro.json", "assets/spineboy.atlas")
+    return Scaffold(
+      appBar: AppBar(title: const Text('Spineboy')),
+      body: const Center(
+        child: SpineWidget("assets/spineboy-pro.skel", "assets/spineboy.atlas")
+      ),
     );
   }
 }
+
+void main() {
+  runApp(MaterialApp(
+      title: "Spine Examples",
+      home: Spineboy()
+  ));
+}

+ 2 - 1
spine-flutter/lib/spine_flutter.dart

@@ -7,6 +7,7 @@ import 'package:flutter/rendering.dart';
 
 import 'package:flutter/services.dart';
 import 'spine_flutter_bindings_generated.dart';
+export 'spine_widget.dart';
 import 'package:path/path.dart' as Path;
 
 int majorVersion() => _bindings.spine_major_version();
@@ -150,4 +151,4 @@ final DynamicLibrary _dylib = () {
   throw UnsupportedError('Unknown platform: ${Platform.operatingSystem}');
 }();
 
-final SpineFlutterBindings _bindings = SpineFlutterBindings(_dylib);
+final SpineFlutterBindings _bindings = SpineFlutterBindings(_dylib);

+ 135 - 0
spine-flutter/lib/spine_widget.dart

@@ -0,0 +1,135 @@
+import 'package:flutter/rendering.dart';
+import 'package:flutter/scheduler.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter/widgets.dart';
+
+import 'spine_flutter.dart';
+
+class SpineWidget extends StatefulWidget {
+  final String skeletonFile;
+  final String atlasFile;
+
+  const SpineWidget(this.skeletonFile, this.atlasFile, {super.key});
+
+  @override
+  State<SpineWidget> createState() => _SpineWidgetState();
+}
+
+class _SpineWidgetState extends State<SpineWidget> {
+  SpineSkeletonDrawable? skeletonDrawable;
+
+  @override
+  void initState() {
+    super.initState();
+    loadSkeleton(widget.skeletonFile, widget.atlasFile);
+  }
+
+  void loadSkeleton(String skeletonFile, String atlasFile) async {
+    final atlas =
+    await SpineAtlas.fromAsset(rootBundle, atlasFile);
+    final skeletonData = skeletonFile.endsWith(".json")
+        ? SpineSkeletonData.fromJson(
+        atlas, await rootBundle.loadString(skeletonFile))
+        : SpineSkeletonData.fromBinary(
+        atlas, await rootBundle.load(skeletonFile));
+    skeletonDrawable = SpineSkeletonDrawable(atlas, skeletonData);
+    skeletonDrawable?.update(0.016);
+    setState(() {});
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    if (skeletonDrawable != null) {
+      print("Skeleton loaded, rebuilding painter");
+      return _SpineRenderObjectWidget(skeletonDrawable!);
+    } else {
+      print("Skeleton not loaded yet");
+      return SizedBox();
+    }
+  }
+}
+
+class _SpineRenderObjectWidget extends LeafRenderObjectWidget {
+  final SpineSkeletonDrawable skeletonDrawable;
+
+  _SpineRenderObjectWidget(this.skeletonDrawable);
+
+  @override
+  RenderObject createRenderObject(BuildContext context) {
+    return _SpineRenderObject(skeletonDrawable);
+  }
+
+  @override
+  void updateRenderObject(BuildContext context,
+      covariant _SpineRenderObject renderObject) {
+    renderObject.skeletonDrawable = skeletonDrawable;
+  }
+}
+
+class _SpineRenderObject extends RenderBox {
+  SpineSkeletonDrawable _skeletonDrawable;
+  double _deltaTime = 0;
+  final Stopwatch _stopwatch = Stopwatch();
+
+  _SpineRenderObject(this._skeletonDrawable);
+
+  set skeletonDrawable(SpineSkeletonDrawable skeletonDrawable) {
+    if (_skeletonDrawable == skeletonDrawable) return;
+
+    // FIXME dispose old drawable here?
+    _skeletonDrawable = skeletonDrawable;
+    markNeedsPaint();
+  }
+
+  @override
+  bool get sizedByParent => true;
+
+  @override
+  bool get isRepaintBoundary => true;
+
+  @override
+  bool hitTestSelf(Offset position) => true;
+
+  @override
+  void performResize() {
+    size = constraints.biggest;
+  }
+
+  @override
+  void attach(PipelineOwner owner) {
+    super.attach(owner);
+    _stopwatch.start();
+  }
+
+  @override
+  void detach() {
+    _stopwatch.stop();
+    super.detach();
+  }
+
+  void _beginFrame(Duration duration) {
+    _deltaTime = _stopwatch.elapsedTicks / _stopwatch.frequency;
+    _stopwatch.reset();
+    _stopwatch.start();
+    _skeletonDrawable.update(_deltaTime);
+    markNeedsPaint();
+  }
+
+  @override
+  void paint(PaintingContext context, Offset offset) {
+    final Canvas canvas = context.canvas
+      ..save()
+      ..clipRect(offset & size);
+
+    final commands = _skeletonDrawable.render();
+    canvas.save();
+    canvas.translate(offset.dx + size.width / 2, offset.dy + size.height);
+    for (final cmd in commands) {
+      canvas.drawVertices(cmd.vertices, BlendMode.modulate,
+          _skeletonDrawable.atlas.atlasPagePaints[cmd.atlasPageIndex]);
+    }
+
+    canvas.restore();
+    SchedulerBinding.instance.scheduleFrameCallback(_beginFrame);
+  }
+}