もくじ
こんにちは。
スマホアプリをメインに開発しているロッキーカナイです。
今回は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を組む必要があります。
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;
}
使う際は、こちらの感じで。
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