見出し画像

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を使うと円のボーダーを引いてくれます。

スクリーンショット 2020-05-09 17.45.37

    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を返すことでふきだしを実現できます。ふきだしの向きは下向きで真ん中に配置しました。今回は省略しますが、向きが何パターンか必要なら、プロパティで指定できるようにするといいですね。

スクリーンショット 2020-05-09 17.38.01

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;
}


この記事が気に入ったらサポートをしてみませんか?