
Photo by
mupyyyyy
Containerでふきだしを作成する方法
HTMLの場合はCSSだけでふきだしを作成できるのですが、Flutterではどうやるのでしょうか。そのままの名前でBubbleというOSSがあり、様々な形のふきだしを作成できるようです。これでOKなら良かったのですが、デザイナーが指定する形と合わないので自作することにします。
ShapeDecorationを使う
Containerのdecorationプロパティでボーダーラインを描画するので、これを使えばふきだしのボーダーラインを実現できそうです。ふきだしの中身はContainerのchildにTextなどを書いていく感じです。
ContainerのdecorationプロパティにShapeDecorationクラスを渡します。
ShapeDecorationクラスはcolorやshadowプロパティがあるので、ふきだしの色やシャドウはこれでOKです。ShapeDecorationのshapeプロパティはShapeBorderクラスですが、試しにShapeBorderクラスを継承したCircleBorderを使うと円のボーダーを引いてくれます。
Container(
height: 100,
padding: EdgeInsets.all(16),
decoration: ShapeDecoration(
color: Colors.green[200],
shadows: [
const BoxShadow(
color: Color(0x80000000),
offset: Offset(0, 2),
blurRadius: 2,
)
],
shape: CircleBorder(),
),
child: ...
BubbleBorderを作る
ではShapeBorderクラスを継承したBubbleBorderクラスを自作して、ふきだしの形のボーダーを作ります。ShapeBorderクラスのgetOuterPath()でふきだしの形のPathを返すことでふきだしを実現できます。ふきだしの向きは下向きで真ん中に配置しました。今回は省略しますが、向きが何パターンか必要なら、プロパティで指定できるようにするといいですね。
class BubbleBorder extends ShapeBorder {
final bool usePadding;
const BubbleBorder({this.usePadding = true});
@override
EdgeInsetsGeometry get dimensions =>
EdgeInsets.only(bottom: usePadding ? 12 : 0);
@override
Path getInnerPath(Rect rect, {TextDirection textDirection}) => null;
@override
Path getOuterPath(Rect rect, {TextDirection textDirection}) {
final r =
Rect.fromPoints(rect.topLeft, rect.bottomRight - const Offset(0, 12));
return Path()
..addRRect(RRect.fromRectAndRadius(r, Radius.circular(8)))
..moveTo(r.bottomCenter.dx - 10, r.bottomCenter.dy)
..relativeLineTo(10, 12)
..relativeLineTo(10, -12)
..close();
}
@override
void paint(Canvas canvas, Rect rect, {TextDirection textDirection}) {}
@override
ShapeBorder scale(double t) => this;
}