【まとめ】完成コードをカスタマイズしながらFlutterアプリ開発の流れを身につける
この節で学ぶこと
前の節では、完成したNETAFLIX風アプリをカスタマイズしました。
作品を追加する、色を変える、カテゴリを追加する、共有文を変更することで、完成コードを自分の手で動かす練習をしました。
今回の節では、ここまで作ってきたFlutterアプリ開発の流れをまとめます。
ただコードを写して終わるのではなく、
アプリはどこから始まるのか
画面はどう切り替わるのか
データはどこにあるのか
タップしたら何が起きるのか
どこを変えれば自分のアプリになるのか
を、自分の言葉で説明できるようにしていきます。
まず全体の流れを振り返る
今回作ったNETAFLIX風アプリは、次のような流れで動いていました。
main()
↓
runApp()
↓
NetflixLikeApp
↓
MaterialApp
↓
NetflixShell
↓
BottomNavigationで画面切り替え
↓
Home / Search / Clips / My Netaflix
↓
作品をタップ
↓
MovieDetailPage
↓
Playボタン
↓
MoviePlayerPage
Flutterアプリは、最初に main() から始まります。
そこから runApp() によって、アプリ全体の根っこになるWidgetが画面に表示されます。
今回の場合は、NetflixLikeApp がアプリ全体の入口でした。
ここまで作った主な画面
今回のアプリでは、複数の画面を作りました。
| 画面 | 役割 |
|---|---|
HomePage | 作品を一覧で見せるメイン画面 |
MovieDetailPage | 作品の詳細を表示する画面 |
MoviePlayerPage | YouTube動画を再生する画面 |
ClipsPage | 縦型ショート動画風に作品を見せる画面 |
SearchPage | 作品を検索する画面 |
MyNetflixPage | プロフィール・通知・視聴中リストを表示する画面 |
最初はバラバラに見えた画面も、完成してみると、それぞれに役割があります。
アプリ開発では、「この画面は何のためにあるのか」を考えることが大切です。
画面切り替えの中心はNetflixShell
今回のアプリでは、BottomNavigationによる画面切り替えを NetflixShell が担当していました。
final pages = const [
HomePage(),
SearchPage(),
ClipsPage(),
MyNetflixPage(),
];
そして、現在選ばれているタブ番号を currentIndex で管理していました。
int currentIndex = 0;
表示する画面は、次のように決まります。
body: pages[currentIndex],
この仕組みによって、BottomNavigationをタップすると画面が切り替わります。
currentIndex = 0 → HomePage
currentIndex = 1 → SearchPage
currentIndex = 2 → ClipsPage
currentIndex = 3 → MyNetflixPage
状態が変わる画面ではStatefulWidgetを使う
Flutterでは、画面の中で変化する値がある場合、StatefulWidget を使います。
今回のアプリでは、次のような場所で状態が必要でした。
| Widget | 状態 |
|---|---|
NetflixShell | 現在選ばれているタブ番号 |
SearchPage | 検索欄に入力された文字 |
MoviePlayerPage | YouTubeプレイヤーのController |
ClipsPage | ページ表示や共有処理の管理 |
たとえば、BottomNavigationでは、タブを押すと currentIndex が変わります。
setState(() {
currentIndex = index;
});
setState を使うことで、Flutterに「画面を更新してください」と伝えています。
状態が変わらない画面ではStatelessWidgetを使う
一方で、ただ表示するだけの画面や部品は、StatelessWidget で作れます。
たとえば、次のようなWidgetです。
| Widget | 理由 |
|---|---|
ContentCard | 受け取った作品を表示するだけ |
RowTitle | 見出しを表示するだけ |
MyNetflixCard | メニューカードを表示するだけ |
MovieDetailPage | 受け取った作品情報を表示するだけなら状態を持たない |
もちろん、今後Likeボタンや保存状態を追加する場合は、StatefulWidget や状態管理が必要になることもあります。
最初の理解としては、次のように考えると分かりやすいです。
中の値が変わる
↓
StatefulWidget
受け取った情報を表示するだけ
↓
StatelessWidget
MovieItemがアプリの中心データ
今回のアプリで一番重要なデータは、MovieItem でした。
class MovieItem {
const MovieItem({
required this.title,
required this.subtitle,
required this.description,
required this.posterUrl,
required this.backdropUrl,
required this.youtubeVideoId,
required this.matchRate,
required this.year,
required this.rating,
required this.seasonLabel,
required this.category,
});
final String title;
final String subtitle;
final String description;
final String posterUrl;
final String backdropUrl;
final String youtubeVideoId;
final int matchRate;
final int year;
final String rating;
final String seasonLabel;
final String category;
}
MovieItem は、作品1件分の情報をまとめる箱です。
作品タイトル、説明文、画像URL、YouTube動画ID、カテゴリなど、アプリ内で必要な情報が入っています。
moviesを変えるとアプリ全体が変わる
作品一覧は、movies に入っていました。
const movies = [
MovieItem(...),
MovieItem(...),
MovieItem(...),
];
この movies は、いろいろな画面で使われています。
| 画面 | movies** の使い方** |
|---|---|
| Home画面 | 作品一覧として表示 |
| Search画面 | 検索対象として使う |
| Clips画面 | 縦型動画風に表示 |
| My Netaflix画面 | 視聴中リスト・My Listとして表示 |
| Detail画面 | 選ばれた1作品を表示 |
つまり、movies に作品を追加すると、アプリ全体に反映されます。
ここが、データを1か所にまとめる大きなメリットです。
画面遷移ではNavigatorを使う
作品カードをタップしたとき、詳細画面へ移動するには Navigator を使いました。
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (context) => MovieDetailPage(movie: movie),
),
);
このコードでは、ただ画面を移動しているだけではありません。
MovieDetailPage(movie: movie) のように、選んだ作品データを次の画面に渡しています。
作品カードをタップ
↓
MovieDetailPageへ移動
↓
選んだmovieを渡す
↓
詳細画面にその作品の情報が表示される
Flutterの画面遷移では、「どの画面へ行くか」と「どのデータを渡すか」をセットで考えることが大切です。
YouTube再生では動画IDを使う
詳細画面のPlayボタンを押すと、MoviePlayerPage に移動しました。
MoviePlayerPage(movie: movie)
動画再生では、作品データの中にある youtubeVideoId を使いました。
videoId: widget.movie.youtubeVideoId,
このようにすることで、作品ごとに違うYouTube動画を再生できます。
MovieItem
↓
youtubeVideoIdを持っている
↓
MoviePlayerPageに渡す
↓
YouTubeプレイヤーで再生する
動画アプリでは、作品データと再生機能をつなげることが重要です。
検索機能はqueryとfilteredMoviesで作る
Search画面では、入力された文字を query として管理しました。
String query = '';
文字を入力すると、onChanged で query が更新されます。
onChanged: (value) {
setState(() {
query = value;
});
}
そして、filteredMovies で作品を絞り込みました。
return movies.where((movie) {
final title = movie.title.toLowerCase();
final subtitle = movie.subtitle.toLowerCase();
final description = movie.description.toLowerCase();
final category = movie.category.toLowerCase();
return title.contains(keyword) ||
subtitle.contains(keyword) ||
description.contains(keyword) ||
category.contains(keyword);
}).toList();
この流れを理解すると、検索機能の基本が見えてきます。
入力する
↓
queryが変わる
↓
filteredMoviesが変わる
↓
表示される作品が変わる
共通Widgetを使うとコードが整理される
今回のアプリでは、同じようなUIを何度も使いました。
そのため、共通Widgetとして部品化しました。
| 共通Widget | 役割 |
|---|---|
ContentRow | 横スクロールの作品リスト |
ContentCard | 作品1件分のカード |
RowTitle | セクション見出し |
DetailAction | 詳細画面のアクションボタン |
MyNetflixCard | My画面のメニューカード |
SearchResultTile | 検索結果の1件表示 |
共通Widgetを使うと、同じUIを何度も書かなくて済みます。
さらに、あとでデザインを変えたいときも、1か所を直せば複数の画面に反映できます。
同じコードを何度も書く
↓
修正が大変
共通Widgetにする
↓
修正しやすい
↓
読みやすい
共有機能は共通関数にまとめる
共有処理は、shareNetaflixMovie にまとめました。
Future<void> shareNetaflixMovie({
required BuildContext context,
required MovieItem movie,
}) async {
await SharePlus.instance.share(
ShareParams(
text:
'NETAFLIXで「${movie.title}」をチェック!\nhttps://www.youtube.com/watch?v=${movie.youtubeVideoId}',
subject: movie.title,
sharePositionOrigin: shareOriginFromContext(context),
),
);
}
この関数を作っておくと、詳細画面でもClips画面でも同じ共有処理を使えます。
MovieDetailPage
↓
shareNetaflixMovie
ClipsPage
↓
shareNetaflixMovie
共有文を変更したいときも、この関数を変更すれば複数画面に反映されます。
カスタマイズで理解が深まる
完成コードを読むだけでも勉強になります。
しかし、本当に理解が深まるのは、自分で変更したときです。
今回のカスタマイズでは、次のことに挑戦しました。
| カスタマイズ | 学べること |
|---|---|
| 作品追加 | データ構造と画面反映の関係 |
| 色変更 | 共通色管理とデザイン変更 |
| カテゴリ追加 | データ分類と検索の関係 |
| 共有文変更 | 共通関数と文字列操作 |
| アイコン変更 | アプリらしさを高める設定 |
| アプリ名変更 | iOS設定や表示名の考え方 |
カスタマイズは、ただ見た目を変える作業ではありません。
「このコードは何のためにあるのか」を確認するための練習です。
Flutterアプリ開発の基本サイクル
今回の教材全体を通して、Flutterアプリ開発の基本サイクルを体験しました。
1. 画面を作る
2. データを用意する
3. データを画面に表示する
4. タップで画面遷移する
5. 入力によって表示を変える
6. 外部パッケージを使う
7. iOSやAndroidの設定を整える
8. アイコンやアプリ名を設定する
9. 完成コードを読む
10. 自分でカスタマイズする
この流れは、NETAFLIX風アプリだけでなく、他のアプリにも応用できます。
たとえば、飲食店アプリ、学習アプリ、予約アプリ、商品カタログアプリでも、基本は同じです。
他のアプリに応用するなら
今回のNETAFLIX風アプリは、作品データを表示するアプリでした。
しかし、MovieItem を別のデータに変えれば、いろいろなアプリに応用できます。
| 応用例 | MovieItemの代わりになるデータ |
|---|---|
| 飲食店アプリ | MenuItem |
| 学習アプリ | LessonItem |
| ECアプリ | ProductItem |
| 観光アプリ | SpotItem |
| 予約アプリ | ServiceItem |
| 医療系案内アプリ | TreatmentItem |
たとえば、飲食店アプリなら、作品タイトルの代わりにメニュー名を表示できます。
MovieItem.title
↓
MenuItem.name
動画IDの代わりに、商品詳細ページや予約URLを持たせることもできます。
つまり、今回学んだ構造は、動画アプリだけのものではありません。
どこを変えればオリジナルアプリになるか
NETAFLIX風アプリを別のアプリに変える場合、まずは次の場所を変更します。
| 変える場所 | 内容 |
|---|---|
MovieItem | データの形を変える |
movies | 表示するデータを変える |
NetflixColors | 色を変える |
HomePage | 最初に見せたい情報を変える |
SearchPage | 検索対象を変える |
MovieDetailPage | 詳細表示の内容を変える |
shareNetaflixMovie | 共有文を変える |
Info.plist | アプリ名やiOS設定を変える |
icon.png | アプリアイコンを変える |
すべてを一気に変える必要はありません。
まずはデータと色を変えるだけでも、かなり違うアプリに見えます。
よくあるつまずきポイント
Q. 完成コードを見ても、どこを変えればよいか分かりません。
まずは、次の4か所だけ見れば大丈夫です。
movies
NetflixColors
shareNetaflixMovie
BottomNavigationのpages
作品やデータを変えたいなら movies。
色を変えたいなら NetflixColors。
共有文を変えたいなら shareNetaflixMovie。
画面構成を変えたいなら pages を見ます。
Q. 変更したらエラーが出ました。
エラーが出たときは、まず次の点を確認します。
| 確認項目 | よくある原因 |
|---|---|
| カンマ | MovieItem 同士の区切り忘れ |
| required | 必要な項目の書き忘れ |
| 括弧 | ()、[]、{} の閉じ忘れ |
| 文字列 | ' や " の閉じ忘れ |
| YAML | pubspec.yaml のインデントミス |
| URL | 画像URLや動画IDの間違い |
エラーは悪いものではありません。
「ここに書き方の問題があります」と教えてくれるメッセージです。
Q. UIを変えたいのに、どのWidgetを触ればよいか分かりません。
画面全体を変えたいなら、各Pageを見ます。
HomePage
SearchPage
ClipsPage
MyNetflixPage
MovieDetailPage
作品カードの見た目を変えたいなら、ContentCard を見ます。
検索結果の見た目を変えたいなら、SearchResultTile を見ます。
My画面のメニューカードを変えたいなら、MyNetflixCard を見ます。
まずは、「どの見た目を変えたいのか」を決めてから、該当するWidgetを探しましょう。
チャレンジ
チャレンジ1:自分の言葉でアプリの流れを説明しよう
次の流れを、声に出して説明してみましょう。
main()
↓
NetflixLikeApp
↓
NetflixShell
↓
HomePage
↓
MovieDetailPage
↓
MoviePlayerPage
ポイントは、コードを暗記することではありません。
「アプリがどこから始まり、どう画面がつながるのか」を説明できることです。
チャレンジ2:MovieItemを別のデータに置き換えて考えよう
動画アプリではなく、飲食店メニューアプリにするとしたら、MovieItem はどのような名前にできますか。
例です。
MovieItem
↓
MenuItem
そして、次の項目を考えてみましょう。
| MovieItem | MenuItemなら |
|---|---|
title | name |
description | description |
posterUrl | imageUrl |
category | category |
rating | price |
データの形を変えると、アプリのテーマも変えられます。
チャレンジ3:自分だけのカスタマイズ案を3つ書こう
次のように、自分のカスタマイズ案を書いてみましょう。
1. アプリ名を変える
2. 作品データを自分の好きなジャンルにする
3. 共有文を日本語で自然な文章にする
できれば、「どのファイル・どのコードを変えるか」まで書いてみましょう。
チャレンジ4:エラーが出たときの確認順を作ろう
自分用のエラーチェックリストを作ってみましょう。
例です。
1. 保存したか確認する
2. 赤線の場所を見る
3. カンマ忘れを確認する
4. 括弧の閉じ忘れを確認する
5. required項目を書いたか確認する
6. ターミナルのエラー文を読む
エラー対応の型を持っておくと、次の開発がかなり楽になります。
チャレンジの答え
チャレンジ1の答え
アプリは main() から始まります。
main() の中で runApp(const NetflixLikeApp()) が実行され、NetflixLikeApp がアプリ全体の入口になります。
NetflixLikeApp の中では MaterialApp を使い、最初の画面として NetflixShell を表示します。
NetflixShell はBottomNavigationで画面を切り替えます。
Home画面で作品をタップすると、MovieDetailPage に移動し、Playボタンを押すと MoviePlayerPage に移動してYouTube動画を再生します。
チャレンジ2の答え
飲食店メニューアプリにする場合、MovieItem は MenuItem のように変更できます。
例です。
class MenuItem {
const MenuItem({
required this.name,
required this.description,
required this.imageUrl,
required this.price,
required this.category,
});
final String name;
final String description;
final String imageUrl;
final int price;
final String category;
}
このように、データの形を変えることで、動画アプリの構造を別ジャンルのアプリに応用できます。
チャレンジ3の答え
カスタマイズ案の例です。
| カスタマイズ案 | 変更する場所 |
|---|---|
アプリ名を MY MOVIE にする | Info.plist、MaterialApp.title |
| アクセントカラーを青にする | NetflixColors.red |
| 作品ジャンルをアニメ中心にする | movies の category |
| 共有文を日本語にする | shareNetaflixMovie |
| アイコンを変更する | assets/icon/icon.png |
どこを変えればよいかが分かると、自分のアイデアをコードに反映しやすくなります。
チャレンジ4の答え
エラーが出たときの確認順の例です。
1. ファイルを保存したか確認する
2. エラーが出ている行を見る
3. 直前に変更した場所を見る
4. カンマ忘れを確認する
5. 括弧の閉じ忘れを確認する
6. 文字列の閉じ忘れを確認する
7. required項目を書いたか確認する
8. pubspec.yamlならインデントを確認する
9. flutter pub getを実行したか確認する
10. エラー文をそのまま検索・質問する
エラーが出たときは、慌てずに「最後に変えた場所」から確認するのが基本です。
このページのまとめ
このページでは、完成したNETAFLIX風アプリを振り返りながら、Flutterアプリ開発の流れを整理しました。
大切なポイントは次の通りです。
- Flutterアプリは
main()から始まる。 runApp()に渡したWidgetが、アプリ全体の根っこになる。MaterialAppでアプリ全体の設定を行う。NetflixShellがBottomNavigationによる画面切り替えを担当する。StatefulWidgetは、変化する状態を持つ画面で使う。StatelessWidgetは、受け取った情報を表示するだけの部品で使う。MovieItemは、作品1件分のデータ構造。moviesは、アプリ全体で使う作品一覧。Navigatorを使うと、画面遷移ができる。- 画面遷移では、次の画面にデータを渡すことが重要。
youtubeVideoIdによって、作品ごとのYouTube動画を再生できる。queryとfilteredMoviesによって、検索機能を作れる。- 共通Widgetを使うと、コードが整理され、修正もしやすくなる。
- 共有処理は共通関数にまとめると便利。
- 完成コードをカスタマイズすると、コードの役割が理解しやすくなる。
- データ、色、共有文、アイコン、アプリ名を変えるだけでも、オリジナルアプリに近づけられる。
- エラーが出たら、最後に変更した場所から落ち着いて確認する。
次のステップ
ここまでで、NETAFLIX風アプリ制作教材の大きな流れは完了です。
次に進むなら、次の発展課題がおすすめです。
| 発展課題 | 学べること |
|---|---|
| お気に入り保存機能 | 状態管理・ローカル保存 |
| ログイン機能 | FirebaseやSupabase連携 |
| 作品データの外部化 | JSON・API・データベース |
| 予約・購入機能 | 決済やフォーム設計 |
| 管理画面 | データ追加・編集・削除 |
| デプロイ・配布 | アプリ公開の流れ |
今回作ったアプリは、完成形でありながら、発展の土台でもあります。
まずは完成コードを何度も触り、「変えたらどうなるか」を試してみることが、次の成長につながります。
