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

methodで動画データに表示用のふるまいを持たせる

この節で学ぶこと

前回の 3-4 では、constructorproperty を使って、動画データの持ち物を決める方法を学びました。

たとえば、YouTube風アプリで使う Video classには、次のようなpropertyがありました。

class Video {
  const Video({
    required this.title,
    required this.channelName,
    required this.views,
    required this.publishedAt,
    required this.duration,
    required this.category,
    required this.thumbnailColor,
    required this.channelColor,
    required this.isLive,
  });

  final String title;
  final String channelName;
  final int views;
  final String publishedAt;
  final String duration;
  final String category;
  final Color thumbnailColor;
  final Color channelColor;
  final bool isLive;
}

ここまでで、動画1本分の情報をまとめて持てるようになりました。

しかし、実際のアプリでは、データをそのまま表示するだけでは足りないことがあります。

たとえば、再生回数が 128000 という数字で保存されているとします。

でも、画面には次のように表示したいです。

12.8万回視聴

また、通常動画なら、

12.8万回視聴・2日前

と表示したいです。

一方で、ライブ配信中の動画なら、

ライブ配信中

と表示したいです。

このように、保存しているデータを、画面に出しやすい形へ変えるときに使うのが methodgetter です。

この節のゴール

この節のゴールは、Video classの中に、表示用のふるまいを持たせる考え方を理解することです。

最終的には、完成アプリで使っている次のコードが読めるようになることを目指します。

String get viewLabel {
  if (views >= 100000000) {
    return '${(views / 100000000).toStringAsFixed(1)}億回視聴';
  }

  if (views >= 10000) {
    return '${(views / 10000).toStringAsFixed(1)}万回視聴';
  }

  return '$views回視聴';
}

String get metaLabel {
  if (isLive) {
    return 'ライブ配信中';
  }

  return '$viewLabel・$publishedAt';
}

このコードを初めて見ると、少し難しく感じるかもしれません。

でも、やっていることはとてもシンプルです。

再生回数の数字を、画面に出しやすい文字へ変える。
ライブ中なら、表示する文章を切り替える。

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

methodは、データに「できること」を持たせる仕組みである。

まずmethodとは何か

method とは、classの中に書く関数のようなものです。

関数は、処理をまとめるために使いました。

methodも似ています。

ただし、methodはclassの中に書きます。

たとえば、Video classの中に、動画の説明文を作るmethodを書いてみます。

class Video {
  const Video({
    required this.title,
    required this.channelName,
  });

  final String title;
  final String channelName;

  String description() {
    return '$title / $channelName';
  }
}

この中の次の部分がmethodです。

String description() {
  return '$title / $channelName';
}

これは、次の意味です。

titleとchannelNameを使って、動画の説明文を作る。

実際に使うと、次のようになります。

void main() {
  final video = Video(
    title: 'FlutterでYouTube風UIを作る',
    channelName: 'Code Studio',
  );

  print(video.description());
}

class Video {
  const Video({
    required this.title,
    required this.channelName,
  });

  final String title;
  final String channelName;

  String description() {
    return '$title / $channelName';
  }
}

出力結果です。

FlutterでYouTube風UIを作る / Code Studio

video.description() と書くと、Video の中にある description というmethodが実行されます。

propertyとmethodの違い

ここで、propertyとmethodの違いを整理します。

種類役割YouTube風アプリでの例
propertyデータそのものを持つtitleviewspublishedAt
methodデータを使って処理する表示用テキストを作る
gettermethodに近いが、propertyのように取り出せるviewLabelmetaLabel

たとえば、views はpropertyです。

final int views;

これは、再生回数そのものを持っています。

一方で、viewLabel は表示用の文字を作ります。

String get viewLabel {
  return '$views回視聴';
}

views は元データ。

viewLabel は画面に出すための表示用データです。

views:
128000

viewLabel:
128000回視聴

なぜmethodが必要なのか

動画データには、再生回数を数字として持たせます。

final int views;

たとえば、次のような値です。

128000
8500
24000

しかし、画面にそのまま出すと、少し不自然です。

128000
8500
24000

YouTube風の画面なら、次のように表示したいです。

12.8万回視聴
8500回視聴
2.4万回視聴

つまり、データとして持つ値と、画面に表示する文字は少し違います。

元データ表示したい文字
12800012.8万回視聴
85008500回視聴
240002.4万回視聴

