Flutterアプリケーション開発概論

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 です。

この節では、ListMap を使って、複数の動画データをまとめて扱う方法を学びます。

この節のゴール

この節のゴールは、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);
}

このコードは動きます。

しかし、動画タイトルが増えるたびに title4title5title6 と増えていきます。

そこで、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は、次のように考えると分かりやすいです。

キー
titleFlutterでYouTube風UIを作る
channelNameCode Studio
views128000
publishedAt2日前
duration12:34

video['title'] と書くと、title に対応する値を取り出せます。

print(video['title']);

これは、次のように読みます。

videoの中から、titleという名前の値を取り出す

ListとMapを組み合わせる

YouTube風アプリでは、動画1本だけではなく、複数の動画があります。

そのため、MapList の中に入れます。

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> を見ると難しく感じます。

しかし、まず ListMap を理解しておくと、次のように見えるようになります。

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には、複数の型が入っています。

キー
titleFlutterでYouTube風UIを作るString
views128000int
isLivefalsebool

このような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

かなり読みやすくなります。

Mapclass
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
0Flutter
1Dart
2UI

titles[3] は存在しません。

3件あるからといって、最後が3番ではありません。

最後は2番です。

よくあるつまずき2:Mapのキーは正確に書く

Mapでは、キーを文字列で指定します。

video['title']

しかし、次のように間違えると正しく取り出せません。

video['titel']

titletitel は別物です。

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複数のデータを順番に持つ動画一覧、カテゴリ一覧
Map1件分のデータを名前つきで持つ動画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に必要な動画一覧データを作るために、ListMap を学びました。

List は、複数のデータを順番にまとめるために使います。

Map は、1件分のデータをキーと値でまとめるために使います。

動画一覧を考えるときは、次のような構造になります。

List
├─ Map 動画1本目
├─ Map 動画2本目
└─ Map 動画3本目

ただし、Mapはキーの打ち間違いや型の扱いでつまずきやすい面もあります。

そのため、完成アプリでは Video classを使って、動画1本分のデータをより安全に扱います。

この節で一番大切なのは、次の一文です。

YouTube風の動画一覧は、複数の動画データをListで並べたものとして考えられる。

次の 3-3 では、Mapでまとめていた動画1本分の情報を、Video classとして設計する方法を学びます。

教材トップへ戻る