flutter手写板2.0 橡皮擦

Posted 刘文_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了flutter手写板2.0 橡皮擦相关的知识,希望对你有一定的参考价值。

在实现手写的基础上 增加橡皮擦功能
详情见代码

import 'dart:ui';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'dart:ui' as UI;

class HandWrittenBoard extends StatefulWidget {
  ///手写笔颜色
  final Color? painColor;

  ///手写笔宽度
  final double? paintWidth;

  ///橡皮
  final double? clearWidth;

  final double? clearDx;

  final double? clearDy;

  ///手写笔控制器
  final HandWrittenBoardController boardController;

  const HandWrittenBoard(
      {Key? key,
      this.painColor,
      this.clearWidth,
      this.paintWidth,
      required this.boardController,
      this.clearDx,
      this.clearDy})
      : super(key: key);

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

class HandWrittenBoardController extends ChangeNotifier {
  late BuildContext _context;
  late List<Stroke?> strokes = [];

  void bindContext(BuildContext context) {
    _context = context;
  }

  Future<UI.Image>? get uiImage {
    UI.PictureRecorder recorder = UI.PictureRecorder();
    Canvas canvas = Canvas(recorder);
    BoardPainter painter = BoardPainter();
    Size size = _context.size!;
    painter.paint(canvas, size);
    return recorder
        .endRecording()
        .toImage(size.width.floor(), size.height.floor());
  }

  void refStrokes(List<Stroke> newValue) {
    if (strokes != newValue) {
      strokes = newValue;
    }
    notifyListeners();
  }

  void clearBoard() {
    strokes.clear();
    notifyListeners();
  }
}

class _HandWrittenBoardState extends State<HandWrittenBoard> {
  List<Stroke> _strokes = [];

  @override
  void initState() {
    super.initState();
    widget.boardController.bindContext(context);
  }

  void _onUpdate(DragUpdateDetails details) {
    if (isClear) {
      dx = details.localPosition.dx;
      dy = details.localPosition.dy;
    }
    setState(() {
      _strokes.last.path
          .lineTo(details.localPosition.dx, details.localPosition.dy);
    });
    widget.boardController.refStrokes(_strokes);
  }

  void _start(double startX, double startY) {
    if (isClear) {
      dx = startX;
      dy = startY;
    }

    final newStroke = Stroke(
      color: widget.painColor!,
      width: widget.paintWidth!,
      isClear: isClear,
    );
    newStroke.path.moveTo(startX, startY);
    _strokes.add(newStroke);
    widget.boardController.refStrokes(_strokes);
  }

  late double dx = widget.clearDx! + widget.clearWidth! / 2;
  late double dy = widget.clearDy! - widget.clearWidth! / 2;

  bool isClear = false;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onPanUpdate: _onUpdate,
      onPanStart: (details) => _start(
        details.localPosition.dx,
        details.localPosition.dy,
      ),
      onPanDown: (detail) {
        Rect rect =
            Rect.fromCenter(center: Offset(dx, dy), width: 50, height: 50);
        isClear = rect.contains(detail.localPosition);
      },
      child: Stack(
        children: [
          CustomPaint(
            painter: BoardPainter(
              strokes: _strokes,
              clearWidth: widget.clearWidth,
            ),
            size: Size.infinite,
          ),
          Positioned(
            child: Container(
              width: widget.clearWidth,
              height: widget.clearWidth,
              color: Colors.red,
            ),
            left: dx - widget.clearWidth! / 2,
            top: dy - widget.clearWidth! / 2,
          ),
        ],
      ),
    );
  }
}

class Stroke {
  final path = Path();
  final Color color;
  final double width;
  final bool isClear;

  Stroke({
    this.color = Colors.black,
    this.width = 4,
    this.isClear = false,
  });
}

class BoardPainter extends CustomPainter {
  BoardPainter({
    this.strokes,
    this.clearWidth,
  });

  final List<Stroke>? strokes;
  final double? clearWidth;

  @override
  void paint(Canvas canvas, Size size) {
    canvas.clipRect(Rect.fromLTWH(0, 0, size.width, size.height));

    canvas.drawRect(
      Rect.fromLTWH(0, 0, size.width, size.height),
      Paint()..color = Colors.white,
    );
    canvas.saveLayer(Rect.fromLTWH(0, 0, size.width, size.height), Paint());
    for (final stroke in strokes!) {
      final paint = Paint()
        ..strokeWidth = stroke.isClear ? clearWidth! : stroke.width
        ..color = stroke.isClear ? Colors.transparent : stroke.color
        ..strokeCap = StrokeCap.round
        ..style = PaintingStyle.stroke
        ..blendMode = stroke.isClear ? BlendMode.clear : BlendMode.srcOver;
      canvas.drawPath(stroke.path, paint);
    }
    canvas.restore();
  }

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

使用示范

import 'package:flitter_okgo/hand_written_board.dart';
import 'package:flutter/material.dart';

class HandWrittenBoardPage extends StatefulWidget {
  @override
  _TestPageState createState() => _TestPageState();
}

class _TestPageState extends State<HandWrittenBoardPage> {
  HandWrittenBoardController controller = HandWrittenBoardController();

  @override
  void initState() {
    super.initState();
  }

  Widget get initFloatingActionButton {
    return FloatingActionButton(
      backgroundColor: Colors.grey,
      elevation: 1,
      focusElevation: 1,
      onPressed: () {
        controller.clearBoard();
      },
      child: Icon(Icons.clear),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: initFloatingActionButton,
      floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
      appBar: AppBar(
        title: Text("橡皮擦"),
      ),
      body: HandWrittenBoard(
        boardController: controller,
        clearWidth: 50,
        paintWidth: 5,
        painColor: Colors.green,
        clearDx: 0,
        clearDy: 200,
      ),
    );
  }
}

以上是关于flutter手写板2.0 橡皮擦的主要内容,如果未能解决你的问题,请参考以下文章

前端面试题之手写promise

错误记录Flutter 混合开发获取 BinaryMessenger 报错 ( FlutterActivityAndFragmentDelegate.getFlutterEngine() )(代码片段

如何在 Flutter 的原生 C++ 中使用 OpenCV 4(2021 年)(支持 Flutter 2.0)? [关闭]

XD to Flutter 2.0 现已发布!

在 webview_flutter 中启用捏合和缩放,在哪里添加代码片段 [this.webView.getSettings().setBuiltInZoomControls(true);]

XD to Flutter 2.0 现已发布!