この変換を毎回UI側に書くと、コードが読みにくくなります。

そこで、Video classの中に「表示用の文字を作る処理」を持たせます。

これがmethodやgetterの出番です。

まずは単純なmethodを書いてみる

最初は、再生回数に「回視聴」をつけるだけのmethodを書いてみます。

void main() {
  final video = Video(
    title: 'FlutterでYouTube風UIを作る',
    views: 128000,
  );

  print(video.createViewLabel());
}

class Video {
  const Video({
    required this.title,
    required this.views,
  });

  final String title;
  final int views;

  String createViewLabel() {
    return '$views回視聴';
  }
}

出力結果です。

128000回視聴

ここで大事なのは、views は数字として持っていることです。

final int views;

そして、表示するときだけ、文字に変えています。

return '$views回視聴';

このように、methodを使うと、データを表示用に整える処理をclassの中にまとめられます。

methodの書き方を分解する

次のmethodを分解して見ます。

String createViewLabel() {
  return '$views回視聴';
}
部分意味
Stringこのmethodは文字列を返す
createViewLabelmethodの名前
()今回は追加の材料を受け取らない
{ }処理を書く場所
return結果を返す
'$views回視聴'作りたい文字

つまり、このmethodは次のように読めます。

createViewLabelという処理を実行すると、
viewsに「回視聴」をつけた文字を返す。

使うときは、次のように書きます。

video.createViewLabel()

これは、次の意味です。

videoの中にあるcreateViewLabelを実行する

getterとは何か

完成アプリでは、methodではなく getter を使っています。

String get viewLabel {
  return '$views回視聴';
}

getter は、methodのように処理を書けます。

でも、使うときはpropertyのように書けます。

methodの場合です。

video.createViewLabel()

getterの場合です。

video.viewLabel

見た目が少し違います。

種類定義使い方
methodString createViewLabel()video.createViewLabel()
getterString get viewLabelvideo.viewLabel

初心者向けには、まず次の理解で大丈夫です。

getterは、計算して作るpropertyのようなもの。

つまり、viewLabel は実際に保存している値ではありません。

views から、その場で作っている表示用の値です。

getterで再生回数ラベルを作る

getterを使って、再生回数の表示用テキストを作ってみます。

void main() {
  final video = Video(
    title: 'FlutterでYouTube風UIを作る',
    views: 128000,
  );

  print(video.viewLabel);
}

class Video {
  const Video({
    required this.title,
    required this.views,
  });

  final String title;
  final int views;

  String get viewLabel {
    return '$views回視聴';
  }
}

出力結果です。

128000回視聴

viewLabel はpropertyのように使えます。

video.viewLabel

でも、実際には中で処理をしています。

return '$views回視聴';

methodとgetterはどちらを使うべきか

初心者のうちは、厳密に使い分けすぎなくて大丈夫です。

ただし、今回のように「データから表示用の値を作るだけ」の場合は、getterが読みやすいです。

やりたいことおすすめ
再生回数を表示用テキストにするgetter
投稿日と再生回数をまとめた文字を作るgetter
何かを実行する処理を書くmethod
外から値を受け取って計算するmethod

たとえば、完成アプリの viewLabelmetaLabel は、値を取り出しているように見えるため、getterにしています。

video.viewLabel
video.metaLabel

UI側から見ると、とても読みやすくなります。

再生回数を「万回視聴」に変える

ここから、完成アプリに近づけます。

再生回数が10000以上なら、万回視聴 にしたいとします。

128000 → 12.8万回視聴
24000 → 2.4万回視聴
8500 → 8500回視聴

まず、考え方を日本語で書きます。

もし views が 10000 以上なら、
views を 10000 で割って、「万回視聴」をつける。

そうでなければ、
そのまま「回視聴」をつける。

これをDartで書くと、次のようになります。

String get viewLabel {
  if (views >= 10000) {
    return '${(views / 10000).toStringAsFixed(1)}万回視聴';
  }

  return '$views回視聴';
}

少し長く見えますが、分解すれば大丈夫です。

if文で表示を切り替える

まず、if の部分を見ます。

if (views >= 10000) {
  return '${(views / 10000).toStringAsFixed(1)}万回視聴';
}

これは、次の意味です。

もし再生回数が10000以上なら、
万回視聴の形で返す。

views >= 10000 は条件です。

条件意味
views >= 10000viewsが10000以上
views < 10000viewsが10000未満

