KAKEHASHI Tech Blog

カケハシのEngineer Teamによるブログです。

Flutterで全画面表示を実現する

この記事はカケハシ Advent Calendar 2023 の 13日目の記事になります。

今年はPart2もあるのでぜひそちらもご覧ください!

はじめに

こんにちは!KAKEHASHIでおくすり連絡帳 Pocket Musubi というサービスを開発している星川です。チーム内では主にFlutterを利用したスマートフォンアプリ開発を担当しています。

このおくすり連絡帳アプリには、薬剤師と患者さんがオンラインでやり取りする、オンライン服薬指導という機能があり、患者さんはスマートフォンで薬剤師とビデオ通話を行うことが可能になっています。

このようなビデオ通話や画像などのコンテンツを扱う場合は、アプリの没入感を高めるために画面を全画面表示にすることが多いです。

特にAndroidで全画面表示を行うために少々特殊な実装が必要になるため、今回はその方法を紹介したいと思います。

システムUI

全画面表示を行うためには、OSが管理しているシステムUIを非表示にする必要があります。システムUIとは、Androidで言うところのステータスバーとナビゲーションジェスチャーバーのことを指します。

  • ステータスバー
  • ナビゲーションジェスチャーバー(iOSでいうホームインジケーター)

デフォルト状態での表示

まずはデフォルトの表示を確認してみます。

円形のコンテナを縦に3つ並べた際の、ステータスバーとナビゲーションジェスチャーバーの表示状態は以下のようになります。

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: Column(
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        _circle(),
        _circle(),
        _circle(),
      ],
    ),
  );
}

Widget _circle() => Container(
      height: 100,
      decoration: const BoxDecoration(
        shape: BoxShape.circle,
        color: Colors.blue,
      ),
    );

iOS/Androidともに、デフォルト状態でステータスバーの裏に円が回り込んでいるのがわかります。ですが、iOSではホームインジケーターの裏に円が回り込んでいるのに対して、Androidでは回り込んでいません。

Androidでナビゲーションバーの裏にコンテンツを表示するには、少し手を加える必要がありそうです。

ナビゲーションバーの裏にコンテンツを表示する

Androidでナビゲーションバーの裏にコンテンツを表示するには、SystemChromeクラスのsetEnabledSystemUIModeを利用します。

@override
void initState() {
  super.initState();
  SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
}

こうすることでコンテンツの描画領域が全画面になり、ナビゲーションバーの裏にコンテンツを表示することができます。

AppBarの裏にコンテンツを表示する

デフォルトでもステータスバーの裏にコンテンツを表示可能でしたが、AppBarを表示した場合は、AppBarの裏にコンテンツを表示することはできません。

@override
Widget build(BuildContext context) {
  return Scaffold(
    // AppBarを追加すると、コンテンツはAppBarの下に表示される.
    appBar: AppBar(
      backgroundColor:
          Theme.of(context).colorScheme.inversePrimary.withOpacity(0.5),
      title: Text(widget.title),
    ),
    // 省略.
  );
}

AppBarの裏にコンテンツを表示するには、extendBodyBehindAppBarを利用します。

@override
Widget build(BuildContext context) {
  return Scaffold(
    extendBodyBehindAppBar: true, // ← 追加することで、AppBarの裏に回る.
    appBar: AppBar(
      backgroundColor:
          Theme.of(context).colorScheme.inversePrimary.withOpacity(0.5),
      title: Text(widget.title),
    ),
    // 省略.
  );
}

こうすることで、AppBarの裏にコンテンツを表示することができました。これで画面全体にコンテンツを表示することができました。

システムUIを非表示にする

最後に、システムUIの表示状態を切り替える方法を紹介します。

現在のシステムUIの表示状態を取得する方法はないため、自分で表示状態を管理する必要があります。

// システムUIの表示状態を管理するフィールドを追加
bool _isSystemUIVisible = true;

@override
void initState() {
  super.initState();
  // システムUIの表示状態が変更されたときに呼ばれるコールバックを設定
  SystemChrome.setSystemUIChangeCallback((visible) async {
    setState(() {
      _isSystemUIVisible = visible;
    });
  });
  SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
}

状態にアクセスできるようになったので、あとは状態に応じて以下のように切り替えます。

@override
Widget build(BuildContext context) {
  return Scaffold(
    extendBodyBehindAppBar: true,
    // _isSystemUIVisibleの値に応じてAppBarを表示を切り替える.
    appBar: _isSystemUIVisible
        ? AppBar(
            backgroundColor:
                Theme.of(context).colorScheme.inversePrimary.withOpacity(0.5),
            title: Text(widget.title),
          )
        : null,
    body: InkWell(
      onTap: () {
        // 画面をタップするたびに、システムUIの表示状態を切り替える.
        if (_isSystemUIVisible) {
          SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
        } else {
          SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
        }
      },
      // 省略.
    ),
  );
}

これで、画面をタップするたびにシステムUIの表示状態を切り替えることができました。

まとめ

今回はFlutter + Android で全画面表示を行う方法を紹介しました。コンテンツの没入感を高めるために、ぜひ活用してみてください!

今回参考にさせてもらった資料はこちらです。

www.youtube.com

明日以降もカケハシ Advent Calendar 2023 をよろしくお願いします!