Flutter绘图插件flutter_painter_2的使用

Flutter 绘图插件 flutter_painter_2 的使用

概要

Flutter Painter 提供了一个可以用于绘制的组件。目前它支持:

  • 自由式绘画:您可以使用任意宽度和颜色进行涂鸦。
  • 对象:您可以轻松地移动、缩放和旋转的对象,例如:
    • 文本:具有任何 TextStyle 的文本。
    • 形状:如直线、箭头、椭圆和矩形,具有任何 Paint
    • 图像:可以翻转的图像。
  • 自由式橡皮擦:用于擦除您不想在画布上的任何部分。

这些被称为 可绘制对象(drawable)。

您可以为您的绘制设置背景颜色或背景图像,并导出您的绘画作为图像。

示例

您可以查看示例标签以了解如何使用该包。

示例托管在这里,如果您想亲自尝试!

Flutter Painter 视频演示

使用方法

首先,您需要一个 PainterController 对象。PainterController 控制不同的可绘制对象、绘制背景以及为 FlutterPainter 提供所需的设置。然后,在您的用户界面中,使用带有分配了控制器的 FlutterPainter 组件。

class ExampleWidget extends StatefulWidget {
  const ExampleWidget({Key? key}) : super(key: key);

  @override
  _ExampleWidgetState createState() => _ExampleWidgetState();
}

class _ExampleWidgetState extends State<ExampleWidget> {
  PainterController controller = PainterController();

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: 300,
      height: 300,
      child: FlutterPainter(
        controller: controller,        
      ),
    );
  }
}

您也可以使用 FlutterPainter.builder 构造函数,该构造函数使用构建器方法,当控制器发生更改时会自动更新,而无需使用 setState、回调或监听器。然而,这将比 StatefulWidget 表现得更差,因为它会重建更多次,所以如果依赖于 PainterController 的小部件树很简单,建议使用这种方法。

class ExampleWidget extends StatefulWidget {
  const ExampleWidget({Key? key}) : super(key: key);

  @override
  _ExampleWidgetState createState() => _ExampleWidgetState();
}

class _ExampleWidgetState extends State<ExampleWidget> {
  PainterController controller = PainterController();

  @override
  Widget build(BuildContext context) {
    return FlutterPainter.builder(
      controller: controller,
      builder: (context, painter){
        return SizedBox(
          width: 300,
          height: 300,
          child: painter
        );
      }
    ); 
  }
}

注意事项

  • 注意FlutterPainter 不定义其自身的尺寸约束,因此建议使用可以为其子部件提供尺寸约束的小部件,例如 SizedBoxAspectRatio
  • 注意:如果多个 UI 部分依赖于 PainterController,您可以使用 ValueListenableBuilder,其 valueListenable 为您的控制器,这将在控制器更新时自动重新构建。

回调

FlutterPainter 有一些有用的回调,当内部更改发生时会被调用。

  • onDrawableCreated:当从 FlutterPainter 创建一个可绘制对象时被调用。传递该对象作为参数。
  • onDrawableDeleted:当从 FlutterPainter 删除一个可绘制对象时被调用。传递该对象作为参数。
  • onSelectedObjectDrawableChanged:当所选对象可绘制对象更改时被调用。这在您想要显示一些用于编辑对象属性的 UI 时很有用。传递所选对象可绘制对象作为参数。
    • 如果可绘制对象被更新(例如移动),则传递的可绘制对象将变得无效。确保使用 PainterController.selectedObjectDrawable 获取所选可绘制对象的最新值。
  • onPainterSettingsChanged:当 PainterController 的设置从 FlutterPainter 本身更改时被调用。传递新的设置作为参数。

PainterController

PainterController 是 Flutter Painter 操作的核心。它控制 FlutterPainter 的设置、背景和所有可绘制对象,以及所选对象可绘制对象。

所有 PainterController 上的 setter 直接通知您的 FlutterPainter 进行响应并重绘。如果您使用 FlutterPainter.builder,构建器将自动调用来构建小部件树。如果不这样做,请确保使用 setState 并监听回调。

注意事项

  • 注意:如果您正在使用多个画家,请确保每个 FlutterPainter 小部件都有自己的 PainterController不要 为多个画家使用相同的控制器。

设置