たとえば、views128000 なら、10000以上なので、ifの中が実行されます。

views8500 なら、10000未満なので、ifの中は実行されません。

views / 10000 の意味

次の部分を見ます。

views / 10000

これは、再生回数を10000で割っています。

たとえば、

128000 / 10000 = 12.8
24000 / 10000 = 2.4

これで、「何万回か」を出しています。

viewsviews / 10000
12800012.8
240002.4
100001.0

この数字に 万回視聴 をつければ、YouTube風の表示に近づきます。

toStringAsFixed(1) の意味

次に、この部分です。

.toStringAsFixed(1)

これは、小数点以下を1桁にそろえて文字に変える処理です。

たとえば、次のようになります。

数字toStringAsFixed(1)
12.812.8
2.42.4
11.0

今回の表示では、12.8万回視聴 のようにしたいので、小数1桁の文字にしています。

完成アプリでは、次のように使っています。

'${(views / 10000).toStringAsFixed(1)}万回視聴'

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

viewsを10000で割る。
小数1桁の文字にする。
その後ろに「万回視聴」をつける。

まずはDartPadで試すコード

ここまでの内容を、Dartだけで試せるコードにします。

void main() {
  final video = Video(
    title: 'FlutterでYouTube風UIを作る',
    views: 128000,
  );

  print(video.title);
  print(video.viewLabel);
}

class Video {
  const Video({
    required this.title,
    required this.views,
  });

  final String title;
  final int views;

  String get viewLabel {
    if (views >= 10000) {
      return '${(views / 10000).toStringAsFixed(1)}万回視聴';
    }

    return '$views回視聴';
  }
}

出力結果です。

FlutterでYouTube風UIを作る
12.8万回視聴

ここで確認することは、次の3つです。

viewsは128000という数字で持っている。
viewLabelは12.8万回視聴という文字を作る。
元データと表示用テキストを分けている。

複数の動画で試す

次に、複数の動画で試してみます。

void main() {
  final videos = [
    Video(
      title: 'FlutterでYouTube風UIを作る',
      views: 128000,
    ),
    Video(
      title: 'DartのListとMapを解説',
      views: 8500,
    ),
    Video(
      title: 'UIデザインの基本',
      views: 24000,
    ),
  ];

  for (final video in videos) {
    print('${video.title} / ${video.viewLabel}');
  }
}

class Video {
  const Video({
    required this.title,
    required this.views,
  });

  final String title;
  final int views;

  String get viewLabel {
    if (views >= 10000) {
      return '${(views / 10000).toStringAsFixed(1)}万回視聴';
    }

    return '$views回視聴';
  }
}

出力結果です。

FlutterでYouTube風UIを作る / 12.8万回視聴
DartのListとMapを解説 / 8500回視聴
UIデザインの基本 / 2.4万回視聴

同じ viewLabel を使っているのに、動画ごとの再生回数に合わせて表示が変わっています。

これが、classにふるまいを持たせる便利さです。

ここまでの整理

元データgetter表示結果
views: 128000viewLabel12.8万回視聴
views: 8500viewLabel8500回視聴
views: 24000viewLabel2.4万回視聴

views は、計算しやすいように数字で持ちます。

viewLabel は、画面に出しやすいように文字で作ります。

データとして持つもの:
views

画面に出すために作るもの:
viewLabel

1億回以上にも対応する

完成アプリでは、1億回以上の再生回数にも対応しています。

String get viewLabel {
  if (views >= 100000000) {
    return '${(views / 100000000).toStringAsFixed(1)}億回視聴';
  }

  if (views >= 10000) {
    return '${(views / 10000).toStringAsFixed(1)}万回視聴';
  }

  return '$views回視聴';
}

条件が2つあります。

条件表示
views >= 100000000億回視聴
views >= 10000万回視聴
それ以外回視聴

この順番も重要です。

先に1億以上かどうかを確認します。

そのあと、1万以上かどうかを確認します。

条件の順番に注意する

もし、先に1万以上を確認してしまうと、1億以上の動画もそこで止まってしまいます。

悪い例です。

String get viewLabel {
  if (views >= 10000) {
    return '${(views / 10000).toStringAsFixed(1)}万回視聴';
  }

  if (views >= 100000000) {
    return '${(views / 100000000).toStringAsFixed(1)}億回視聴';
  }

  return '$views回視聴';
}

