【Flutter】TextPainterでText Widgetのサイズを取得し、AnimatedContainerでアニメーションをつけたUIを実装する

エキサイト株式会社の武藤です。

FlutterでViewを構築するときに、Text Widgetのサイズが欲しいときがあります。今回は、Text WidgetのWidth、Heightの取得について紹介します。 また、求めたサイズを使ってアニメーションをつけたUIのサンプルを紹介します。

TextPainterクラスを使ったText Widgetのサイズ取得

TextPainterクラスを使用して、Text Widgetのサイズを取得します。

TextPainterクラスは、CanvasにTextSpanを描画して、そのオブジェクトからサイズや行数等のText Widgetに関する情報を取得できます。

TextPainter class - painting library - Dart API

下記は、TextのSizeインスタンスを取得するメソッドです。 引数には、表示するテキスト、フォントサイズ等のTextStyle、描画エリアの幅を指定します。

Size _textSize({
  required String text,
  required TextStyle textStyle,
  required double maxWidth,
}) {
  final TextPainter textPainter = TextPainter(
    text: TextSpan(
      text: text,
      style: textStyle,
    ),
    textAlign: TextAlign.start,
    textDirection: TextDirection.ltr,
  )..layout(
      minWidth: 0,
      maxWidth: maxWidth,
    );
  return textPainter.size;
}

メソッドの呼び出し例です。ここでは描画幅を画面サイズいっぱいとしています。 取得したSizeから、Height、Widthを取得できます。

const sampleText = "テキストテキストテキストテキストテキストテキスト";
const sampleTextStyle = TextStyle(fontSize: 24);
final maxWidth = MediaQuery.of(context).size.width;

final textSize = _textSize(
  text: sampleText,
  textStyle: sampleTextStyle,
  maxWidth: maxWidth,
);
final height = textSize.height;
final width = textSize.width;

AnimatedContainerでアニメーションUIを作る

Text Widgetのサイズを求められました。 次に、AnimatedContainerと組み合わせて、アニメーションをつけたUIを実現してみます。 今回は、SnackBarの閉じるアニメーションを自作してみます。

api.flutter.dev

class _MyHomePageState extends State<MyHomePage> {
  bool _isTapped = false;

  void _switchIsTapped() {
    setState(() {
      _isTapped = !_isTapped;
    });
  }

  @override
  Widget build(BuildContext context) {
    const sampleText = "テキストテキストテキストテキストテキストテキスト";
    const sampleTextStyle = TextStyle(fontSize: 24);
    final maxWidth = MediaQuery.of(context).size.width;

    final textSize = _textSize(
      text: sampleText,
      textStyle: sampleTextStyle,
      maxWidth: maxWidth,
    );

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Align(
        alignment: Alignment.bottomLeft,
        child: AnimatedContainer(
          duration: const Duration(milliseconds: 200),
          height: _isTapped ? 0 : textSize.height,
          child: GestureDetector(
            onTap: () {
              _switchIsTapped();
            },
            child: ColoredBox(
              color: Colors.black,
              child: Text(
                sampleText,
                style: sampleTextStyle.copyWith(color: Colors.white),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

自作したSnackBarの閉じるUI

終わりに

今回は、TextPainterを使ったText Widgetのサイズ取得と、AnimatedContainerを使ったアニメーションがあるUIを紹介しました。 TextWidgetにPaddingをつけている場合は、Padding分の高さを加味して扱う必要があるので注意です。

どなたかの助けになれば幸いです。

採用情報

エキサイトではフロントエンジニア、バックエンドエンジニア、アプリエンジニアを随時募集しております。長期インターンも歓迎していますので、興味があれば連絡いただければと思います。

www.wantedly.com

参考

stackoverflow.com