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

【TeamCard】チームをLINEのトーク一覧風に表示する

23LINE風チームタスク管理アプリを作りながら、ログイン・データベース・権限管理を学ぶ
FlutteriOSAndroidMacOSWindows基礎から学ぶ開発アプリ開発

このページでやること

このページでは、チーム一覧の1件分を表示する TeamCard を作ります。

TeamCard とは、チーム名をLINEのトーク一覧のように表示するための部品です。

前のページでは、Firestoreから参加中チームを取得しました。

今回は、その取得したチームを見やすく表示します。

参加中チームを取得
↓
1件ずつTeamCardで表示
↓
LINEのトーク一覧風に見える

今日のゴール

チーム一覧が、次のように表示されるようにします。

〇 開発チーム                >
〇 営業チーム                >
〇 デザイン確認チーム         >

見た目のイメージは、LINEのトーク一覧です。

左:丸いアイコン
中央:チーム名
右:矢印

このページで出てくる単語

単語一言説明
TeamCardチーム1件分を表示する部品
CircleAvatar丸いアイコンを作るWidget
Row横並びにするWidget
Expanded残りの横幅を使うWidget
onTapタップしたときの処理
VoidCallback引数なし・戻り値なしの処理
Iconアイコンを表示するWidget

Widget とは、Flutterの画面部品のことです。


npmや環境変数はこのページで必要?

このページでは、npmは使いません。

環境変数も設定しません。

このページでやることは、main.dartTeamCard を追加して、チーム一覧で使うことです。

main.dartを開く
↓
TeamCardを作る
↓
ListViewの中でTeamCardを使う
↓
保存する
↓
flutter runで確認する

Step 1:main.dartを開く

次のファイルを開きます。

lib/main.dart

VS Codeを使っている場合は、ターミナルで次を実行してもOKです。

code lib/main.dart

Step 2:TeamCardを追加する

AppCardErrorBox の近くに、次のコードを追加します。

class TeamCard extends StatelessWidget {
  const TeamCard({
    super.key,
    required this.name,
    required this.onTap,
  });

  final String name;
  final VoidCallback onTap;

  @override
  Widget build(BuildContext context) {
    final initial = name.isNotEmpty ? name.characters.first : '?';

    return AppCard(
      onTap: onTap,
      child: Row(
        children: [
          CircleAvatar(
            backgroundColor: AppColors.lineGreen,
            child: Text(
              initial,
              style: const TextStyle(
                color: Colors.white,
                fontWeight: FontWeight.w900,
              ),
            ),
          ),
          const SizedBox(width: 12),
          Expanded(
            child: Text(
              name,
              maxLines: 1,
              overflow: TextOverflow.ellipsis,
              style: const TextStyle(
                color: AppColors.text,
                fontSize: 16,
                fontWeight: FontWeight.w900,
              ),
            ),
          ),
          const Icon(
            Icons.chevron_right,
            color: AppColors.subText,
          ),
        ],
      ),
    );
  }
}

これで、チーム1件分の見た目をまとめられます。


Step 3:TeamCardの中身を確認する

TeamCard の中身は、次の3つです。

左:CircleAvatar
中央:Text
右:Icon

コードでは、この部分です。

Row(
  children: [
    CircleAvatar(...),
    SizedBox(width: 12),
    Expanded(child: Text(...)),
    Icon(Icons.chevron_right),
  ],
)

Row は、部品を横に並べるWidgetです。


Step 4:丸いアイコンを作る

この部分です。

CircleAvatar(
  backgroundColor: AppColors.lineGreen,
  child: Text(
    initial,
    style: const TextStyle(
      color: Colors.white,
      fontWeight: FontWeight.w900,
    ),
  ),
),

CircleAvatar は、丸いアイコンを作るWidgetです。

今回は、チーム名の1文字目を丸の中に表示します。

たとえば、

開発チーム → 開
営業チーム → 営

という表示になります。


Step 5:チーム名を表示する

この部分です。

