はじめに
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を用意したサンプルになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 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の中心に線を引きたいというときには以下のようにします。
1 2 3 4 5 6 7 8 9 10 11 12 | 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のサイズではありません、なので
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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を呼び出します。
1 2 3 4 5 6 7 8 | 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に色を指定し、円の中心位置と半径を指定します。
1 2 3 4 5 6 7 8 | 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を指定することで円を塗りつぶさずに表示することもできます。
1 2 3 4 5 6 7 8 9 10 11 | 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はパスを指定して図形を描画します。四角や円以外の図形を描画したい際に使用します。今回は三角を描画します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 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に指定することで塗りつぶしも行えます。
1 2 3 4 | final paint = Paint() ..color = Colors.green ..style = PaintingStyle.fill ..strokeWidth = 6; |
さいごに
Flutterには標準のWidgetや便利なパッケージもありますが、こうゆうことも自前でできるという選択肢があり、自由度が高くとても良いと思います。