Flutter绘图插件painter的使用

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

Flutter绘图插件painter的使用

painter 是一个简单的Flutter小部件,允许用户用手指绘画。它提供了丰富的功能来满足不同的绘画需求。

功能特性

  • 颜色控制:可以更改前景色和背景色。
  • 线条粗细调整:能够调整所绘制线条的厚度。
  • 导出为PNG:支持将绘制的内容导出为PNG格式图片。
  • 撤销功能:可以撤销上一步的绘制操作。
  • 清除画布:一键清除所有已绘制内容。
  • 检测是否绘制:通过 PainterController.isEmpty 方法检查是否有任何绘制动作。
  • 橡皮擦模式:提供橡皮擦功能以擦除不需要的部分。

注意事项

  • 调用 finish() 方法后,不能继续在同一幅画上进行绘制,若需重新开始则需要创建新的 PainterController 实例。
  • 第一次调用 finish() 会渲染图像,后续再次调用将返回缓存的渲染结果。

示例代码

以下是完整的示例代码,展示了如何在Flutter应用中集成并使用 painter 插件。此示例包括了基本的界面布局、绘画控制器的初始化以及与用户交互的功能实现。

import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
import 'package:painter/painter.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Painter Example',
      home: ExamplePage(),
    );
  }
}

class ExamplePage extends StatefulWidget {
  @override
  _ExamplePageState createState() => _ExamplePageState();
}

class _ExamplePageState extends State<ExamplePage> {
  bool _finished = false;
  PainterController _controller = _newController();

  static PainterController _newController() {
    PainterController controller = PainterController();
    controller.thickness = 5.0;
    controller.backgroundColor = Colors.green;
    return controller;
  }

  void _show(PictureDetails picture, BuildContext context) {
    setState(() {
      _finished = true;
    });
    Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) {
      return Scaffold(
        appBar: AppBar(
          title: Text('View your image'),
        ),
        body: Container(
          alignment: Alignment.center,
          child: FutureBuilder<Uint8List>(
            future: picture.toPNG(),
            builder: (context, snapshot) {
              switch (snapshot.connectionState) {
                case ConnectionState.done:
                  if (snapshot.hasError) {
                    return Text('Error: ${snapshot.error}');
                  } else {
                    return Image.memory(snapshot.data!);
                  }
                default:
                  return CircularProgressIndicator();
              }
            },
          ),
        ),
      );
    }));
  }

  @override
  Widget build(BuildContext context) {
    List<Widget> actions;
    if (_finished) {
      actions = [
        IconButton(
          icon: Icon(Icons.content_copy),
          tooltip: 'New Painting',
          onPressed: () {
            setState(() {
              _finished = false;
              _controller = _newController();
            });
          },
        ),
      ];
    } else {
      actions = [
        IconButton(
          icon: Icon(Icons.undo),
          tooltip: 'Undo',
          onPressed: () {
            if (_controller.isEmpty) {
              showModalBottomSheet(
                context: context,
                builder: (_) => Text('Nothing to undo'),
              );
            } else {
              _controller.undo();
            }
          },
        ),
        IconButton(
          icon: Icon(Icons.delete),
          tooltip: 'Clear',
          onPressed: _controller.clear,
        ),
        IconButton(
          icon: Icon(Icons.check),
          onPressed: () => _show(_controller.finish(), context),
        ),
      ];
    }
    return Scaffold(
      appBar: AppBar(
        title: Text('Painter Example'),
        actions: actions,
        bottom: PreferredSize(
          child: DrawBar(_controller),
          preferredSize: Size(MediaQuery.of(context).size.width, 30.0),
        ),
      ),
      body: Center(
        child: AspectRatio(
          aspectRatio: 1.0,
          child: Painter(_controller),
        ),
      ),
    );
  }
}

class DrawBar extends StatelessWidget {
  final PainterController _controller;

  DrawBar(this._controller);

  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Flexible(
          child: StatefulBuilder(
            builder: (context, setState) {
              return Container(
                child: Slider(
                  value: _controller.thickness,
                  onChanged: (value) => setState(() {
                    _controller.thickness = value;
                  }),
                  min: 1.0,
                  max: 20.0,
                  activeColor: Colors.white,
                ),
              );
            },
          ),
        ),
        StatefulBuilder(
          builder: (context, setState) {
            return RotatedBox(
              quarterTurns: _controller.eraseMode ? 2 : 0,
              child: IconButton(
                icon: Icon(Icons.create),
                tooltip: (_controller.eraseMode ? 'Disable' : 'Enable') + ' eraser',
                onPressed: () {
                  setState(() {
                    _controller.eraseMode = !_controller.eraseMode;
                  });
                },
              ),
            );
          },
        ),
        ColorPickerButton(_controller, false),
        ColorPickerButton(_controller, true),
      ],
    );
  }
}