Expanded(
  child: Text(
    name,
    maxLines: 1,
    overflow: TextOverflow.ellipsis,
    style: const TextStyle(
      color: AppColors.text,
      fontSize: 16,
      fontWeight: FontWeight.w900,
    ),
  ),
),

Expanded は、残りの横幅を使うためのWidgetです。

maxLines: 1 は、1行だけ表示する設定です。

overflow: TextOverflow.ellipsis は、長い文字を ... で省略する設定です。

たとえば、

とても長いチーム名ですこれは...

のように表示されます。


Step 6:右側に矢印を出す

この部分です。

const Icon(
  Icons.chevron_right,
  color: AppColors.subText,
),

Icons.chevron_right は、右向き矢印のアイコンです。

これがあると、ユーザーに「タップできる」と伝わりやすくなります。


Step 7:ListViewの中でTeamCardを使う

前のページでは、チーム一覧の中で AppCard を直接使っていました。

この部分を探してください。

return AppCard(
  onTap: () {
    // 次のページでタスク一覧画面へ移動します
  },
  child: Row(
    children: [
      CircleAvatar(
        backgroundColor: AppColors.lineGreen,
        child: Text(
          name.isNotEmpty ? name.characters.first : '?',
          style: const TextStyle(
            color: Colors.white,
            fontWeight: FontWeight.w900,
          ),
        ),
      ),
      const SizedBox(width: 12),
      Expanded(
        child: Text(
          name,
          style: const TextStyle(
            color: AppColors.text,
            fontSize: 16,
            fontWeight: FontWeight.w900,
          ),
        ),
      ),
      const Icon(
        Icons.chevron_right,
        color: AppColors.subText,
      ),
    ],
  ),
);

これを、次の短いコードに置き換えます。

return TeamCard(
  name: name,
  onTap: () {
    // 次のページでタスク一覧画面へ移動します
  },
);

これで、一覧表示のコードが短くなります。


Step 8:ListViewの完成形

ListView.separated の中は、次の形になります。

return ListView.separated(
  padding: const EdgeInsets.all(16),
  itemCount: teams.length,
  separatorBuilder: (_, __) => const SizedBox(height: 10),
  itemBuilder: (context, index) {
    final doc = teams[index];
    final data = doc.data();

    final name = (data['name'] ?? '無題のチーム').toString();

    return TeamCard(
      name: name,
      onTap: () {
        // 次のページでタスク一覧画面へ移動します
      },
    );
  },
);

ListView.separated は、一覧の間に余白を入れられるListViewです。

separatorBuilder が、チームとチームの間の余白を作っています。


Step 9:保存する

main.dart を保存します。

Macの場合:

command + S

Windowsの場合:

Ctrl + S

Step 10:実行する

ターミナルで実行します。

flutter run

すでに起動している場合は、ターミナルで r を押します。

r

うまく反映されない場合は、R でホットリスタートします。

R

Step 11:画面を確認する

ログイン後、トーク一覧画面を見ます。

チームがある場合、次のように表示されればOKです。

丸アイコン  チーム名  >

たとえば、

開  開発チーム       >
営  営業チーム       >

のような見た目になれば成功です。


Step 12:チームがない場合

まだチームがない場合は、先に右下の + ボタンから作成します。

右下の+
↓
チーム名を入力
↓
作成する
↓
一覧に表示される

例:

開発チーム
営業チーム

作成すると、TeamCard として一覧に表示されます。


1か所だけ変更してみる

丸アイコンの色を少し変えてみます。

この部分を探します。

backgroundColor: AppColors.lineGreen,

次のように変えてみます。

backgroundColor: AppColors.lineGreenDark,

保存して、ホットリロードします。

r

丸アイコンの緑が少し濃くなれば成功です。

確認できたら、元に戻してOKです。

backgroundColor: AppColors.lineGreen,

よくあるエラーと直し方

エラー原因直し方
TeamCard isn't definedTeamCardを追加していないclass TeamCard を追加する
VoidCallback isn't definedMaterialのimportがないimport 'package:flutter/material.dart'; を確認
characters が見つからない文字処理でエラー下の修正版を使う
画面が変わらない保存していないcommand + S
チームが表示されないFirestore取得ができていない前ページの where arrayContains を確認
タップしても何も起きないまだ画面遷移を書いていない次のページで対応

