手绘板的制作——重置与橡皮擦(2)

·  阅读 150

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第17天,点击查看活动详情

前言

在上一篇文章「手绘板的制作——手绘(1) 」中,我们完成了手绘的功能,这一篇我们在其基础上来讲讲重置与橡皮擦的功能实现。

在讲具体的功能实现前,我们需要先弄几个文本,用于笔刷、重置、橡皮擦的功能切换,同时把手绘板的功能抽取出来,放到 HandPaintedBoard 类中,大致代码如下,由于大多都是 UI 代码,可以直接初略看看即可,若需要自己实践再进行 copy。

void main() {
  runApp(const MyHomePage());
}

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

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final PaintedBoardProvider _paintedBoardProvider = PaintedBoardProvider();   // <- 重点在这里

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Container(
          color: Colors.white,
          child: SafeArea(
            child: Flex(
              direction: Axis.vertical,
              children: [
                SizedBox(
                  height: 100,
                  child: Flex(
                    direction: Axis.horizontal,
                    children: [
                      Expanded(
                        child: GestureDetector(
                          onTap: () {
                            print("点击了笔刷");
                          },
                          child: const Center(
                            child: Text("笔刷"),
                          ),
                        ),
                      ),
                      Expanded(
                        child: GestureDetector(
                          onTap: () {
                            print("点击了重置");
                          },
                          child: const Center(
                            child: Text("重置"),
                          ),
                        ),
                      ),
                      Expanded(
                        child: GestureDetector(
                          onTap: () {
                            print("点击了橡皮擦");
                          },
                          child: const Center(
                            child: Text("橡皮擦"),
                          ),
                        ),
                      ),
                    ],
                  ),
                ),
                Expanded(child: HandPaintedBoard(_paintedBoardProvider)),  // <- 重点在这里
              ],
            ),
          ),
        ),
      ),
    );
  }
}
复制代码
class HandPaintedBoard extends StatefulWidget {
  const HandPaintedBoard(
    this._paintedBoardProvider, {
    Key? key,
  }) : super(key: key);
  final PaintedBoardProvider _paintedBoardProvider;

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

class _HandPaintedBoardState extends State<HandPaintedBoard> {
  PaintedBoardProvider get _paintedBoardProvider =>
      widget._paintedBoardProvider;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onPanStart: (details) {
        _paintedBoardProvider.onStart(details);
      },
      onPanUpdate: (details) {
        _paintedBoardProvider.onUpdate(details);
      },
      onPanEnd: (details) {
        print("onPanDown:移动结束");
      },
      child: CustomPaint(
        painter: MyPainter(_paintedBoardProvider),
        size: Size.infinite,
      ),
    );
  }
}
复制代码

至于 stroke.dartpainted_board_provider.dartmy_painter.dart「手绘板的制作——手绘(1) 」中都有,这里就不贴出了。

UI 效果:

橡皮擦1.png

然后我们点击三个按钮试试:

I/flutter: 点击了笔刷
I/flutter: 点击了重置
I/flutter: 点击了橡皮擦
复制代码

准备工作完成,正文开始!

重置

重置功能其实就是将当前绘画的内容全部清空,而我们用于存储绘画数据的为 PaintedBoardProvider 中的 List<Stroke> _strokes,所以,我们只要将其清空,然后刷下页面即可。

PaintedBoardProvider 中添加以下方法:

  void clearBoard() {
    _strokes.clear();
    notifyListeners();
  }
复制代码

然后在点击的地方调用:

                      Expanded(
                        child: GestureDetector(
                          onTap: () {
                            print("点击了重置");
                            _paintedBoardProvider.clearBoard();
                          },
                          child: const Center(
                            child: Text("重置"),
                          ),
                        ),
复制代码

ok,功能完成,就是这么简单,下一个。

橡皮擦

关于橡皮擦功能的实现,目前有两种方式:

  • 假清除效果,也就是把画笔颜色改为白色,或者说改为跟画布同一个颜色,然后这样绘画的时候,就会将原有的画笔绘画效果覆盖住,造成一种清除效果的假象。所以这里不建议这样使用,有兴趣的可以自己实现下。
  • 真清除效果,也就是把画笔颜色改为透明,然后用画笔进行绘画的时候,当画笔绘画的内容产生交接时,将其 blendMode 改为 clear,就可以把交接处直接清除。

下面我们来讲讲真清除效果。

    // 获取绘画数据进行绘画
    for (final stroke in paintedBoardProvider.strokes) {
      final paint = Paint()
        ..strokeWidth = stroke.width
        ..color = stroke.color
        ..strokeCap = StrokeCap.round
        ..style = PaintingStyle.stroke
        ..blendMode = stroke.isClear ? BlendMode.clear : BlendMode.src;  //  <-  新增
      canvas.drawPath(stroke.path, paint);
    }
复制代码

看看效果:

橡皮擦2.png

em...怎么变成黑色了?虽然说我们是直接在画布上绘画,即使是把背景清除了,也不应该是黑色,因为我也尝试过使用橙色背景的 Container 包裹住 CustomPaint,但是画出的颜色还是黑色。对此了解的大佬麻烦解答下。

至于解决办法我倒是了解,也就是使用 saveLayer。相当于我们在使用 Photoshop 的时候,新建一个透明蒙层,在新的蒙层上进行绘画,等绘画完成后,我们可以调用 restore 将该蒙层贴回画布中,重新在画布上进行绘制。大致的代码如下:

    canvas.saveLayer(Rect.fromLTWH(0, 0, size.width, size.height), Paint());
    // 获取绘画数据进行绘画
    for (final stroke in paintedBoardProvider.strokes) {
      final paint = Paint()
        ..strokeWidth = stroke.width
        ..color = stroke.color
        ..strokeCap = StrokeCap.round
        ..style = PaintingStyle.stroke
        ..blendMode = stroke.isClear ? BlendMode.clear : BlendMode.src;  //  <-  新增
      canvas.drawPath(stroke.path, paint);
    }
    canvas.restore();
复制代码

效果:

橡皮擦3.png

分类:
Android
标签:
收藏成功!
已添加到「」, 点击更改