【データ設計】MovieItemクラスで作品情報をひとまとまりにする
この節で学ぶこと
前の節では、黒背景・赤アクセント・白文字を使って、動画アプリ風の世界観を作る方法を学びました。
今回の節では、アプリに表示する 作品情報の持ち方 を見ていきます。
アプリの画面には、作品タイトル、説明文、ポスター画像、背景画像、YouTube動画ID、年齢制限、カテゴリなど、いろいろな情報が表示されています。
たとえば、Home画面では作品の画像が表示されます。
作品詳細画面では、タイトルや説明文が表示されます。
YouTube再生画面では、動画IDを使ってトレーラーを再生します。
Search画面では、タイトルやカテゴリを使って検索します。
このように、1つの作品にはたくさんの情報が入っています。
その情報をバラバラに持つのではなく、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.year,
required this.rating,
required this.seasonLabel,
required this.category,
required this.matchRate,
required this.homeCategory,
});
final String title;
final String subtitle;
final String description;
final String posterUrl;
final String backdropUrl;
final String youtubeVideoId;
final String year;
final String rating;
final String seasonLabel;
final String category;
final int matchRate;
final HomeCategory homeCategory;
}
最初は少し長く見えるかもしれません。
でも、やっていることはシンプルです。
1つの作品に必要な情報をまとめるための設計図を作っている
ということです。
MovieItemは「作品カードの設計図」
MovieItem は、作品情報を入れるための箱のようなものです。
たとえば、1つの作品には次のような情報があります。
| 情報 | 例 |
|---|---|
| タイトル | Squid Game |
| サブタイトル | Survival thriller series |
| 説明文 | Hundreds of cash-strapped players… |
| ポスター画像 | 縦長の作品画像URL |
| 背景画像 | 横長の背景画像URL |
| YouTube動画ID | oqxAJKy0ii4 |
| 公開年 | 2021 |
| 年齢制限 | 18+ |
| シーズン | Season 1 |
| カテゴリ | TV Drama |
| マッチ率 | 98 |
| Homeカテゴリ | Shows |
これらを毎回バラバラに書くと、かなり管理しづらくなります。
そこで、MovieItem という形でまとめています。
作品1つ分の情報 = MovieItem
と考えると分かりやすいです。
クラスとは?
ここで出てくる class という言葉も確認しておきましょう。
class MovieItem {
...
}
class は、データや処理をまとめるための設計図です。
今回の場合、MovieItem は「作品情報の設計図」です。
たとえるなら、映画館の作品紹介カードを作るための入力用紙のようなものです。
タイトルを書く欄
説明文を書く欄
画像URLを書く欄
年齢制限を書く欄
カテゴリを書く欄
このような欄をあらかじめ決めておくことで、作品情報を同じ形でそろえることができます。
final String title とは?
MovieItem の中には、次のようなコードがあります。
final String title;
これは、
titleという名前の文字データを持ちます
という意味です。
分けて見ると、こうなります。
| コード | 意味 |
|---|---|
final | 一度入れたら基本的に変更しない |
String | 文字データ |
title | データの名前 |
つまり、title には作品タイトルが入ります。
たとえば、
title: 'Squid Game',
のように使います。
Stringとintの違い
MovieItem には、String と int が出てきます。
final String title;
final int matchRate;
String は文字です。
'Squid Game'
'2021'
'18+'
このように ' で囲まれているものは、基本的に文字として扱われます。
一方で、int は整数です。
98
96
91
今回の matchRate は、98% Match のように表示するための数字なので、int にしています。
| 型 | 使うもの | 例 |
|---|---|---|
String | 文字 | 'Squid Game' |
int | 整数 | 98 |
最初は、「文字はString、数字はint」と覚えておくと十分です。
required this.title とは?
次に、この部分を見てみましょう。
const MovieItem({
required this.title,
required this.subtitle,
required this.description,
...
});
これは、MovieItem を作るときに必要な情報を指定しています。
required は、
これは必ず入力してください
という意味です。
たとえば、title がない作品データを作ろうとすると困ります。
タイトルがないと、画面に作品名を表示できません。
そのため、
required this.title,
として、必ずタイトルを入れるようにしています。
const MovieItemとは?
MovieItem の最初に、次のように書かれています。
const MovieItem({
...
});
const は、簡単に言うと「中身が固定されているデータ」に使います。
今回の作品データは、アプリの中に最初から書いてある固定データです。
ユーザーが自由に追加・編集するものではありません。
そのため、const を使っています。
最初は深く考えすぎなくて大丈夫です。
最初から決まっているデータにはconstを使うことがある
くらいでOKです。
実際の作品データを見てみよう
次に、MovieItem を使って作品データを作っている部分を見てみます。
const movies = [
MovieItem(
title: 'Squid Game',
subtitle: 'Survival thriller series',
description:
'Hundreds of cash-strapped players accept a strange invitation to compete in children’s games. Inside, a tempting prize awaits — with deadly high stakes.',
posterUrl:
'https://image.tmdb.org/t/p/w500/dDlEmu3EZ0Pgg93K2SVNLCjCSvE.jpg',
backdropUrl:
'https://image.tmdb.org/t/p/w1280/oaGvjB0DvdhXhOAuADfHb261ZHa.jpg',
youtubeVideoId: 'oqxAJKy0ii4',
year: '2021',
rating: '18+',
seasonLabel: 'Season 1',
category: 'TV Drama',
matchRate: 98,
homeCategory: HomeCategory.shows,
),
];
これは、Squid Game という作品1つ分のデータです。
MovieItem の中で決めた項目に沿って、実際の値を入れています。
つまり、次のような関係です。
MovieItemクラス
↓
作品情報の設計図
MovieItem(...)
↓
設計図を使って作った作品データ
moviesリストとは?
作品データは、movies というリストにまとめています。
const movies = [
MovieItem(...),
MovieItem(...),
MovieItem(...),
];
リストとは、複数のデータを順番に並べたものです。
今回の場合は、複数の作品をまとめて管理しています。
movies
├── Squid Game
├── Stranger Things
├── Money Heist
├── Wednesday
├── Dark
└── The Witcher
Home画面やSearch画面では、この movies リストを使って作品を表示しています。
なぜリストにするの?
アプリには、作品が1つだけ表示されるわけではありません。
横スクロールの一覧にも使いますし、検索結果にも使います。
Clips画面では縦にスワイプして作品を切り替えます。
My Netaflix画面では、Continue Watchingとして並べています。
そのため、作品データをまとめておく必要があります。
movies にまとめておくと、いろいろな画面で同じ作品データを使い回せます。
作品データを1か所にまとめる
↓
Home画面でも使える
↓
Search画面でも使える
↓
Clips画面でも使える
↓
詳細画面でも使える
これがデータ設計の大事なところです。
各項目の役割を確認しよう
ここで、MovieItem の各項目がどこで使われるのかを整理します。
| 項目 | 役割 |
|---|---|
title | 作品タイトルとして表示する |
subtitle | 作品の短い説明として使う |
description | 詳細画面やClips画面の説明文に使う |
posterUrl | 縦長のポスター画像に使う |
backdropUrl | 横長の背景画像に使う |
youtubeVideoId | YouTube再生に使う |
year | 公開年として表示する |
rating | 年齢制限として表示する |
seasonLabel | シーズン情報として表示する |
category | ジャンル表示や検索に使う |
matchRate | 98% Match のような表示に使う |
homeCategory | Home画面のカテゴリ切り替えに使う |
このように、作品データは画面のあちこちで使われています。
1つのデータが、いろいろな画面に反映されるのが面白いところです。
posterUrlとbackdropUrlの違い
作品画像には、posterUrl と backdropUrl の2つがあります。
posterUrl:
'https://image.tmdb.org/t/p/w500/dDlEmu3EZ0Pgg93K2SVNLCjCSvE.jpg',
backdropUrl:
'https://image.tmdb.org/t/p/w1280/oaGvjB0DvdhXhOAuADfHb261ZHa.jpg',
どちらも画像URLですが、使われる場所が違います。
| 項目 | 画像の形 | 使う場所 |
|---|---|---|
posterUrl | 縦長画像 | 作品カード、横スクロール一覧 |
backdropUrl | 横長画像 | Homeの背景、詳細画面の背景、Clips背景 |
動画アプリでは、縦長のポスター画像と横長の背景画像を使い分けることが多いです。
縦長画像は、作品一覧に並べやすいです。
横長画像は、画面いっぱいの背景に使いやすいです。
youtubeVideoIdは動画再生に使う
youtubeVideoId は、YouTube動画を再生するために使います。
youtubeVideoId: 'oqxAJKy0ii4',
YouTubeのURLがこちらだとします。
https://www.youtube.com/watch?v=oqxAJKy0ii4
この中の動画IDは、
oqxAJKy0ii4
です。
アプリでは、この動画IDを使ってYouTubeプレイヤーを表示しています。
controller = YoutubePlayerController.fromVideoId(
videoId: widget.movie.youtubeVideoId,
autoPlay: true,
params: const YoutubePlayerParams(
showControls: true,
showFullscreenButton: true,
playsInline: true,
strictRelatedVideos: true,
enableCaption: true,
),
);
つまり、作品ごとに youtubeVideoId を変えると、再生される動画も変わります。
homeCategoryとは?
homeCategory は、Home画面のカテゴリ切り替えに使います。
homeCategory: HomeCategory.shows,
今回のアプリには、次のカテゴリがあります。
enum HomeCategory {
all,
shows,
movies,
games,
newHot,
}
この homeCategory によって、作品がどのカテゴリに属しているかを決めています。
たとえば、Squid Game は shows です。
homeCategory: HomeCategory.shows,
Wednesday は newHot です。
homeCategory: HomeCategory.newHot,
Home画面で Shows タブを押すと、HomeCategory.shows の作品だけが表示されます。
enumとは?
ここで出てくる enum も確認しておきましょう。
enum HomeCategory {
all,
shows,
movies,
games,
newHot,
}
enum は、選択肢をあらかじめ決めておくためのものです。
今回の場合は、Home画面のカテゴリとして使えるものを決めています。
All
Shows
Movies
Games
New & Hot
文字で毎回 'shows' や 'movies' と書く方法もありますが、スペルミスが起きやすくなります。
enum にしておくと、決まった選択肢の中から選べるので、コードが安全になります。
labelで表示名を作る
HomeCategory には、画面に表示するためのラベルも用意しています。
extension HomeCategoryLabel on HomeCategory {
String get label {
switch (this) {
case HomeCategory.all:
return 'All';
case HomeCategory.shows:
return 'Shows';
case HomeCategory.movies:
return 'Movies';
case HomeCategory.games:
return 'Games';
case HomeCategory.newHot:
return 'New & Hot';
}
}
}
これは、HomeCategory.shows を画面上では Shows と表示するための仕組みです。
たとえば、コードではこのように使えます。
tab.label
すると、カテゴリに応じて、
Shows
Movies
Games
New & Hot
のように表示されます。
データが画面に表示される流れ
ここまで見た内容を、画面表示の流れとして整理してみます。
moviesリストに作品データを書く
↓
Home画面がmoviesを読む
↓
作品カードにposterUrlを表示する
↓
作品カードをタップする
↓
MovieDetailPageにmovieを渡す
↓
詳細画面でtitleやdescriptionを表示する
↓
PlayボタンでyoutubeVideoIdを使って動画を再生する
つまり、1つの MovieItem データが、いろいろな画面につながっています。
データ設計がきれいにできていると、画面づくりも楽になります。
まずカスタマイズしてみよう
今回は、作品タイトルを変えてみましょう。
movies の中にある、次の部分を探してください。
title: 'Squid Game',
これを、たとえば次のように変えてみます。
title: 'Survival Game',
保存して、アプリを確認してください。
Home画面や詳細画面のタイトルが変わっていれば成功です。
このように、movies のデータを変えるだけで、画面の表示も変わります。
説明文もカスタマイズしてみよう
次に、作品の説明文を変えてみます。
description:
'Hundreds of cash-strapped players accept a strange invitation to compete in children’s games. Inside, a tempting prize awaits — with deadly high stakes.',
たとえば、教材用に分かりやすくするなら、次のようにできます。
description:
'参加者たちが不思議なゲームに挑戦する、緊張感のあるサバイバル作品です。',
保存して、作品詳細画面やClips画面を確認してください。
説明文が変わっていればOKです。
matchRateをカスタマイズしてみよう
次は、マッチ率を変えてみます。
matchRate: 98,
これを次のように変えてみます。
matchRate: 87,
保存して、詳細画面やClips画面を確認してください。
87% Match
のように表示が変わります。
数字を変えるだけで、画面の情報が変わることが分かります。
よくあるつまずきポイント
Q. 作品データを追加したらエラーが出ました。
MovieItem では、すべての項目が required になっています。
そのため、作品を追加するときは、次の項目をすべて入れる必要があります。
MovieItem(
title: '',
subtitle: '',
description: '',
posterUrl: '',
backdropUrl: '',
youtubeVideoId: '',
year: '',
rating: '',
seasonLabel: '',
category: '',
matchRate: 0,
homeCategory: HomeCategory.shows,
),
1つでも足りないと、エラーになることがあります。
Q. カンマは必要ですか?
必要です。
Dartでは、項目の区切りにカンマを使います。
title: 'Squid Game',
subtitle: 'Survival thriller series',
description: '...',
カンマがないと、次の項目との区切りが分からなくなってエラーになります。
特に、作品データを追加するときはカンマ忘れが起きやすいです。
Q. 画像が表示されません。
posterUrl や backdropUrl のURLが正しいか確認してください。
また、URLが途中で切れていないかも見てください。
posterUrl:
'https://image.tmdb.org/t/p/w500/dDlEmu3EZ0Pgg93K2SVNLCjCSvE.jpg',
URLは長いので、コピーするときに一部が抜けることがあります。
Q. YouTubeが再生されません。
youtubeVideoId に、URL全体ではなく動画IDだけを入れているか確認してください。
OKな例:
youtubeVideoId: 'oqxAJKy0ii4',
間違いやすい例:
youtubeVideoId: 'https://www.youtube.com/watch?v=oqxAJKy0ii4',
今回のコードでは、動画IDだけを使います。
チャレンジ
チャレンジ1:作品タイトルを変えてみよう
次のコードを探してください。
title: 'Squid Game',
これを好きな作品名に変えてみましょう。
例:
title: 'Survival Game',
チャレンジ2:説明文を日本語にしてみよう
次のような説明文を探してください。
description:
'Hundreds of cash-strapped players accept a strange invitation to compete in children’s games. Inside, a tempting prize awaits — with deadly high stakes.',
これを日本語の説明文に変えてみましょう。
例:
description:
'参加者たちが不思議なゲームに挑戦する、緊張感のあるサバイバル作品です。',
チャレンジ3:マッチ率を変えてみよう
次のコードを探してください。
matchRate: 98,
これを次のように変えてみましょう。
matchRate: 87,
チャレンジ4:カテゴリを変えてみよう
次のコードを探してください。
homeCategory: HomeCategory.shows,
これを次のように変えてみましょう。
homeCategory: HomeCategory.movies,
Home画面でカテゴリタブを押したとき、表示される場所が変わるか確認してください。
チャレンジの答え
チャレンジ1の答え
変更前:
title: 'Squid Game',
変更後の例:
title: 'Survival Game',
Home画面や詳細画面に表示される作品タイトルが変わります。
チャレンジ2の答え
変更前:
description:
'Hundreds of cash-strapped players accept a strange invitation to compete in children’s games. Inside, a tempting prize awaits — with deadly high stakes.',
変更後の例:
description:
'参加者たちが不思議なゲームに挑戦する、緊張感のあるサバイバル作品です。',
詳細画面やClips画面に表示される説明文が変わります。
チャレンジ3の答え
変更前:
matchRate: 98,
変更後:
matchRate: 87,
画面上の表示が 87% Match に変わります。
チャレンジ4の答え
変更前:
homeCategory: HomeCategory.shows,
変更後:
homeCategory: HomeCategory.movies,
Home画面で Movies タブを押したときに、その作品が表示されるようになります。
この節のまとめ
この節では、MovieItem クラスを使って作品情報をひとまとまりにする方法を学びました。
大切なポイントは次の通りです。
MovieItemは、作品情報をまとめるためのクラス。title、description、posterUrl、youtubeVideoIdなどを1つの作品データとして持てる。Stringは文字、intは整数を表す。requiredがついている項目は、作品データを作るときに必ず必要。moviesリストに複数のMovieItemを入れることで、作品一覧を作れる。posterUrlは縦長画像、backdropUrlは横長背景画像に使う。youtubeVideoIdは、YouTube再生に使う。homeCategoryは、Home画面のカテゴリ切り替えに使う。- データを1か所にまとめると、いろいろな画面で使い回しやすい。
次のステップ
次の節では、movies リストに作品データを追加する方法を学びます。
今回学んだ MovieItem の設計図を使って、新しい作品を1つ追加してみます。
作品タイトル、画像URL、説明文、YouTube動画IDを入れて、自分だけの作品データを画面に表示していきましょう。