この場合、views120000000 でも、最初の views >= 10000 に当てはまってしまいます。

そのため、億回視聴 の判定まで進みません。

だから、大きい条件から先に書きます。

1億以上か確認
↓
1万以上か確認
↓
それ以外

この考え方は、プログラミングでとても大切です。

前半のまとめ

この前半では、methodgetter の基本を学びました。

大切なポイントは、次の通りです。

- methodは、classの中に書く処理である
- getterは、計算して作るpropertyのように使える
- viewsは数字として持つ
- viewLabelは、画面に表示する文字として作る
- 10000以上なら「万回視聴」に変換できる
- 条件分岐では、判定する順番が大切

YouTube風アプリでは、動画データをそのまま表示するだけではありません。

views のような元データを、viewLabel のような表示用テキストに変換して使います。

metaLabelを作る

前半では、views という数字から、viewLabel という表示用テキストを作りました。

String get viewLabel {
  if (views >= 100000000) {
    return '${(views / 100000000).toStringAsFixed(1)}億回視聴';
  }

  if (views >= 10000) {
    return '${(views / 10000).toStringAsFixed(1)}万回視聴';
  }

  return '$views回視聴';
}

これで、次のような表示が作れます。

128000 → 12.8万回視聴
8500 → 8500回視聴
24000 → 2.4万回視聴

しかし、YouTube風の動画カードでは、再生回数だけではなく、投稿日も一緒に表示したいです。

たとえば、次のような表示です。

12.8万回視聴・2日前

このような、再生回数と投稿日をまとめた表示用テキストを metaLabel として作ります。

metaLabelとは何か

metaLabel は、動画タイトルの下に表示する補足情報のようなものです。

完成アプリでは、動画カードの下に次のような情報が表示されます。

Code Studio
12.8万回視聴・2日前

このうち、下の行が metaLabel です。

12.8万回視聴・2日前

元になるデータは、次の2つです。

元データ意味
viewLabel再生回数を表示用にした文字
publishedAt投稿日

この2つを組み合わせて、metaLabel を作ります。

String get metaLabel {
  return '$viewLabel・$publishedAt';
}

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

viewLabelとpublishedAtをつなげて、動画の補足情報を作る。

metaLabelをDartPadで試す

まずは、ライブ判定なしのシンプルな形で試します。

void main() {
  final video = Video(
    title: 'FlutterでYouTube風UIを作る',
    views: 128000,
    publishedAt: '2日前',
  );

  print(video.title);
  print(video.viewLabel);
  print(video.metaLabel);
}

class Video {
  const Video({
    required this.title,
    required this.views,
    required this.publishedAt,
  });

  final String title;
  final int views;
  final String publishedAt;

  String get viewLabel {
    if (views >= 100000000) {
      return '${(views / 100000000).toStringAsFixed(1)}億回視聴';
    }

    if (views >= 10000) {
      return '${(views / 10000).toStringAsFixed(1)}万回視聴';
    }

    return '$views回視聴';
  }

  String get metaLabel {
    return '$viewLabel・$publishedAt';
  }
}

出力結果です。

FlutterでYouTube風UIを作る
12.8万回視聴
12.8万回視聴・2日前

ここで大切なのは、metaLabel の中で viewLabel を使っていることです。

return '$viewLabel・$publishedAt';

つまり、getterの中で、別のgetterを使うこともできます。

viewLabelとmetaLabelの関係

viewLabelmetaLabel の役割を整理します。

getter役割表示例
viewLabel再生回数だけを表示用にする12.8万回視聴
metaLabel再生回数と投稿日をまとめる12.8万回視聴・2日前

流れとしては、こうです。

views
↓
viewLabel
↓
metaLabel

もう少し具体的に見ると、次のようになります。

128000
↓
12.8万回視聴
↓
12.8万回視聴・2日前

このように、元データを少しずつ画面用の文字に整えていきます。

ライブ配信の場合を考える

完成アプリには、通常動画だけでなく、ライブ配信中の動画もあります。

たとえば、次のような動画です。

Video(
  title: 'ライブ:Flutter質問会|Widget・ListView・classの疑問を解決',
  channelName: 'Mobile Dev Live',
  views: 5600,
  publishedAt: '現在',
  duration: 'LIVE',
  category: 'LIVE',
  isLive: true,
)

この動画はライブ配信中なので、普通の動画のように、

5600回視聴・現在

と出すよりも、

ライブ配信中

