【Flutter】吹き出しを作る【ShapeDecoration Bubble ボーター】

もくじ

こんにちは。

スマホアプリをメインに開発しているロッキーカナイです。

今回は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

関連する記事

もっと見る