カテゴリー: Tech

[Flutter] CustomPaintという選択肢

はじめに

Flutterで用意されているWidgetや、パッケージを探してみても望む表現ができない場合は、
CustomPaintという選択肢が出てきます。iOSやAndroidなどでもグラフや複雑な図形を描画するのにCanvasをなどを用いて低レベルなAPIを使ったグラフィック操作を使用しますが、今回はFlutterでやってみます。

CustomPaint

CustomPaintを用いて、できることは以下になります。

  • drawLine(線を描画)
  • drawRect(四角形を描画)
  • drawCircle(円を描画)
  • drawArc(アーチを描画)
  • drawPath(パスを用いて図形を描画)
  • drawImage(ビットマップ画像を描画)
  • drawParagraph(テキストを描画)

今回の記事では、drawLine、drawRect、drawCircle、drawPathを使ってみたいと思います。

drawLine

CustomPaintのCustomPainterにてグラフィック操作を行います。Paintのcolorにて色、strokeWidthで枠線の太さを選択します。Paintの指定を行なったらcanvas.drawLineで線を描画してみます。今回は400×400のcanvasを用意したサンプルになります。

class _Body extends StatelessWidget {
  _Body();

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.only(top: 100, left: 50),
      width: 400,
      height: 400,
      child: CustomPaint(
        painter: _SamplePainter(),
      ),
    );
  }
}

class _SamplePainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()..color = Colors.blue;
    paint.strokeWidth = 5;
    canvas.drawLine(Offset(10, 10), Offset(10, 60), paint);
    paint.color = Colors.grey;
    paint.strokeWidth = 10;
    canvas.drawLine(Offset(30, 10), Offset(30, 60), paint);
  }

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

上記を実行すると以下のような線が表示されます。

例えばcanvasの中心に線を引きたいというときには以下のようにします。

class _SamplePainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = Colors.blue
      ..strokeWidth = 14;

    canvas.drawLine(
        Offset(size.width / 2, 0), Offset(size.width / 2, size.height), paint);
    canvas.drawLine(
        Offset(0, size.height / 2), Offset(size.width, size.height / 2), paint);
  }

中心はpaintメソッドの引数のsizeから求めることができます。あくまでもcanvasのサイズであり、端末やwindowのサイズではありません、なので

class _Body extends StatelessWidget {
  _Body();

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.only(top: 100, left: 50),
      width: 400,
      height: 400,
      child: CustomPaint(
        painter: _SamplePainter(),
      ),
    );
  }
}

400×400でpaddingのtopを100、leftを50とすると、以下のような形で表示されます。

drawRect

drawRectは四角形を描画します。drawLineと同じくPaintに色を指定しcanvas.drawRectを呼び出します。

class _SamplePainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()..color = Colors.blue;
    canvas.drawRect(Rect.fromLTWH(0, 0, 50, 50), paint);
    paint.color = Colors.yellow;
    canvas.drawRect(Rect.fromLTWH(60, 0, 100, 100), paint);
  }

上記を実行すると以下のような四角形が表示されます。

drawCircle

drawCircleは円を描画します、これまで同様にPaintに色を指定し、円の中心位置と半径を指定します。

class _SamplePainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()..color = Colors.red;
    final center = Offset(size.width / 2, size.height / 2);
    final radius = size.width / 2;
    canvas.drawCircle(center, radius, paint);
  }

上記を実行すると以下のような円が表示されます。

Paintのstyleを指定することで円を塗りつぶさずに表示することもできます。

class _SamplePainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = Colors.red
      ..style = PaintingStyle.stroke// 塗りつぶしなし
      ..strokeWidth = 12;// 枠線の太さを指定
    final center = Offset(size.width / 2, size.height / 2);
    final radius = size.width / 2;
    canvas.drawCircle(center, radius, paint);
  }

drawPath

drawPathはパスを指定して図形を描画します。四角や円以外の図形を描画したい際に使用します。今回は三角を描画します。

class _SamplePainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final path = Path()
      ..moveTo(
        0,
        size.height,
      )
      ..lineTo(
        size.width / 2,
        0,
      )
      ..lineTo(
        size.width,
        size.height,
      )
      ..lineTo(
        0,
        size.height,
      );

    final paint = Paint()
      ..color = Colors.green
      ..style = PaintingStyle.stroke
      ..strokeWidth = 6;

    canvas.drawPath(path, paint);
  }

まずは図形を描画するためのPathを作成します。moveToで始点を設定し、lineToで指定した座標へ向かって線を引きます。この際Pathの座標は指定された座標へと移動しているので、lineToを繰り返してPathを作成していきます。上記を実行すると以下のように三角が表示されます。

styleをfillに指定することで塗りつぶしも行えます。

    final paint = Paint()
      ..color = Colors.green
      ..style = PaintingStyle.fill
      ..strokeWidth = 6;

さいごに

Flutterには標準のWidgetや便利なパッケージもありますが、こうゆうことも自前でできるという選択肢があり、自由度が高くとても良いと思います。

おすすめ書籍

nukky

シェア
執筆者:
nukky
タグ: Flutter

最近の投稿

フロントエンドで動画デコレーション&レンダリング

はじめに 今回は、以下のように…

2週間 前

Goのクエリビルダー goqu を使ってみる

はじめに 最近携わっているとあ…

4週間 前

【Xcode15】プライバシーマニフェスト対応に備えて

はじめに こんにちは、suzu…

2か月 前

FSMを使った状態管理をGoで実装する

はじめに 一般的なアプリケーシ…

3か月 前