characters** でエラーが出る場合**

この行でエラーが出る場合があります。

final initial = name.isNotEmpty ? name.characters.first : '?';

その場合は、次のように変更してください。

final initial = name.isNotEmpty ? name.substring(0, 1) : '?';

ただし、日本語や絵文字を安全に扱うなら、characters.first の方が向いています。

もし characters が使えない場合は、main.dart の上に次を追加します。

import 'package:flutter/services.dart';

ただし、通常のFlutter環境では name.characters.first が使えることが多いです。


タップしても何も起きない理由

今の段階では、onTap の中にまだ画面移動を書いていません。

onTap: () {
  // 次のページでタスク一覧画面へ移動します
},

このページでは、表示だけできればOKです。

次のページで、チームをタップしたときに TaskListPage へ移動します。


最短作業まとめ

読むのが大変な人は、ここだけ見てください。

1. TeamCardを追加

class TeamCard extends StatelessWidget {
  const TeamCard({
    super.key,
    required this.name,
    required this.onTap,
  });

  final String name;
  final VoidCallback onTap;

  @override
  Widget build(BuildContext context) {
    final initial = name.isNotEmpty ? name.characters.first : '?';

    return AppCard(
      onTap: onTap,
      child: Row(
        children: [
          CircleAvatar(
            backgroundColor: AppColors.lineGreen,
            child: Text(
              initial,
              style: const TextStyle(
                color: Colors.white,
                fontWeight: FontWeight.w900,
              ),
            ),
          ),
          const SizedBox(width: 12),
          Expanded(
            child: Text(
              name,
              maxLines: 1,
              overflow: TextOverflow.ellipsis,
              style: const TextStyle(
                color: AppColors.text,
                fontSize: 16,
                fontWeight: FontWeight.w900,
              ),
            ),
          ),
          const Icon(
            Icons.chevron_right,
            color: AppColors.subText,
          ),
        ],
      ),
    );
  }
}

2. ListViewの中で使う

return TeamCard(
  name: name,
  onTap: () {
    // 次のページでタスク一覧画面へ移動します
  },
);

3. 保存して実行

flutter run

チェックリスト

□ main.dartを開いた
□ TeamCardを追加した
□ nameを受け取れるようにした
□ onTapを受け取れるようにした
□ CircleAvatarを使った
□ チーム名の1文字目を表示した
□ チーム名をTextで表示した
□ 右側に矢印アイコンを表示した
□ ListViewの中でTeamCardを使った
□ 保存した
□ flutter runで確認した
□ チームがLINEのトーク一覧風に表示された

ミニ確認問題

Q1. TeamCardは何のために作りますか?

回答

チーム1件分を、LINEのトーク一覧のような見た目で表示するためです。


Q2. CircleAvatarは何を作るWidgetですか?

回答

丸いアイコンを作るWidgetです。

今回は、チーム名の1文字目を丸の中に表示します。


Q3. overflow: TextOverflow.ellipsis は何をしますか?

回答

文字が長すぎるときに、末尾を ... で省略します。


Q4. このページでnpmや環境変数は必要ですか?

回答

必要ありません。

このページでは、チーム一覧の見た目を整える TeamCard を作るだけです。


このページのまとめ

  • TeamCard は、チーム1件分を表示する共通UI。
  • LINEのトーク一覧風に、左に丸アイコン、中央にチーム名、右に矢印を置く。
  • チーム名の1文字目を CircleAvatar に表示する。
  • 長いチーム名は ... で省略する。
  • ListView の中で TeamCard を使うと、コードが短くなる。
  • このページではnpmや環境変数は不要。
  • 今回は表示だけでOK。
  • タップ時の画面移動は次のページで作る。

次のページでやること

次のページでは、チームカードをタップして、タスク一覧画面へ移動します。

teamIdteamName を渡して、選んだチームのタスクだけを表示する準備をします。

教材トップへ戻る