
ListとMapで動画一覧の元データを作る
この節で学ぶこと
前回の 3-1 では、動画タイトル、チャンネル名、再生回数、投稿日、動画時間などを、ただのバラバラな値ではなく、「動画1本分の情報」として見る考え方を学びました。
今回は、そこから一歩進みます。
YouTube風アプリでは、動画は1本だけではありません。
画面には、複数の動画カードが縦に並びます。
完成アプリでは、次のように videos という動画一覧データを使っていました。
const videos = [
Video(
title: 'FlutterでYouTube風UIを作る|ListViewとCardの実践入門',
channelName: 'Code Studio',
views: 128000,
publishedAt: '2日前',
duration: '12:34',
category: 'Flutter',
thumbnailColor: Color(0xFF121212),
channelColor: Color(0xFFE53935),
isLive: false,
),
Video(
title: 'DartのListとMapをアプリ画面で使う方法をやさしく解説',
channelName: 'App School',
views: 8500,
publishedAt: '5日前',
duration: '08:21',
category: 'Dart',
thumbnailColor: Color(0xFF1E3A8A),
channelColor: Color(0xFF1565C0),
isLive: false,
),
];
このコードの中心にあるのが、List です。
この節では、List と Map を使って、複数の動画データをまとめて扱う方法を学びます。
この節のゴール
この節のゴールは、YouTube風UIに表示する「動画一覧の元データ」を理解できるようになることです。
最終的には、次の考え方が分かるようになります。
動画1本分のデータ
↓
Mapで1本分をまとめる
↓
Listで複数本をまとめる
↓
Listの中から1件ずつ取り出す
↓
動画一覧UIに表示する準備ができる
まだFlutterの画面表示を完全に作る必要はありません。
今回は、画面に表示する前の「データの並び」を理解する段階です。
まずListとは何か
List は、複数の値を順番にまとめておける箱です。
たとえば、動画タイトルが3つあるとします。
FlutterでYouTube風UIを作る
DartのListとMapを解説
UIデザインの基本
これをバラバラの変数で持つと、次のようになります。
void main() {
String title1 = 'FlutterでYouTube風UIを作る';
String title2 = 'DartのListとMapを解説';
String title3 = 'UIデザインの基本';
print(title1);
print(title2);
print(title3);
}
このコードは動きます。
しかし、動画タイトルが増えるたびに title4、title5、title6 と増えていきます。
そこで、List を使います。
void main() {
final titles = [
'FlutterでYouTube風UIを作る',
'DartのListとMapを解説',
'UIデザインの基本',
];
print(titles);
}
titles の中に、複数のタイトルがまとまりました。
titles
├─ FlutterでYouTube風UIを作る
├─ DartのListとMapを解説
└─ UIデザインの基本
Listは「順番のある一覧」
Listには、順番があります。
最初のデータは0番目、次は1番目、その次は2番目です。
void main() {
final titles = [
'FlutterでYouTube風UIを作る',
'DartのListとMapを解説',
'UIデザインの基本',
];
print(titles[0]);
print(titles[1]);
print(titles[2]);
}
出力結果は次のようになります。
FlutterでYouTube風UIを作る
DartのListとMapを解説
UIデザインの基本
ここで注意するのは、Listの番号は 1 からではなく 0 から始まることです。
| 書き方 | 取り出される値 |
|---|---|
titles[0] | 1つ目のタイトル |
titles[1] | 2つ目のタイトル |
titles[2] | 3つ目のタイトル |
初心者がよくつまずくところです。
Listの最初は0番目。
ここは、何度も出てきます。
Listの型を明示する
Dartでは、Listの中にどんな型のデータを入れるかを明示できます。
動画タイトルは文字列なので、List<String> と書けます。
void main() {
final List<String> titles = [
'FlutterでYouTube風UIを作る',
'DartのListとMapを解説',
'UIデザインの基本',
];
print(titles[0]);
}
List<String> は、次の意味です。
Stringの一覧
つまり、文字列が複数入ったListです。
| 書き方 | 意味 |
|---|---|
String | 文字列1つ |
List<String> | 文字列の一覧 |
int | 数字1つ |
List<int> | 数字の一覧 |
YouTube風アプリでは、複数の動画を扱います。
そのため、最終的には List<Video> が出てきます。
List<Video>
↓
Videoデータの一覧
for文でListを順番に取り出す
Listの便利なところは、中身を順番に取り出せることです。
void main() {
final List<String> titles = [
'FlutterでYouTube風UIを作る',
'DartのListとMapを解説',
'UIデザインの基本',
];
for (final title in titles) {
print(title);
}
}
このコードは、titles の中にあるタイトルを1つずつ取り出して表示します。
1回目:FlutterでYouTube風UIを作る
2回目:DartのListとMapを解説
3回目:UIデザインの基本
for (final title in titles) は、次のように読みます。
titlesの中から、titleを1つずつ取り出す
YouTube風UIでは、動画一覧の中から動画を1本ずつ取り出して、動画カードを作ります。
この考え方が、あとで ListView.builder につながります。
動画タイトルだけではカードは作れない
ここまで、動画タイトルだけをListにしました。
final titles = [
'FlutterでYouTube風UIを作る',
'DartのListとMapを解説',
'UIデザインの基本',
];
しかし、YouTube風の動画カードを作るには、タイトルだけでは足りません。
動画カードには、次の情報も必要です。
動画タイトル
チャンネル名
再生回数
投稿日
動画時間
カテゴリ
つまり、動画1本分の情報をまとめる必要があります。
そこで、Map を使います。
Mapとは何か
Map は、キーと値の組み合わせでデータを持つ仕組みです。
動画1本分の情報をMapで書くと、次のようになります。
void main() {
final video = {
'title': 'FlutterでYouTube風UIを作る',
'channelName': 'Code Studio',
'views': 128000,
'publishedAt': '2日前',
'duration': '12:34',
};
print(video['title']);
print(video['channelName']);
print(video['views']);
}
Mapは、次のように考えると分かりやすいです。
| キー | 値 |
|---|---|
| title | FlutterでYouTube風UIを作る |
| channelName | Code Studio |
| views | 128000 |
| publishedAt | 2日前 |
| duration | 12:34 |
video['title'] と書くと、title に対応する値を取り出せます。
print(video['title']);
これは、次のように読みます。
videoの中から、titleという名前の値を取り出す
ListとMapを組み合わせる
YouTube風アプリでは、動画1本だけではなく、複数の動画があります。
そのため、Map を List の中に入れます。
void main() {
final videos = [
{
'title': 'FlutterでYouTube風UIを作る',
'channelName': 'Code Studio',
'views': 128000,
'publishedAt': '2日前',
'duration': '12:34',
},
{
'title': 'DartのListとMapを解説',
'channelName': 'App School',
'views': 8500,
'publishedAt': '5日前',
'duration': '08:21',
},
{
'title': 'UIデザインの基本',
'channelName': 'Design Lab',
'views': 24000,
'publishedAt': '1週間前',
'duration': '15:10',
},
];
print(videos[0]['title']);
print(videos[1]['title']);
print(videos[2]['title']);
}
この構造を図で見ると、次のようになります。
videos
├─ 0番目のMap
│ ├─ title
│ ├─ channelName
│ ├─ views
│ ├─ publishedAt
│ └─ duration
├─ 1番目のMap
│ ├─ title
│ ├─ channelName
│ ├─ views
│ ├─ publishedAt
│ └─ duration
└─ 2番目のMap
├─ title
├─ channelName
├─ views
├─ publishedAt
└─ duration
これは、動画一覧アプリの元データにかなり近い形です。
videos[0][‘title’] の読み方
次のコードは、最初は少し読みにくいかもしれません。
videos[0]['title']
これは、2段階で読みます。
1. videos[0]
videosの0番目の動画データを取り出す
2. ['title']
その動画データの中からtitleを取り出す
つまり、全体では次の意味です。
動画一覧の中から、0番目の動画のタイトルを取り出す
同じように、
videos[1]['channelName']
これは次の意味です。
動画一覧の中から、1番目の動画のチャンネル名を取り出す
for文で動画一覧を表示する
ListとMapを組み合わせたら、for文で一覧表示できます。
void main() {
final videos = [
{
'title': 'FlutterでYouTube風UIを作る',
'channelName': 'Code Studio',
'views': 128000,
'publishedAt': '2日前',
'duration': '12:34',
},
{
'title': 'DartのListとMapを解説',
'channelName': 'App School',
'views': 8500,
'publishedAt': '5日前',
'duration': '08:21',
},
{
'title': 'UIデザインの基本',
'channelName': 'Design Lab',
'views': 24000,
'publishedAt': '1週間前',
'duration': '15:10',
},
];
for (final video in videos) {
print('${video['title']} / ${video['channelName']}');
}
}
出力結果は次のようになります。
FlutterでYouTube風UIを作る / Code Studio
DartのListとMapを解説 / App School
UIデザインの基本 / Design Lab
この処理は、YouTube風UIで動画カードを順番に並べる考え方と同じです。
videosの中から1件ずつ取り出す
↓
動画タイトルとチャンネル名を取り出す
↓
1件分の表示を作る
完成アプリとのつながり
完成アプリでは、Mapではなく Video classを使っています。
const videos = [
Video(
title: 'FlutterでYouTube風UIを作る|ListViewとCardの実践入門',
channelName: 'Code Studio',
views: 128000,
publishedAt: '2日前',
duration: '12:34',
category: 'Flutter',
thumbnailColor: Color(0xFF121212),
channelColor: Color(0xFFE53935),
isLive: false,
),
];
ただし、考え方は同じです。
| 今回の練習 | 完成アプリ |
|---|---|
List<Map> | List<Video> |
video['title'] | video.title |
| Mapで1本分をまとめる | Video classで1本分をまとめる |
| for文で1件ずつ取り出す | ListView.builderで1件ずつ表示する |
つまり、今回のListとMapは、完成アプリを理解するための準備です。
いきなり List<Video> を見ると難しく感じます。
しかし、まず List と Map を理解しておくと、次のように見えるようになります。
List:
複数のデータを並べるもの
Map:
1件分の情報を名前つきでまとめるもの
Video class:
Mapより安全に、1件分の動画情報をまとめるもの
ListView.builderとのつながり
完成アプリでは、次のコードが使われています。
ListView.builder(
itemCount: videos.length,
itemBuilder: (context, index) {
return VideoCard(video: videos[index]);
},
)
今はまだFlutterの詳しい説明はしません。
ただし、データの流れだけ見ておきます。
| コード | 意味 |
|---|---|
videos.length | 動画が何件あるか |
index | 何番目の動画か |
videos[index] | index番目の動画データ |
VideoCard(video: videos[index]) | その動画データをカードに渡す |
これは、Listの考え方そのものです。
3-2で videos[0]、videos[1] を理解しておくと、後で videos[index] が読みやすくなります。
lengthで件数を調べる
Listには、何件入っているかを調べる length があります。
void main() {
final titles = [
'FlutterでYouTube風UIを作る',
'DartのListとMapを解説',
'UIデザインの基本',
];
print(titles.length);
}
出力結果です。
3
titles.length は、「titlesの中に何件あるか」を表します。
完成アプリでは、これが動画カードの表示件数に使われます。
itemCount: videos.length
これは、次の意味です。
videosの件数分だけ、動画カードを作る
条件に合う動画だけを取り出す
Listでは、条件に合うデータだけを取り出すこともできます。
たとえば、再生回数が10000以上の動画だけを表示したいとします。
void main() {
final videos = [
{
'title': 'FlutterでYouTube風UIを作る',
'views': 128000,
},
{
'title': 'DartのListとMapを解説',
'views': 8500,
},
{
'title': 'UIデザインの基本',
'views': 24000,
},
];
for (final video in videos) {
final views = video['views'] as int;
if (views >= 10000) {
print(video['title']);
}
}
}
出力結果です。
FlutterでYouTube風UIを作る
UIデザインの基本
このように、Listを使うと、複数データの中から条件に合うものを選べます。
YouTube風アプリで言えば、人気動画だけを表示する、特定カテゴリだけを表示する、ライブ配信だけを表示する、といった処理につながります。
カテゴリで絞り込む
YouTube風アプリには、上部にカテゴリがあります。
完成アプリでは、次のようなカテゴリを使っています。
final categories = [
'すべて',
'Flutter',
'Dart',
'UI',
'ライブ',
'最近アップロード',
'視聴済み',
];
これは、カテゴリ名のListです。
動画データにも category を入れておけば、カテゴリで絞り込めます。
void main() {
final videos = [
{
'title': 'FlutterでYouTube風UIを作る',
'category': 'Flutter',
},
{
'title': 'DartのListとMapを解説',
'category': 'Dart',
},
{
'title': 'UIデザインの基本',
'category': 'UI',
},
];
for (final video in videos) {
if (video['category'] == 'Dart') {
print(video['title']);
}
}
}
出力結果です。
DartのListとMapを解説
このように、カテゴリもデータとして持っておくことで、表示の切り替えができるようになります。
Mapで型を扱うときの注意
Mapは便利ですが、値の型が混ざると注意が必要です。
final video = {
'title': 'FlutterでYouTube風UIを作る',
'views': 128000,
'isLive': false,
};
このMapには、複数の型が入っています。
| キー | 値 | 型 |
|---|---|---|
| title | FlutterでYouTube風UIを作る | String |
| views | 128000 | int |
| isLive | false | bool |
このようなMapから値を取り出すと、Dartは「どの型として使えばよいのか」を判断しにくい場合があります。
そのため、次のように型を指定することがあります。
final views = video['views'] as int;
これは、次の意味です。
video['views'] を int として扱う
このあたりが少し面倒になってきます。
だから、次の 3-3 以降で class を使います。
classを使うと取り出しが読みやすくなる
Mapでは、次のように取り出しました。
video['title']
video['views']
video['category']
classを使うと、次のように書けます。
video.title
video.views
video.category
かなり読みやすくなります。
| Map | class |
|---|---|
video['title'] | video.title |
video['views'] | video.views |
video['category'] | video.category |
| キーの打ち間違いが起きやすい | propertyとして扱える |
| 型が見えにくい | 型がはっきりする |
この節では、まずMapでデータのまとまりを理解しました。
次の 3-3 では、同じ考え方をclassで安全に書けるようにします。
DartPadで試すコード1:タイトル一覧を表示する
まずは、Listだけを使う練習です。
void main() {
final List<String> titles = [
'FlutterでYouTube風UIを作る',
'DartのListとMapを解説',
'UIデザインの基本',
];
for (final title in titles) {
print(title);
}
}
このコードで確認することは、次の2つです。
1. Listで複数のタイトルを持てる
2. for文で1つずつ取り出せる
DartPadで試すコード2:Mapで動画1本を表示する
次に、Mapで動画1本分をまとめます。
void main() {
final video = {
'title': 'FlutterでYouTube風UIを作る',
'channelName': 'Code Studio',
'views': 128000,
'publishedAt': '2日前',
'duration': '12:34',
};
print('${video['title']}');
print('${video['channelName']}');
print('${video['views']}回視聴・${video['publishedAt']}');
print('動画時間:${video['duration']}');
}
このコードで確認することは、次の2つです。
1. Mapで動画1本分の情報をまとめられる
2. キーを使って値を取り出せる
DartPadで試すコード3:ListとMapで動画一覧を表示する
最後に、ListとMapを組み合わせます。
void main() {
final videos = [
{
'title': 'FlutterでYouTube風UIを作る',
'channelName': 'Code Studio',
'views': 128000,
'publishedAt': '2日前',
'duration': '12:34',
},
{
'title': 'DartのListとMapを解説',
'channelName': 'App School',
'views': 8500,
'publishedAt': '5日前',
'duration': '08:21',
},
{
'title': 'UIデザインの基本',
'channelName': 'Design Lab',
'views': 24000,
'publishedAt': '1週間前',
'duration': '15:10',
},
];
for (final video in videos) {
print('--------------------');
print(video['title']);
print(video['channelName']);
print('${video['views']}回視聴・${video['publishedAt']}');
print('動画時間:${video['duration']}');
}
}
出力結果は次のようになります。
--------------------
FlutterでYouTube風UIを作る
Code Studio
128000回視聴・2日前
動画時間:12:34
--------------------
DartのListとMapを解説
App School
8500回視聴・5日前
動画時間:08:21
--------------------
UIデザインの基本
Design Lab
24000回視聴・1週間前
動画時間:15:10
この出力は、まだコンソール上の文字です。
しかし、考え方は動画一覧UIと同じです。
動画データを1件ずつ取り出す
↓
タイトルを表示する
↓
チャンネル名を表示する
↓
再生回数と投稿日を表示する
手を動かす練習1:カテゴリ一覧をListで作る
完成アプリのカテゴリバーに近いデータを作ります。
次のカテゴリをListで書いてください。
すべて
Flutter
Dart
UI
ライブ
解答例
void main() {
final categories = [
'すべて',
'Flutter',
'Dart',
'UI',
'ライブ',
];
for (final category in categories) {
print(category);
}
}
手を動かす練習2:動画1本をMapで作る
次の動画情報をMapで作ってください。
タイトル:ライブ:Flutter質問会
チャンネル名:Mobile Dev Live
再生回数:5600
投稿日:現在
動画時間:LIVE
カテゴリ:LIVE
ライブ中:true
解答例
void main() {
final video = {
'title': 'ライブ:Flutter質問会',
'channelName': 'Mobile Dev Live',
'views': 5600,
'publishedAt': '現在',
'duration': 'LIVE',
'category': 'LIVE',
'isLive': true,
};
print(video['title']);
print(video['channelName']);
print(video['isLive']);
}
手を動かす練習3:動画一覧をListで作る
次の2本の動画を、Listの中にMapとして入れてください。
動画1:
タイトル:FlutterでYouTube風UIを作る
チャンネル名:Code Studio
再生回数:128000
動画2:
タイトル:DartのListとMapを解説
チャンネル名:App School
再生回数:8500
解答例
void main() {
final videos = [
{
'title': 'FlutterでYouTube風UIを作る',
'channelName': 'Code Studio',
'views': 128000,
},
{
'title': 'DartのListとMapを解説',
'channelName': 'App School',
'views': 8500,
},
];
for (final video in videos) {
print('${video['title']} / ${video['channelName']}');
}
}
手を動かす練習4:人気動画だけ表示する
次の動画一覧から、再生回数が10000以上の動画だけを表示してください。
final videos = [
{
'title': 'FlutterでYouTube風UIを作る',
'views': 128000,
},
{
'title': 'DartのListとMapを解説',
'views': 8500,
},
{
'title': 'UIデザインの基本',
'views': 24000,
},
];
解答例
void main() {
final videos = [
{
'title': 'FlutterでYouTube風UIを作る',
'views': 128000,
},
{
'title': 'DartのListとMapを解説',
'views': 8500,
},
{
'title': 'UIデザインの基本',
'views': 24000,
},
];
for (final video in videos) {
final views = video['views'] as int;
if (views >= 10000) {
print(video['title']);
}
}
}
よくあるつまずき1:Listの番号は0から始まる
Listは、最初のデータが0番目です。
final titles = [
'Flutter',
'Dart',
'UI',
];
print(titles[0]);
出力されるのは、Flutter です。
| index | 値 |
|---|---|
| 0 | Flutter |
| 1 | Dart |
| 2 | UI |
titles[3] は存在しません。
3件あるからといって、最後が3番ではありません。
最後は2番です。
よくあるつまずき2:Mapのキーは正確に書く
Mapでは、キーを文字列で指定します。
video['title']
しかし、次のように間違えると正しく取り出せません。
video['titel']
title と titel は別物です。
Mapを使うときは、キーの名前をそろえることが大切です。
この弱点を減らすために、次の節ではclassを使います。
よくあるつまずき3:Mapの中の値の型が混ざる
Mapの中には、文字、数字、真偽値が混ざることがあります。
final video = {
'title': 'Flutter',
'views': 128000,
'isLive': false,
};
この場合、video['views'] を数字として使いたいときに、型の扱いでつまずくことがあります。
final views = video['views'] as int;
このような書き方が必要になる場合があります。
初心者にとっては少し面倒です。
だからこそ、最終的にはclassを使います。
よくあるつまずき4:ListとMapの役割が混ざる
ListとMapは、どちらもデータをまとめるために使います。
ただし、役割が違います。
| 使うもの | 役割 | YouTube風UIでの例 |
|---|---|---|
| List | 複数のデータを順番に持つ | 動画一覧、カテゴリ一覧 |
| Map | 1件分のデータを名前つきで持つ | 動画1本分の情報 |
初心者は、ここを混同しやすいです。
次のように考えると分かりやすいです。
List:
たくさん並べるもの
Map:
1つの中身を詳しく書くもの
動画一覧なら、こうなります。
List
├─ Map 動画1本目
├─ Map 動画2本目
└─ Map 動画3本目
この節で覚える対応表
| やりたいこと | 使うもの |
|---|---|
| 動画タイトルを1つ持つ | String |
| 動画タイトルを複数持つ | List<String> |
| 動画1本分の情報をまとめる | Map |
| 複数の動画情報をまとめる | List<Map> |
| 何件あるか調べる | .length |
| 何番目かを取り出す | [index] |
| Mapから値を取り出す | ['key'] |
| 1件ずつ処理する | for |
| 条件で表示する | if |
確認問題1
List はどのようなときに使いますか。
答え
複数のデータを順番にまとめて扱いたいときに使います。
YouTube風UIでは、動画一覧やカテゴリ一覧に使えます。
確認問題2
次のコードでは、何が表示されますか。
final titles = [
'Flutter',
'Dart',
'UI',
];
print(titles[1]);
答え
Dart
Listは0番目から始まるため、titles[1] は2つ目の値です。
確認問題3
Map はどのようなときに使いますか。
答え
1件分のデータを、キーと値の組み合わせでまとめたいときに使います。
YouTube風UIでは、動画1本分のタイトル、チャンネル名、再生回数などをまとめるときに使えます。
確認問題4
次のコードは何を取り出していますか。
videos[0]['title']
答え
動画一覧 videos の0番目の動画から、title を取り出しています。
つまり、最初の動画のタイトルです。
確認問題5
完成アプリでは、なぜ videos.length が必要になりますか。
答え
動画が何件あるかを知るためです。
ListView.builder では、videos.length を使って、動画の件数分だけカードを作ります。
この節のまとめ
この節では、YouTube風UIに必要な動画一覧データを作るために、List と Map を学びました。
List は、複数のデータを順番にまとめるために使います。
Map は、1件分のデータをキーと値でまとめるために使います。
動画一覧を考えるときは、次のような構造になります。
List
├─ Map 動画1本目
├─ Map 動画2本目
└─ Map 動画3本目
ただし、Mapはキーの打ち間違いや型の扱いでつまずきやすい面もあります。
そのため、完成アプリでは Video classを使って、動画1本分のデータをより安全に扱います。
この節で一番大切なのは、次の一文です。
YouTube風の動画一覧は、複数の動画データをListで並べたものとして考えられる。
次の 3-3 では、Mapでまとめていた動画1本分の情報を、Video classとして設計する方法を学びます。