FlutterのCustomPaintで図形を描いて遊ぶ

3 min read読了の目安(約3400字

はじめに

Flutterでアプリを作っていると、独自な描画をしたくなることがあります。
こうした時は、CustomPaintを使うと、自由に図形を描画することができます。

CustomPaintは次の手順で簡単に使うことができます。

  1. CustomPaintをウィジェットツリーに追加
  2. CustomPaintsizepainterを与える
  3. painterを実装(CustomPainterを拡張して作る)
  4. CustomPainterpaint()shouldRepaint()を実装する

paint()では次のような関数を使い、canvas上に自由に描画できます。

  • 線を描画するdrawLine()
  • 長方形を描画するdrawRect()
  • 円を描画するdrawCircle()
  • アーチを描画するdrawArc()
  • パスを描画するdrawPath()
  • ビットマップ画像を描画するdrawImage()
  • テキストを描画するdrawParagraph()

ここでは実際にいくつかCustomPaintを使って図形を書いてみます。

次のコードでシンプルな円を描くことができます。

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

class PaintTestPage extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: CustomPaint(
          size: const Size(100, 100),
          painter: CirclePaint(),
        ),
      ),
    );
  }
}
class CirclePaint extends CustomPainter {
  
  void paint(Canvas canvas, Size size) {
    print('Size(${size.width},${size.height})');// Size(100,100)
    final paint = Paint()..color = Colors.red;
    final center = Offset(size.width / 2, size.height / 2);
    final radius = min(size.width, size.height);
    canvas.drawCircle(center, radius, paint);
  }

  // 再描画する必要なし
  
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return false;
  }
}


paint()stylePaintingStyle.strokeを指定すれば、次のように塗りつぶしでなく、線を引くことができます。

...
final paint = Paint()
      ..color = Colors.red
      ..style = PaintingStyle.stroke
      ..strokeCap = StrokeCap.round
      ..strokeWidth = 12;
...

三角形

次は正三角形を書いてみましょう。
次のように、drawPath()を使うことで、与えたパスに対し描画を行うことができます。

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

class PaintTestPage extends StatelessWidget {

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: CustomPaint(
          size: const Size(100, 100),
          painter: TriPaint(),
        ),
      ),
    );
  }
}

class TriPaint extends CustomPainter {
  
  void paint(Canvas canvas, Size size) {
    final path = Path()
      ..moveTo(
        0,
        size.height,
      )
      ..lineTo(
        size.width / 2,
        size.height - size.width / 2 * sqrt(3),
      )
      ..lineTo(
        size.width,
        size.height,
      )
      ..lineTo(
        0,
        size.height,
      );

    final paint = Paint()
      ..color = Colors.blue
      ..style = PaintingStyle.stroke
      ..strokeWidth = 2;

    canvas.drawPath(path, paint);
  }

  
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return false;
  }
}

参考文献

CustomPaint class - widgets library - Dart API
Paths in Flutter: A Visual Guide. Flutter gives us a lot of standard… | by Muhammed Salih Guler | Flutter Community | Medium
How to Paint in Flutter. A simple guide for learning to use the… | by Suragch | Medium