こんにちは。
スマホアプリをメインに開発しているロッキーカナイです。
今回はFlutterで外枠ボーダーのふきだしのWidgetを作る必要がありましたので、調べた事や関連する情報、作ったものを紹介します。
Flutterで吹き出しを使う
手っ取り早く吹き出しを使いたい場合は、こちらのbubbleというライブラリがおすすめです。評価も高く、パラメータも豊富なのでカスタム性もありそうです。
ただ、ボーダーの吹き出しはできなそうなので、自作する事にします。
Flutterで吹き出しを作る上での参考サイト
こちらのContainerでふきだしを作成する方法に概要がありました。
Containerのdecorationプロパティでボーダーラインを描画する
なるほど。
ContainerのdecorationにShapeDecorationを指定し、自作のShapeBorderを設定で実装できそうという事が分かりました。
ふきだしの形を作るのは、ShapeBorderのgetOuterPath()メソッド内のPathになります。
ただ、ボーダーの吹き出しに関しては書かれてませんでした。(こちらの記事では塗り潰し前提のふきだしで、角丸パーツとふきだしパーツを組み合わせているのでボーダーにすると2つのパーツが枠線されます。)
もう一点、
こちらのFlutterで始めるアプリ開発/Flight BookingでPathやShapeBorderに関して、とても参考になりましたので紹介させて頂きます。
Flutterでボーダー吹き出しを作る
まず、ShapeBorderを継承したクラスを作ります。
getOuterPath()で、吹き出しのPathを作ります。ボーダーで表現する為に一筆書きの様にPathを組む必要があります。
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
class BubbleBorder extends ShapeBorder { BubbleBorder({ @required this.width, @required this.radius, }); final double width; final double radius; @override EdgeInsetsGeometry get dimensions { return EdgeInsets.all(width); } @override Path getInnerPath(Rect rect, {TextDirection textDirection}) { return getOuterPath( rect.deflate(width / 2.0), textDirection: textDirection, ); } @override Path getOuterPath(Rect rect, {TextDirection textDirection}) { final r = radius; final rs = radius / 2; final w = rect.size.width; final h = rect.size.height; return Path() ..addPath( Path() ..moveTo(r, 0) ..lineTo(w - r, 0) ..arcToPoint(Offset(w, r), radius: Radius.circular(r)) ..lineTo(w, h - rs) ..arcToPoint(Offset(w - r, h), radius: Radius.circular(r)) ..lineTo(r, h) ..arcToPoint(Offset(0, h - r), radius: Radius.circular(r)) ..lineTo(0, h / 2) ..relativeLineTo(-12, -12) ..lineTo(0, h / 2 - 10) ..lineTo(0, r) ..arcToPoint(Offset(r, 0), radius: Radius.circular(r)), Offset(rect.left, rect.top), ); } @override void paint(Canvas canvas, Rect rect, {TextDirection textDirection}) { final paint = Paint() ..style = PaintingStyle.stroke ..strokeWidth = 1 ..color = Colors.black; canvas.drawPath( getOuterPath( rect.deflate(width / 2.0), textDirection: textDirection, ), paint, ); } @override ShapeBorder scale(double t) => this; } |
使う際は、こちらの感じで。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
Container( margin: const EdgeInsets.only(left: 15.0), padding: const EdgeInsets.symmetric( vertical: 5.0, horizontal: 10.0, ), child: const Text("そう。あれは強い雨が振り、辺りは轟音の渦となりはてていた。" "堕天使ルシファーの称号を手にした俺は、天空の城に囚われているゆきぽよを助ける為、" "精神と時の部屋と呼んでいる賃貸アパートの四畳半で..."), decoration: ShapeDecoration( color: Colors.white, shape: BubbleBorder( width: 1, radius: 10, ), ), ), |

このコードを使う場合は、必ずこのテキストを使ってくださいw
うそですw
