Blog スタッフブログ

Flutter システム開発

[Flutter]手書き対応Widgetのコードスニペット

こんにちは、株式会社MIXシステム開発担当のBloomです。

今回はFlutterで利用できるコードスニペットを紹介します。まずはこちらのクラスを定義しましょう。

import 'package:flutter/material.dart';

class FreeDrawCanvas extends StatefulWidget {
  final Color strokeColor;
  final double strokeWidth;

  const FreeDrawCanvas({
    super.key,
    this.strokeColor = Colors.black,
    this.strokeWidth = 4.0,
  });

  @override
  State<FreeDrawCanvas> createState() => _FreeDrawCanvasState();
}

class _FreeDrawCanvasState extends State<FreeDrawCanvas> {
  final List<Offset?> _points = [];
  final GlobalKey _canvasKey = GlobalKey();

  Offset _getLocalPosition(DragUpdateDetails details) {
    final box = _canvasKey.currentContext?.findRenderObject() as RenderBox;
    return box.globalToLocal(details.globalPosition);
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onPanUpdate: (details) {
        setState(() => _points.add(_getLocalPosition(details)));
      },
      onPanEnd: (_) => setState(() => _points.add(null)),
      child: RepaintBoundary(
        key: _canvasKey,
        child: CustomPaint(
          painter: _FreeDrawPainter(_points, widget.strokeColor, widget.strokeWidth),
          size: Size.infinite,
        ),
      ),
    );
  }
}

class _FreeDrawPainter extends CustomPainter {
  final List<Offset?> points;
  final Color color;
  final double width;

  _FreeDrawPainter(this.points, this.color, this.width);

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = color
      ..strokeWidth = width
      ..strokeCap = StrokeCap.round;

    for (int i = 0; i < points.length - 1; i++) {
      if (points[i] != null && points[i + 1] != null) {
        canvas.drawLine(points[i]!, points[i + 1]!, paint);
      }
    }
  }
  @override
  bool shouldRepaint(_FreeDrawPainter oldDelegate) => true;
}

利用例はこちらのようになります。Widgetとして利用できますが、明確なサイズ指定を与えなければ警告が発生するので注意してください。

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(title: Text("手書き")),
    body: FreeDrawCanvas(
      strokeColor: Colors.blue,
      strokeWidth: 3.0,
    ),
  );
}

これだけでFlutterで手書き機能を実装することができました。良かったですね。