Flutter无限画布绘制插件infinite_canvas的使用

发布于 1周前 作者 nodeper 来自 Flutter

Flutter无限画布绘制插件infinite_canvas的使用

Infinite Canvas

infinite_canvas

Flutter无限画布(Infinite Canvas)是一个可以缩放和平移的画布。此外,它还提供了一个用于常见操作的菜单和用于多选的虚线框。

示例代码

主程序入口

import 'package:flutter/material.dart';
import 'package:infinite_canvas/infinite_canvas.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: const Example(),
      theme: ThemeData.light(useMaterial3: true),
      darkTheme: ThemeData.dark(useMaterial3: true),
      themeMode: ThemeMode.system,
    );
  }
}

无限画布示例

class Example extends StatefulWidget {
  const Example({super.key});

  @override
  State<Example> createState() => _ExampleState();
}

class _ExampleState extends State<Example> {
  late InfiniteCanvasController controller;

  @override
  void initState() {
    super.initState();
    final rectangleNode = InfiniteCanvasNode(
      key: UniqueKey(),
      label: 'Rectangle',
      offset: const Offset(400, 300),
      size: const Size(200, 200),
      child: Builder(
        builder: (context) {
          return CustomPaint(
            isComplex: true,
            willChange: true,
            painter: InlineCustomPainter(
              brush: Paint(),
              builder: (brush, canvas, rect) {
                // Draw rect
                brush.color = Theme.of(context).colorScheme.secondary;
                canvas.drawRect(rect, brush);
              },
            ),
          );
        },
      ),
    );
    final triangleNode = InfiniteCanvasNode(
      key: UniqueKey(),
      label: 'Triangle',
      offset: const Offset(550, 300),
      size: const Size(200, 200),
      child: Builder(
        builder: (context) {
          return CustomPaint(
            painter: InlineCustomPainter(
              brush: Paint(),
              builder: (brush, canvas, rect) {
                // Draw triangle
                brush.color = Theme.of(context).colorScheme.secondaryContainer;
                final path = Path();
                path.addPolygon([
                  rect.topCenter,
                  rect.bottomLeft,
                  rect.bottomRight,
                ], true);
                canvas.drawPath(path, brush);
              },
            ),
          );
        },
      ),
    );
    final circleNode = InfiniteCanvasNode(
      key: UniqueKey(),
      label: 'Circle',
      offset: const Offset(500, 450),
      size: const Size(200, 200),
      child: Builder(
        builder: (context) {
          return CustomPaint(
            painter: InlineCustomPainter(
              brush: Paint(),
              builder: (brush, canvas, rect) {
                // Draw circle
                brush.color = Theme.of(context).colorScheme.tertiary;
                canvas.drawCircle(rect.center, rect.width / 2, brush);
              },
            ),
          );
        },
      ),
    );
    final nodes = [
      rectangleNode,
      triangleNode,
      circleNode,
    ];
    controller = InfiniteCanvasController(nodes: nodes, edges: [
      InfiniteCanvasEdge(
        from: rectangleNode.key,
        to: triangleNode.key,
        label: '4 -> 3',
      ),
      InfiniteCanvasEdge(
        from: rectangleNode.key,
        to: circleNode.key,
        label: '[] -> ()',
      ),
      InfiniteCanvasEdge(
        from: triangleNode.key,
        to: circleNode.key,
      ),
    ]);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Infinite Canvas Example'),
        centerTitle: false,
      ),
      body: InfiniteCanvas(
        controller: controller,
      ),
    );
  }
}

class InlineCustomPainter extends CustomPainter {
  const InlineCustomPainter({
    required this.brush,
    required this.builder,
    this.isAntiAlias = true,
  });
  final Paint brush;
  final bool isAntiAlias;
  final void Function(Paint paint, Canvas canvas, Rect rect) builder;

  @override
  void paint(Canvas canvas, Size size) {
    final rect = Offset.zero & size;
    brush.isAntiAlias = isAntiAlias;
    canvas.save();
    builder(brush, canvas, rect);
    canvas.restore();
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return true;
  }
}

示例节点生成

import 'package:flutter/material.dart';

import 'generated_nodes.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: const GeneratedNodes(),
      theme: ThemeData.light(useMaterial3: true),
      darkTheme: ThemeData.dark(useMaterial3: true),
      themeMode: ThemeMode.system,
    );
  }
}

链接

通过上述代码,您可以创建一个具有矩形、三角形和圆形的无限画布,并且这些图形之间可以通过边进行连接。您还可以通过InfiniteCanvasController来控制画布的状态,如缩放和平移等操作。希望这个示例能帮助您更好地理解和使用infinite_canvas插件。


更多关于Flutter无限画布绘制插件infinite_canvas的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter无限画布绘制插件infinite_canvas的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何使用Flutter中的infinite_canvas插件来创建一个无限画布的示例代码。这个插件允许用户在画布上无限滚动并绘制内容。

首先,确保你已经在pubspec.yaml文件中添加了infinite_canvas依赖:

dependencies:
  flutter:
    sdk: flutter
  infinite_canvas: ^最新版本号  # 请替换为实际的最新版本号

然后,运行flutter pub get来安装依赖。

接下来,创建一个Flutter应用并使用InfiniteCanvas组件。以下是一个完整的示例代码:

import 'package:flutter/material.dart';
import 'package:infinite_canvas/infinite_canvas.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Infinite Canvas Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: InfiniteCanvasScreen(),
    );
  }
}

class InfiniteCanvasScreen extends StatefulWidget {
  @override
  _InfiniteCanvasScreenState createState() => _InfiniteCanvasScreenState();
}

class _InfiniteCanvasScreenState extends State<InfiniteCanvasScreen> {
  final InfiniteCanvasController _controller = InfiniteCanvasController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Infinite Canvas Demo'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: InfiniteCanvas(
          controller: _controller,
          backgroundColor: Colors.white,
          gridColor: Colors.grey.withOpacity(0.2),
          gridSize: 20,
          onStrokeStart: (details) {
            // 当开始绘制时回调
            print('Stroke started at: ${details.globalPosition}');
          },
          onStrokeUpdate: (details) {
            // 当绘制过程中回调
            print('Stroke updated at: ${details.globalPosition}');
          },
          onStrokeEnd: (details) {
            // 当结束绘制时回调
            print('Stroke ended at: ${details.globalPosition}');
          },
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // 清空画布
          _controller.clearCanvas();
        },
        tooltip: 'Clear',
        child: Icon(Icons.clear),
      ),
    );
  }
}

在这个示例中,我们做了以下几件事:

  1. 创建应用入口MyApp是一个StatelessWidget,设置了应用的主题和主页。
  2. 创建主页面InfiniteCanvasScreen是一个StatefulWidget,包含了一个InfiniteCanvas组件。
  3. 初始化控制器:使用InfiniteCanvasController来控制画布的行为。
  4. 配置画布:在InfiniteCanvas组件中,我们设置了背景颜色、网格颜色、网格大小,并提供了几个回调函数来处理绘制开始、更新和结束的事件。
  5. 清空画布按钮:在底部浮动按钮中,我们添加了一个按钮来清空画布内容。

运行这个应用,你会看到一个可以无限滚动的画布,并且可以在上面绘制。按下浮动按钮可以清空画布。

请注意,由于infinite_canvas插件的具体实现和API可能会随着版本更新而变化,因此请务必查阅最新的官方文档以获取最准确的信息。

回到顶部