と表示したほうが自然です。

つまり、isLive の値によって表示を切り替えます。

isLive表示したいmetaLabel
trueライブ配信中
false12.8万回視聴・2日前

isLiveで表示を切り替える

isLivebool 型です。

true または false のどちらかを持ちます。

final bool isLive;

metaLabel の中で、この isLive を使って条件分岐します。

String get metaLabel {
  if (isLive) {
    return 'ライブ配信中';
  }

  return '$viewLabel・$publishedAt';
}

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

もしライブ配信中なら、「ライブ配信中」と返す。

そうでなければ、再生回数と投稿日をつなげて返す。

if (isLive) は、次の意味です。

isLiveがtrueなら

つまり、

if (isLive) {
  return 'ライブ配信中';
}

は、

ライブ中なら、この時点で「ライブ配信中」を返して終わる。

という意味です。

ライブ表示をDartPadで試す

通常動画とライブ動画を比べてみます。

void main() {
  final normalVideo = Video(
    title: 'FlutterでYouTube風UIを作る',
    views: 128000,
    publishedAt: '2日前',
    isLive: false,
  );

  final liveVideo = Video(
    title: 'ライブ:Flutter質問会',
    views: 5600,
    publishedAt: '現在',
    isLive: true,
  );

  print(normalVideo.title);
  print(normalVideo.metaLabel);

  print('---');

  print(liveVideo.title);
  print(liveVideo.metaLabel);
}

class Video {
  const Video({
    required this.title,
    required this.views,
    required this.publishedAt,
    required this.isLive,
  });

  final String title;
  final int views;
  final String publishedAt;
  final bool isLive;

  String get viewLabel {
    if (views >= 100000000) {
      return '${(views / 100000000).toStringAsFixed(1)}億回視聴';
    }

    if (views >= 10000) {
      return '${(views / 10000).toStringAsFixed(1)}万回視聴';
    }

    return '$views回視聴';
  }

  String get metaLabel {
    if (isLive) {
      return 'ライブ配信中';
    }

    return '$viewLabel・$publishedAt';
  }
}

出力結果です。

FlutterでYouTube風UIを作る
12.8万回視聴・2日前
---
ライブ:Flutter質問会
ライブ配信中

同じ metaLabel を使っているのに、isLive の値によって表示が変わっています。

ここが、getterにふるまいを持たせる面白いところです。

なぜUI側に直接書かないのか

ここで、疑問が出るかもしれません。

「表示を切り替えるなら、画面側で直接書けばよいのでは?」

たしかに、それもできます。

たとえば、Flutterの画面側で次のように書くこともできます。

Text(
  video.isLive
      ? 'ライブ配信中'
      : '${video.viewLabel}・${video.publishedAt}',
)

しかし、画面側にこのような処理が増えると、UIコードが読みにくくなります。

画面側では、本来は「何を表示するか」をできるだけシンプルに書きたいです。

Text(video.metaLabel)

このように書けると、かなり読みやすくなります。

書き方読みやすさ
Text(video.isLive ? 'ライブ配信中' : '${video.viewLabel}・${video.publishedAt}')条件が混ざっていて少し読みにくい
Text(video.metaLabel)何を表示するかが分かりやすい

そのため、表示用のルールは Video classの中にまとめておくと便利です。

データ側にふるまいを持たせる考え方

ここまでで、Video classには2種類のものが入っていることが分かります。

1つ目は、元データです。

final String title;
final int views;
final String publishedAt;
final bool isLive;

2つ目は、元データから作る表示用の値です。

String get viewLabel { ... }
String get metaLabel { ... }

整理すると、次のようになります。

種類役割
propertyviews元データを持つ
getterviewLabel元データを表示用に変える
gettermetaLabel複数の元データから表示文を作る

このように、classには「持ち物」だけでなく、「ふるまい」も持たせることができます。

Videoは、viewsを持っている。
Videoは、viewsを使ってviewLabelを作れる。
Videoは、isLiveを見てmetaLabelを切り替えられる。

これが、methodで動画データに表示用のふるまいを持たせる という意味です。

完成アプリのVideo classに近づける

完成アプリの Video classは、次のようになっていました。

class Video {
  const Video({
    required this.title,
    required this.channelName,
    required this.views,
    required this.publishedAt,
    required this.duration,
    required this.category,
    required this.thumbnailColor,
    required this.channelColor,
    required this.isLive,
  });

