Flutter绘图与涂鸦插件flutter_painter的使用

Flutter绘图与涂鸦插件flutter_painter的使用

Flutter Painter 🎨🖌️

pub package Buy Me A Pizza

一个纯Flutter包,用于绘画。

Summary

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

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

这些被称为可绘制对象

你可以使用颜色或图像作为绘制背景,并导出你的作品为图像。

示例

你可以在示例标签中查看如何使用该包的例子。

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

展示示例运行的视频录制:

Flutter Painter 视频演示

使用方法

首先,你需要一个 PainterController 对象。PainterController 控制不同的可绘制对象、你正在绘制的背景,并向 FlutterPainter 组件提供所需的设置。然后,在你的UI中,使用带有分配给它的控制器的 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: 这些控制使用的画笔和形状工厂(形状工厂用于创建形状),以及形状是一次性绘制还是连续绘制。
  • 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 对象,你可以使用 ImageProviderimage 扩展获取器(ImageProvider 的示例:FileImageMemoryImageNetworkImage)。此获取器返回 Future<ui.Image>

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

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 构造函数提供一个初始的可绘制对象列表,以初始化控制器。你也可以从控制器修改它们,但要小心,使用 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的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

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


当然,以下是一个关于如何使用 flutter_painter 插件在 Flutter 中实现绘图与涂鸦功能的代码示例。flutter_painter 是一个强大的 Flutter 插件,允许用户进行绘图、涂鸦等操作。

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

dependencies:
  flutter:
    sdk: flutter
  flutter_painter: ^latest_version  # 请替换为最新版本号

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

接下来,下面是一个完整的 Flutter 应用示例,展示了如何使用 flutter_painter 进行绘图和涂鸦:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Painter Demo'),
        ),
        body: Padding(
          padding: const EdgeInsets.all(8.0),
          child: FlutterPainter(
            controller: _PainterController(),
            painter: CustomPainterDelegate(
              paintBuilder: (Canvas canvas, Size size) {
                // 这里可以添加自定义的绘制逻辑,如果需要的话
              },
            ),
            backgroundPainter: BackgroundPainterDelegate(
              color: Colors.white,
            ),
            toolbarOptions: ToolbarOptions(
              drawButtonEnabled: true,
              eraserButtonEnabled: true,
              undoButtonEnabled: true,
              redoButtonEnabled: true,
              clearButtonEnabled: true,
              colorPickerEnabled: true,
              strokeWidthPickerEnabled: true,
            ),
            tool: Tool.pen,
            color: Colors.black,
            strokeWidth: 5.0,
          ),
        ),
      ),
    );
  }
}

class _PainterController extends PainterController {
  @override
  void onClear() {
    // 当用户点击清除按钮时,可以在这里添加自定义逻辑
    super.onClear();
  }

  @override
  void onUndo() {
    // 当用户点击撤销按钮时,可以在这里添加自定义逻辑
    super.onUndo();
  }

  @override
  void onRedo() {
    // 当用户点击重做按钮时,可以在这里添加自定义逻辑
    super.onRedo();
  }
}

在这个示例中:

  1. FlutterPainter 是主要的绘图组件。
  2. _PainterController 是一个自定义的控制器类,继承自 PainterController,你可以在这里重写 onClearonUndoonRedo 方法来处理用户操作。
  3. ToolbarOptions 配置了工具栏的选项,包括画笔、橡皮擦、撤销、重做、清除、颜色选择器和笔触宽度选择器。
  4. Tool.pen 设置默认工具为画笔,你也可以设置为 Tool.eraser 或其他工具。
  5. colorstrokeWidth 分别设置默认颜色和笔触宽度。

这个示例提供了一个基本的绘图和涂鸦功能。你可以根据需求进一步自定义和扩展,比如添加更多的绘制逻辑、保存绘图结果等。

回到顶部