目前有三种类型的设置:

  • freeStyleSettings:它们控制用于绘制涂鸦的参数,如宽度和颜色。它还有一个字段来启用/禁用涂鸦,以防止用户在 FlutterPainter 上绘制。
  • textSettings:它们主要控制要绘制的文本的 TextStyle。它还有一个焦点节点字段,允许您检测用户何时开始和停止编辑文本。
  • objectSettings:这些设置控制可以移动、缩放和旋转的对象。文本、形状和图像是所有被认为是对象。它控制布局辅助功能,允许居中对象并以直角旋转它们,以及关于对象控制的设置,用于缩放、旋转和调整大小。
  • shapeSettings:这些控制使用的 Paint 和形状工厂(用于创建形状),以及形状是一次绘制还是连续绘制。
  • scaleSettings:这些设置控制画布上的缩放(放大/缩小)。默认情况下,缩放是禁用的。

您可以提供初始设置,通过 PainterController 构造函数中的 settings 参数,为您想要绘制的内容。

每个设置和子设置都有扩展的 setter 和 getter,您可以使用它们来读取和修改该设置的值。

例如,这是如何修改自由式绘制的笔画宽度:

void setStrokeWidth(double value){
  controller.freeStyleStrokeWidth = value;
}

注意事项

  • 注意:如果您不使用扩展库,则请注意所有设置对象都是不可变的并且不能被修改,因此为了更改某些设置,您需要创建当前设置的副本并应用所需的更改(这类似于如何复制 ThemeData)。

背景

您还可以从控制器为 FlutterPainter 小部件提供背景。您可以使用颜色或图像作为背景。

要使用颜色,只需调用 backgroundDrawable 扩展获取器即可。

void setBackground(){
  // 将背景设置为黑色
  controller.background = Colors.black.backgroundDrawable;
}

要使用图像,您需要一个来自 dart:ui 库的 Image 对象。由于 Flutter 有一个来自 Material 包的 Image 小部件,我们将引用我们需要的图像类型为 ui.Image

import 'dart:ui' as ui;
ui.Image? myImage;

为了从通常的图像源(文件、资源、网络)获取 ui.Image 对象,您可以使用 ImageProvider 并使用 image 扩展获取器(ImageProvider 的示例:FileImageMemoryImageNetworkImage)。此获取器返回 Future<ui.Image>

然后,您可以使用 ui.Image 上的 backgroundDrawable 扩展获取器。

void setBackground() async {
  // 从网络获取图像并创建 [ui.Image] 对象
  final ui.Image myImage = await NetworkImage('https://picsum.photos/960/720').image;
  // 将背景设置为图像
  controller.background = myImage.backgroundDrawable;
}

背景也可以直接从 PainterController 构造函数中分配。

可绘制对象

所有绘制在 FlutterPainter 上的可绘制对象都存储并由 PainterController 控制。在大多数情况下,您不需要直接与可绘制对象交互。但是,您可能需要从代码中添加、插入、替换或删除可绘制对象(而不让用户实际绘制它们)。

您可以从 PainterController 构造函数中分配一个初始的 drawables 列表,以便使用它们初始化控制器。您还可以从控制器修改它们,但要小心,使用 PainterController 自身的方法,而不是直接修改 drawables 列表。

正确的做法

void addMyDrawables(List<Drawable> drawables){
  controller.addDrawables(drawables);
}

错误的做法

void addMyDrawables(List<Drawable> drawables){
  controller.drawables.addAll(drawables);
}

选定的对象可绘制对象

PainterController 还提供了当前选定的 ObjectDrawable,通过 PainterController.selectedObjectDrawable 获取器字段。此值会根据 UI 中的任何更改保持最新(例如用户选择一个新的对象可绘制对象)。您还可以编程方式选择和取消选择一个对象可绘制对象,前提是它在控制器的可绘制对象列表中。

void selectObjectDrawable(ObjectDrawable drawable){
  controller.selectObjectDrawable(drawable);
}

void deselectObjectDrawable(){
  controller.deselectObjectDrawable();
}

如果选定的对象可绘制对象被替换或从控制器中移除,它也会自动更新。

渲染图像

PainterController,您可以将 FlutterPainter 的内容渲染为 PNG 编码的 ui.Image 对象。为此,您需要提供输出图像的大小。所有绘制都会根据该大小进行缩放。