class ColorPickerButton extends StatefulWidget {
  final PainterController _controller;
  final bool _background;

  ColorPickerButton(this._controller, this._background);

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

class _ColorPickerButtonState extends State<ColorPickerButton> {
  @override
  Widget build(BuildContext context) {
    return IconButton(
      icon: Icon(widget._background ? Icons.format_color_fill : Icons.brush, color: _color),
      tooltip: widget._background ? 'Change background color' : 'Change draw color',
      onPressed: _pickColor,
    );
  }

  void _pickColor() async {
    Color pickerColor = _color;
    await Navigator.of(context).push(MaterialPageRoute(
      fullscreenDialog: true,
      builder: (context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text('Pick color'),
          ),
          body: Container(
            alignment: Alignment.center,
            child: ColorPicker(
              pickerColor: pickerColor,
              onColorChanged: (Color c) => pickerColor = c,
            ),
          ),
        );
      },
    ));
    setState(() {
      _color = pickerColor;
    });
  }

  Color get _color => widget._background ? widget._controller.backgroundColor : widget._controller.drawColor;

  set _color(Color color) {
    if (widget._background) {
      widget._controller.backgroundColor = color;
    } else {
      widget._controller.drawColor = color;
    }
  }
}

以上就是关于 painter 插件的基本介绍及其在Flutter中的具体应用方法。希望这些信息对你有所帮助!如果你有任何疑问或需要进一步的帮助,请随时提问。


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

1 回复

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


在Flutter中,CustomPainter 是一个强大的工具,允许你直接在Canvas上进行绘图。下面是一个使用 CustomPainter 的基本示例,展示如何在Flutter应用中进行绘图。

首先,你需要创建一个继承自 CustomPainter 的类,并实现 paint 方法和 shouldRepaint 方法。paint 方法用于定义绘图的逻辑,而 shouldRepaint 方法用于确定何时应该重绘。

1. 创建自定义Painter类

import 'package:flutter/material.dart';

class MyCustomPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    // 创建一个Paint对象,用于定义绘图的样式
    final Paint paint = Paint()
      ..color = Colors.blue
      ..strokeWidth = 4.0
      ..style = PaintingStyle.stroke;

    // 绘制一个矩形
    final Rect rect = Rect.fromLTWH(50, 50, 100, 100);
    canvas.drawRect(rect, paint);

    // 绘制一个圆形
    final center = Offset(size.width / 2, size.height / 2);
    final radius = 50.0;
    canvas.drawCircle(center, radius, paint);

    // 绘制一条线
    final Paint linePaint = Paint()
      ..color = Colors.red
      ..strokeWidth = 2.0;
    canvas.drawLine(Offset(0, 0), Offset(size.width, size.height), linePaint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    // 在这里返回true或false,取决于是否需要重绘
    // 如果你的Painter对象的状态没有改变,返回false以提高性能
    return false;
  }
}

2. 在Widget中使用CustomPainter

然后,你可以在你的Widget中使用这个自定义Painter。通常,你会在一个 CustomPaint widget中这样做。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter CustomPainter Example'),
        ),
        body: Center(
          child: CustomPaint(
            size: Size(300, 300), // 设置绘图区域的大小
            painter: MyCustomPainter(),
          ),
        ),
      ),
    );
  }
}

3. 运行应用

将上述代码放入你的Flutter项目中并运行。你应该会看到一个带有蓝色矩形、圆形和红色对角线的屏幕。

注意事项

  • shouldRepaint 方法默认返回 false,这意味着除非明确告知,否则Flutter不会重绘。如果你需要基于某些状态变化来重绘,你可以在这里添加逻辑。
  • CustomPaintsize 属性定义了绘图的区域大小。你可以根据需要调整它。
  • Paint 对象提供了许多配置选项,如颜色、线条宽度、样式等,你可以根据需要调整这些属性。

通过这种方式,你可以在Flutter中实现复杂的绘图需求。

回到顶部