Flutter で発表資料作ってみた

みなさんは LT やカンファレンスの発表資料、何で作っていますでしょうか。自分は __Flutter アプリ__ で作っています。

Flutter はモバイルだけでなく Web、デスクトップ向けのアプリケーションも作れるフレームワークです。つまり、__アプリ開発と同じ要領で発表資料が作れてしまう__ というわけです。

たとえば最近では、[FlutterNinjas](https://flutterninjas.dev/) 向けの登壇資料を Flutter アプリで作成しました。

できあがった資料はこちらです。（Web アプリとしてビルドして GitHub Pages にデプロイしています）

https://chooyan-eng.github.io/flutter_ninjas_2025/#/title

この記事では「Flutter アプリとして発表資料を作る」ことにどのようなメリットがあるのか、またどのように作れるのかを簡単に紹介したいと思います。

## 「Flutter アプリとして発表資料を作る」とは

先述の通り、Flutter は Web、デスクトップ向けにアプリをビルドできます。つまり、スライドの 1 ページ 1 ページを「アプリの 1 画面」として実装し、Enter キーや右キーで次に進むよう実装して PC で表示すればそれは立派な発表資料として使えます。

Flutter は Hot reload により UI のコーディングはとても得意ですので、テキストや画像を置いてレイアウトを調整して、というような作業もスムーズです。コーディングで自由にコンポーネント化・共通化できる分、普通に作るより楽と言えるかもしれません。

しかし、やはりページ送り等の仕組みまで毎回自分で作っていては面倒です。そこで使えるのが `flutter_deck` というパッケージです。

https://pub.dev/packages/flutter_deck

`flutter_deck` を使うことで、以下のようなスライドに必要な機能が揃った Flutter アプリを簡単に開発できるようになります。

- Enter キー、矢印キーによるページ移動
- 特定のページにジャンプ
- M キーによる発表中のお絵描き
- 他言語への切り替え
- Dark/Light モードの切り替え

言語や Dark/Light モードの切り替えなどはいかにもアプリならではという感じですね。（もしかしたら一般的なスライド作成ソフトにあるのを私が知らないだけかもしれませんが。）

具体的な開発方法は後ほど説明します。

## Flutter アプリで作るメリット

発表資料を Flutter アプリで作ることによって、以下のようなメリットが生まれます。

### 資料の中にデモを埋め込める

なんといってもこれです。

技術系の発表となると、発表内で実際の動作を見せるデモを行うことは少なくありません。通常は資料とデモ用のウィンドウ（IDE やエミュレーターなど）を行ったりきたりしながらデモをすることが多いかと思いますが、切り替えのタイミングでどうしても流れが途切れてしまうという問題があります。

一方で資料自体を Flutter アプリとして作ることで、デモしたい動作自体を発表資料の中に埋め込むことができてしまいます。

百聞は一見にしかず、以下は私がアニメーション関連の LT をした際に資料に埋め込んだデモの様子です。

![flutter_deck_demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134943/e26ae863-cc3b-4c0e-a90b-e273465d7ca4.gif)

見ての通り、資料の中に触れる仕組みを埋め込むことで、シームレスに説明の中にデモを入れ込むことができるようになります。これによりテンポを落とすことなく伝わりやすいプレゼンができるようになります。

### 発表を面白くする仕組みを入れられる

Flutter アプリですので、アプリでできることは基本的になんでもできちゃいます。

たとえば私が今までに試したところだと

- Firebase と連携してアンケートシステムを埋め込む
- スライドと連動した補足資料を手元のスマートフォンや PC で見れるようにする
- タイムキープのための時計を配置する（且つ、その時計の実装を例にしてデモする）
- お遊びで実装した花火で盛り上げる

![flutter_deck_hanabi.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134943/fbfb985c-d86b-46ff-9027-130991c576db.gif)

プレゼンでは聴いている人たちが積極的に、楽しんで参加できることも重要な要素です。アプリという特性を活かしてより前のめりで聴いてもらえる仕掛けを自由に入れられるのも大きなメリットと言えます。

## Flutter で作るデメリット

メリットを書いたらちゃんとデメリットも書いておかねばなりません。

### 作るのに時間がかかる

文字と画像だけのスライドであれば問題ないのですが、仕掛けに凝り始めるといくらでも時間が使えてしまいます。やってることはアプリ開発ですので、動きや仕掛けのあるスライドほど実装に時間がかかります。このあたりは生成 AI にうまく助けてもらいたいところです。

### レイアウトが定まらない

アプリですので、レイアウトは画面サイズに合わせて動的に変化します。

つまり、手元のモニターで問題なく表示できたとしても、発表用のプロジェクターにつなげた瞬間レイアウトが崩れることも十分に考えられます。また資料を公開した後もそれを見る端末の環境によってレイアウトが崩れます。

Flutter アプリで資料を作る際はあまり文字の配置やレイアウトに拘らず、ある程度画面が伸縮しても耐えられる余白を持っておくのが吉です。

### 発表中にエラーが発生することも

Flutter アプリですので、実装にミスがあると発表中に実行時エラーが発生してスライドが止まったり想定しない挙動をしたりします。その際はそれをネタにしながら資料を実行し直してあげてください。

---

ここまでをまとめると、 __テキストや画像とトークだけではないデモや仕掛けで発表を盛り上げたい__ 場合に Flutter アプリ製の資料が効果を発揮するでしょう。

## flutter_deck で作る発表資料

それでは実装方法をみてみましょう。

先述の通り、[flutter_deck](https://pub.dev/packages/flutter_deck) パッケージを利用することで効率よく資料作りを進められます。

```shell
$ flutter create my_slide_deck
$ cd my_slide_deck
$ flutter pub add flutter_deck
```

いつも通りに Flutter アプリのプロジェクトを作成したら `flutter_deck` を依存関係に追加します。

通常 Flutter アプリを開発する際は Widget ツリーの先頭の方に `MaterialApp` を配置しますが、`flutter_deck` を使う場合は `FlutterDeckApp` を配置します。

```dart
class MainApp extends StatelessWidget {
  const MainApp({super.key});

  @override
  Widget build(BuildContext context) {
    return FlutterDeckApp(
      themeMode: ThemeMode.dark,
      darkTheme: FlutterDeckThemeData.dark().copyWith(
        textTheme: const FlutterDeckTextTheme(
          title: TextStyle(fontSize: 32, fontWeight: FontWeight.bold),
          ...省略
```

`FlutterDeckApp` の引数でスライド（アプリ）全体のテーマを設定しつつ、ひとつひとつのページは以下のように `FlutterDeckSlideWidget` を継承したクラスを定義します。

```dart
/// ページ設定を保持する Widget
class WrapUpPage extends FlutterDeckSlideWidget {
  const VelocityPage({super.key})
    : super(
        configuration: const FlutterDeckSlideConfiguration(
          route: '/wrapup-page',
          title: 'Wrap up',
        ),
      );

  @override
  Widget build(BuildContext context) {
    return FlutterDeckSlide.custom(
      builder: (context) {
        return const _Slide(); // ページ本体の UI を構築する Widget
      },
    );
  }
}
```

あとはいつも通りスライドの UI を `build()` メソッドに実装していく流れになります。作成したページ（ここでは `WrapUpWidget`）たちは `FlutterDeckApp` の `slides` 引数のリスト追加することで、順番にページが表示されるようになります。

```dart
class MainApp extends StatelessWidget {
  const MainApp({super.key});

  @override
  Widget build(BuildContext context) {
    return FlutterDeckApp(
      ...省略
      slides: [
        const TitleSlide(),
        const AnimationControllerSlide(),
        const BasicsSlide(),
        const BasicsAnimationSlide(),
        const WrapUpSlide(),
      ],
    );
  }
}
```

ページの作成と `FlutterDeckApp` への登録ができたら、macOS や Windows 等のデスクトップアプリ、もしくは Web アプリとして実行します。

ここでは大雑把な流れのみ説明しましたが、詳しくは以下の公式ドキュメントを参照してください。

https://flutterdeck.dev/

繰り返しですが、これは Flutter アプリです。アプリ全体で状態を共有した仕掛けを入れたければ `Riverpod` でも `InheritedWidget` でも使えますし、SDK がプラットフォームに対応している限り Firebase や Supabase などのバックエンドとの連携も可能です。普段のアプリ開発の技術を使って自由に仕掛けを入れてしまいましょう。

---

以上です。

Flutter はモバイルに限らずあらゆるプラットフォームで実行可能なフレームワークです。そのため用途もいわゆる「アプリ」にとどまらず、このような発表資料としても活用できてしまいます。

ちょっと変わった資料で発表を盛り上げてみたい方、ぜひ `flutter_deck` を使って「Flutter アプリ」として資料を作ってみてください。