ui.Image 对象,您可以将其转换为原始字节列表 (Uint8List) 以便使用 Image.memory 显示或保存为文件。

Uint8List? renderImage(Size size) async {
  final ui.Image renderedImage = await controller.renderImage(size);
  final Uint8List? byteData = await renderedImage.pngBytes;
  return byteData;
}

更多关于Flutter绘图插件flutter_painter_2的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

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


flutter_painter_2 是一个用于在 Flutter 应用中实现绘图功能的插件。它允许用户在画布上绘制线条、形状、文本等,并且支持手势操作。以下是如何使用 flutter_painter_2 的基本步骤。

1. 添加依赖

首先,在 pubspec.yaml 文件中添加 flutter_painter_2 的依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_painter_2: ^1.0.0  # 请使用最新的版本

然后运行 flutter pub get 来获取依赖。

2. 导入包

在你的 Dart 文件中导入 flutter_painter_2 包:

import 'package:flutter_painter_2/flutter_painter_2.dart';

3. 创建绘图画布

使用 Painter widget 来创建一个绘图画布。你可以在 Painter 中配置各种绘图工具和样式。

class MyPainter extends StatefulWidget {
  [@override](/user/override)
  _MyPainterState createState() => _MyPainterState();
}

class _MyPainterState extends State<MyPainter> {
  PainterController? _controller;

  [@override](/user/override)
  void initState() {
    super.initState();
    _controller = PainterController()
      ..setDrawMode(DrawMode.freeStyle) // 设置绘图模式为自由绘制
      ..setStrokeColor(Colors.black) // 设置画笔颜色
      ..setStrokeWidth(5.0); // 设置画笔宽度
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Painter 2'),
      ),
      body: Center(
        child: Painter(
          controller: _controller!,
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // 保存绘制的图像
          final image = await _controller!.renderImage();
          // 处理保存的图像
        },
        child: Icon(Icons.save),
      ),
    );
  }
}

4. 配置绘图工具

PainterController 提供了多种方法来配置绘图工具和样式。以下是一些常用的配置:

  • setDrawMode(DrawMode mode): 设置绘图模式,如自由绘制 (DrawMode.freeStyle)、直线 (DrawMode.line)、矩形 (DrawMode.rect) 等。
  • setStrokeColor(Color color): 设置画笔颜色。
  • setStrokeWidth(double width): 设置画笔宽度。
  • setFillColor(Color color): 设置填充颜色(适用于形状绘制)。
  • setTextStyle(TextStyle style): 设置文本样式(适用于文本绘制)。

5. 保存绘图结果

你可以使用 PainterControllerrenderImage() 方法来将绘制的图像保存为 ui.Image 对象。然后你可以将其转换为 Uint8List 或保存到文件中。

final image = await _controller!.renderImage();
final byteData = await image.toByteData(format: ImageByteFormat.png);
final Uint8List imageBytes = byteData!.buffer.asUint8List();

6. 清除画布

你可以使用 PainterControllerclear() 方法来清除画布上的所有内容。

_controller!.clear();

7. 其他功能

flutter_painter_2 还支持撤销/重做、缩放、平移等功能。你可以通过 PainterController 提供的方法来实现这些功能。

示例代码

以下是一个完整的示例代码,展示了如何使用 flutter_painter_2 创建一个简单的绘图应用:

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

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

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyPainter(),
    );
  }
}

class MyPainter extends StatefulWidget {
  [@override](/user/override)
  _MyPainterState createState() => _MyPainterState();
}

class _MyPainterState extends State<MyPainter> {
  PainterController? _controller;

  [@override](/user/override)
  void initState() {
    super.initState();
    _controller = PainterController()
      ..setDrawMode(DrawMode.freeStyle)
      ..setStrokeColor(Colors.black)
      ..setStrokeWidth(5.0);
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Painter 2'),
      ),
      body: Center(
        child: Painter(
          controller: _controller!,
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          final image = await _controller!.renderImage();
          final byteData = await image.toByteData(format: ImageByteFormat.png);
          final Uint8List imageBytes = byteData!.buffer.asUint8List();
          // 处理保存的图像
        },
        child: Icon(Icons.save),
      ),
    );
  }
}
回到顶部