  final String title;
  final String channelName;
  final int views;
  final String publishedAt;
  final String duration;
  final String category;
  final Color thumbnailColor;
  final Color channelColor;
  final bool isLive;

  String get viewLabel {
    if (views >= 100000000) {
      return '${(views / 100000000).toStringAsFixed(1)}億回視聴';
    }

    if (views >= 10000) {
      return '${(views / 10000).toStringAsFixed(1)}万回視聴';
    }

    return '$views回視聴';
  }

  String get metaLabel {
    if (isLive) {
      return 'ライブ配信中';
    }

    return '$viewLabel・$publishedAt';
  }
}

これを大きく分けると、次の3つです。

部分役割
constructorVideo を作るときに値を受け取る
property動画の元データを持つ
getter画面に表示しやすい文字を作る

つまり、Video classは、ただの入れ物ではありません。

画面表示に必要な小さな処理も持っています。

VideoInfoではmetaLabelを使う

完成アプリの VideoInfo では、次のように metaLabel を使っています。

Text(
  video.metaLabel,
  maxLines: 1,
  overflow: TextOverflow.ellipsis,
)

ここでは、video.metaLabel と書くだけで、通常動画とライブ動画の表示を切り替えられます。

通常動画なら、

12.8万回視聴・2日前

ライブ動画なら、

ライブ配信中

になります。

UI側のコードは、細かい条件を知る必要がありません。

Video classが、表示用の文字を用意してくれているからです。

Thumbnailではdurationを使う

完成アプリでは、サムネイル右下に動画時間を表示しています。

通常動画なら、次のような表示です。

12:34
08:21
15:10

この表示には、duration propertyを使います。

Text(video.duration)

一方、ライブ配信の場合は、durationLIVE を入れています。

duration: 'LIVE',

さらに、画面側では isLive を使って、赤い「ライブ」ラベルを出す処理もできます。

isLiveがtrue
↓
赤いライブ表示

isLiveがfalse
↓
黒い動画時間表示

ここでも、Video のpropertyがUIに使われています。

methodとgetterの考え方をもう一度整理する

ここで、methodとgetterの違いをもう一度整理します。

method

methodは、処理を実行する形です。

String createViewLabel() {
  return '$views回視聴';
}

使うときは、丸かっこをつけます。

video.createViewLabel()

getter

getterは、処理を書けますが、propertyのように取り出せます。

String get viewLabel {
  return '$views回視聴';
}

使うときは、丸かっこをつけません。

video.viewLabel

今回のように「表示用の値を取り出したい」場合は、getterが自然です。

手を動かす練習1:単純なviewLabelを作る

まず、再生回数に「回視聴」をつけるだけのgetterを書いてください。

解答例

void main() {
  final video = Video(
    title: 'Dartのmethod入門',
    views: 8500,
  );

  print(video.viewLabel);
}

class Video {
  const Video({
    required this.title,
    required this.views,
  });

  final String title;
  final int views;

  String get viewLabel {
    return '$views回視聴';
  }
}

出力結果です。

8500回視聴

手を動かす練習2:10000以上なら万回視聴にする

次に、10000以上なら 万回視聴 に変換してください。

解答例

void main() {
  final video = Video(
    title: 'UIデザインの基本',
    views: 24000,
  );

  print(video.viewLabel);
}

class Video {
  const Video({
    required this.title,
    required this.views,
  });

  final String title;
  final int views;

  String get viewLabel {
    if (views >= 10000) {
      return '${(views / 10000).toStringAsFixed(1)}万回視聴';
    }

    return '$views回視聴';
  }
}

出力結果です。

2.4万回視聴

手を動かす練習3:metaLabelを作る

viewLabelpublishedAt を使って、metaLabel を作ってください。

解答例

void main() {
  final video = Video(
    title: 'FlutterでYouTube風UIを作る',
    views: 128000,
    publishedAt: '2日前',
  );

  print(video.metaLabel);
}

class Video {
  const Video({
    required this.title,
    required this.views,
    required this.publishedAt,
  });

  final String title;
  final int views;
  final String publishedAt;

  String get viewLabel {
    if (views >= 10000) {
      return '${(views / 10000).toStringAsFixed(1)}万回視聴';
    }

    return '$views回視聴';
  }

  String get metaLabel {
    return '$viewLabel・$publishedAt';
  }
}

出力結果です。

12.8万回視聴・2日前

手を動かす練習4:isLiveで表示を切り替える

isLivetrue のときは ライブ配信中false のときは 再生回数・投稿日 を表示してください。

解答例

void main() {
  final normalVideo = Video(
    title: 'FlutterでYouTube風UIを作る',
    views: 128000,
    publishedAt: '2日前',
    isLive: false,
  );

  final liveVideo = Video(
    title: 'ライブ:Flutter質問会',
    views: 5600,
    publishedAt: '現在',
    isLive: true,
  );

  print(normalVideo.metaLabel);
  print(liveVideo.metaLabel);
}

class Video {
  const Video({
    required this.title,
    required this.views,
    required this.publishedAt,
    required this.isLive,
  });

  final String title;
  final int views;
  final String publishedAt;
  final bool isLive;

  String get viewLabel {
    if (views >= 10000) {
      return '${(views / 10000).toStringAsFixed(1)}万回視聴';
    }

    return '$views回視聴';
  }

  String get metaLabel {
    if (isLive) {
      return 'ライブ配信中';
    }

    return '$viewLabel・$publishedAt';
  }
}

出力結果です。

12.8万回視聴・2日前
ライブ配信中

手を動かす練習5:複数動画でmetaLabelを表示する

複数の動画をListに入れて、タイトルと metaLabel を表示してください。

解答例

void main() {
  final videos = [
    Video(
      title: 'FlutterでYouTube風UIを作る',
      views: 128000,
      publishedAt: '2日前',
      isLive: false,
    ),
    Video(
      title: 'DartのListとMapを解説',
      views: 8500,
      publishedAt: '5日前',
      isLive: false,
    ),
    Video(
      title: 'ライブ:Flutter質問会',
      views: 5600,
      publishedAt: '現在',
      isLive: true,
    ),
  ];

  for (final video in videos) {
    print('${video.title} / ${video.metaLabel}');
  }
}

class Video {
  const Video({
    required this.title,
    required this.views,
    required this.publishedAt,
    required this.isLive,
  });

  final String title;
  final int views;
  final String publishedAt;
  final bool isLive;

  String get viewLabel {
    if (views >= 10000) {
      return '${(views / 10000).toStringAsFixed(1)}万回視聴';
    }

    return '$views回視聴';
  }

  String get metaLabel {
    if (isLive) {
      return 'ライブ配信中';
    }

    return '$viewLabel・$publishedAt';
  }
}

出力結果です。

FlutterでYouTube風UIを作る / 12.8万回視聴・2日前
DartのListとMapを解説 / 8500回視聴・5日前
ライブ:Flutter質問会 / ライブ配信中

このように、getterをclassの中に書いておくと、複数の動画でも同じルールで表示できます。

よくあるつまずき1:methodとgetterの違いが分からない

methodとgetterは似ています。

ただし、使うときの書き方が違います。

種類定義使い方
methodString createViewLabel()video.createViewLabel()
getterString get viewLabelvideo.viewLabel

今回のように、表示用の値を取り出したいだけなら、getterが読みやすいです。

Text(video.metaLabel)

UI側では、このようにすっきり書けます。

よくあるつまずき2:returnの意味が分からない

getterやmethodでは、return が出てきます。

return '$views回視聴';

return は、「この結果を返す」という意味です。

たとえば、

String get viewLabel {
  return '$views回視聴';
}

これは、次の意味です。

viewLabelを呼び出したら、
'$views回視聴' という文字を結果として返す。

return がないと、作った結果を外で使えません。

よくあるつまずき3:文字列の中に変数を入れる書き方

Dartでは、文字列の中に変数を入れるときに $ を使います。

return '$views回視聴';

これは、views の値を文字の中に入れています。

たとえば、views8500 なら、

8500回視聴

になります。

少し複雑な計算を入れるときは、${} を使います。

return '${(views / 10000).toStringAsFixed(1)}万回視聴';

これは、次の意味です。

views / 10000 を計算する。
小数1桁にする。
その結果を文字列の中に入れる。

よくあるつまずき4:if文の順番を間違える

前半でも扱いましたが、1億回以上と1万回以上を判定するときは、大きい条件から書きます。

正しい例です。

String get viewLabel {
  if (views >= 100000000) {
    return '${(views / 100000000).toStringAsFixed(1)}億回視聴';
  }

  if (views >= 10000) {
    return '${(views / 10000).toStringAsFixed(1)}万回視聴';
  }

  return '$views回視聴';
}

先に views >= 10000 を書くと、1億以上の数字もそこで当てはまってしまいます。

条件分岐は、順番も大切。

この考え方は、今後のプログラムでもよく使います。

よくあるつまずき5:UI側とデータ側の役割が混ざる

初心者は、画面側にすべての処理を書いてしまいがちです。

たとえば、次のような書き方です。

Text(
  video.isLive
      ? 'ライブ配信中'
      : '${video.viewLabel}・${video.publishedAt}',
)

これは動きます。

しかし、UI側が少し読みにくくなります。

そこで、Video class側に metaLabel を作ります。

String get metaLabel {
  if (isLive) {
    return 'ライブ配信中';
  }

  return '$viewLabel・$publishedAt';
}

すると、UI側はこう書けます。

Text(video.metaLabel)

画面側は表示に集中し、データ側で表示用の値を作る。

この分け方ができると、コードがかなり読みやすくなります。

完成アプリとのつながり

完成アプリの VideoInfo では、次のように metaLabel を表示します。

Text(
  video.metaLabel,
  maxLines: 1,
  overflow: TextOverflow.ellipsis,
  style: TextStyle(
    color: video.isLive ? Color(0xFFE62117) : Color(0xFF606060),
    fontSize: 13,
    fontWeight: video.isLive ? FontWeight.w700 : FontWeight.w400,
    height: 1.25,
  ),
)

このコードの中で、表示する文字そのものは video.metaLabel が作っています。

通常動画なら、

12.8万回視聴・2日前

ライブ動画なら、

ライブ配信中

になります。

さらに、video.isLive を使って、文字色や太さも変えています。

isLiveがtrue
↓
赤く太い文字

isLiveがfalse
↓
グレーの通常文字

つまり、Video のデータとgetterが、UIの表示にそのままつながっています。

この節で覚える対応表

やりたいこと使うもの
再生回数の数字を持つpropertyviews
再生回数を表示用にするgetterviewLabel
投稿日と再生回数をまとめるgettermetaLabel
ライブ中か判定するboolisLive
表示を切り替えるif文if (isLive)
結果を返すreturnreturn 'ライブ配信中';
UIで表示するTextText(video.metaLabel)

確認問題1

method とは何ですか。

答え

classの中に書く処理です。

そのclassが持っているデータを使って、計算したり、表示用の文字を作ったりできます。

確認問題2

getter はどのように使いますか。

答え

propertyのように、丸かっこをつけずに使います。

video.viewLabel

viewLabel は保存された値ではなく、views から作られる表示用の値です。

確認問題3

次のコードは何をしていますか。

String get viewLabel {
  return '$views回視聴';
}

答え

views の値に「回視聴」をつけて、表示用の文字を作っています。

たとえば、views8500 なら、8500回視聴 になります。

確認問題4

次のコードで、isLivetrue のとき何が返りますか。

String get metaLabel {
  if (isLive) {
    return 'ライブ配信中';
  }

  return '$viewLabel・$publishedAt';
}

答え

ライブ配信中

が返ります。

確認問題5

なぜ metaLabelVideo classの中に作ると便利ですか。

答え

UI側で毎回条件分岐を書かなくてよくなるからです。

Text(video.metaLabel) と書くだけで、通常動画なら再生回数と投稿日、ライブ動画なら「ライブ配信中」を表示できます。

この節のまとめ

この節では、methodgetter を使って、動画データに表示用のふるまいを持たせる方法を学びました。

views は、再生回数の元データです。

viewLabel は、views を画面に出しやすい文字へ変えたものです。

metaLabel は、動画の補足情報として表示する文字です。

通常動画なら、

12.8万回視聴・2日前

ライブ動画なら、

ライブ配信中

と表示できます。

この節のポイント:
- methodは、classの中に書く処理である
- getterは、計算して作るpropertyのように使える
- viewsは数字として持つ
- viewLabelは画面表示用の文字を作る
- metaLabelは再生回数・投稿日・ライブ状態を見て表示を切り替える
- UI側では Text(video.metaLabel) のようにシンプルに使える

大事なことは、

Video classは、動画のデータを持つだけでなく、画面に表示しやすい形へ整えるふるまいも持てる。

次の 3-6 では、final や getter の考え方をさらに使いながら、データを安全に扱うためのカプセル化を学びます。

教材トップへ戻る