TEXTBOOK SECTION / AI LEARNING

Flutterアプリのデザインをポケモン図鑑風に整える

Flutterアプリケーション開発概論の「Flutter API連携入門|ポケモン図鑑アプリの作り方」より、Flutterアプリのデザインをポケモン図鑑風に整えるを解説。生成AI、AI活用、DX、業務改善を実践しながら学べるオンライン教材です。

第16節Flutter API連携入門|ポケモン図鑑アプリの作り方Flutter / iOS / Android / MacOS / Windows / 基礎から学ぶ / 開発 / アプリ開発

OVERVIEW

この節で学べること

概要を表示する
項目内容
教材名Flutterアプリケーション開発概論
章Flutter API連携入門|ポケモン図鑑アプリの作り方
節Flutterアプリのデザインをポケモン図鑑風に整える
カテゴリFlutter / iOS / Android / MacOS / Windows / 基礎から学ぶ / 開発 / アプリ開発
学習内容生成AI、AI活用、DX、業務改善を実践しながら理解するための教材です。

TABLE OF CONTENTS

目次

CONTENT

ここから

前の節では、API取得失敗時のエラー表示を作りました。

今回は、アプリ全体の見た目を少し整えて、ポケモン図鑑風の検索アプリに近づけます。

本物のポケモン図鑑を完全再現するのではなく、教材として扱いやすいように、赤・白・カード・丸い画像エリアを使って雰囲気を作ります。

出典なし。


この節で作ること

作業内容
背景色を整える薄い赤系の背景にする
AppBarを赤くする図鑑らしい印象にする
検索エリアをカード化する入力欄とボタンを見やすくする
結果カードを調整する画像・番号・名前を中央に配置する

忙しい方はここだけ見て

デザイン調整の中心は、次の3つです。

backgroundColor: const Color(0xFFFFF3F3),
appBar: AppBar(
  title: const Text('ポケモン図鑑'),
  backgroundColor: const Color(0xFFE53935),
  foregroundColor: Colors.white,
),
Card(
  elevation: 6,
  shape: RoundedRectangleBorder(
    borderRadius: BorderRadius.circular(24),
  ),
)

色・角丸・余白を整えるだけで、アプリの印象はかなり変わります。


手順1:背景色を変更する

Scaffold に backgroundColor を追加します。

Scaffold(
  backgroundColor: const Color(0xFFFFF3F3),
  appBar: AppBar(
    title: const Text('ポケモン図鑑'),
  ),
)

薄い赤系の背景にすると、ポケモン図鑑らしい雰囲気が出ます。


手順2:AppBarを赤くする

AppBar を次のように変更します。

appBar: AppBar(
  title: const Text('ポケモン図鑑'),
  centerTitle: true,
  backgroundColor: const Color(0xFFE53935),
  foregroundColor: Colors.white,
),

backgroundColor は背景色です。foregroundColor は文字やアイコンの色です。


手順3:検索エリアをカードにする

入力欄と検索ボタンを、白いカードの中に入れます。

Card(
  elevation: 4,
  shape: RoundedRectangleBorder(
    borderRadius: BorderRadius.circular(20),
  ),
  child: Padding(
    padding: const EdgeInsets.all(16),
    child: Column(
      children: <Widget>[
        TextField(
          controller: _pokemonIdController,
          keyboardType: TextInputType.number,
          enabled: !_isLoading,
          decoration: const InputDecoration(
            labelText: 'ポケモン番号',
            hintText: '例: 25',
            border: OutlineInputBorder(),
          ),
        ),
        const SizedBox(height: 16),
        SizedBox(
          width: double.infinity,
          child: ElevatedButton(
            onPressed: _isLoading ? null : _searchPokemon,
            child: Text(_isLoading ? '検索中...' : '検索する'),
          ),
        ),
      ],
    ),
  ),
)

入力欄とボタンをカードにまとめると、「検索エリア」として分かりやすくなります。


手順4:検索ボタンを赤くする

ElevatedButton に style を追加します。

ElevatedButton(
  onPressed: _isLoading ? null : _searchPokemon,
  style: ElevatedButton.styleFrom(
    backgroundColor: const Color(0xFFE53935),
    foregroundColor: Colors.white,
    padding: const EdgeInsets.symmetric(vertical: 14),
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(14),
    ),
  ),
  child: Text(_isLoading ? '検索中...' : '検索する'),
)

ボタンも赤にすると、アプリ全体の印象がまとまります。


手順5:結果カードを図鑑風にする

検索結果のカードを少し整えます。

Card(
  elevation: 6,
  shape: RoundedRectangleBorder(
    borderRadius: BorderRadius.circular(24),
  ),
  child: Padding(
    padding: const EdgeInsets.all(24),
    child: Column(
      children: <Widget>[
        Text(
          'No. $_pokemonIdText',
          style: const TextStyle(
            fontSize: 16,
            color: Colors.grey,
            fontWeight: FontWeight.bold,
          ),
        ),
        const SizedBox(height: 12),
        Container(
          width: 180,
          height: 180,
          decoration: BoxDecoration(
            color: Color(0xFFF5F5F5),
            shape: BoxShape.circle,
          ),
          child: Image.network(
            _pokemonImageUrl!,
            fit: BoxFit.contain,
          ),
        ),
        const SizedBox(height: 20),
        Text(
          _pokemonName,
          style: const TextStyle(
            fontSize: 30,
            fontWeight: FontWeight.bold,
          ),
        ),
      ],
    ),
  ),
)

画像の後ろに丸い背景を入れると、キャラクターが見やすくなります。


完成コード

build() の中を中心に、次のように整えます。

/**
 * ポケモン検索画面を構築する関数。
 *
 * 入力: BuildContext
 * 出力: Scaffold
 */
@override
Widget build(BuildContext context) {
  return Scaffold(
    backgroundColor: const Color(0xFFFFF3F3),
    appBar: AppBar(
      title: const Text('ポケモン図鑑'),
      centerTitle: true,
      backgroundColor: const Color(0xFFE53935),
      foregroundColor: Colors.white,
    ),
    body: SingleChildScrollView(
      padding: const EdgeInsets.all(16),
      child: Column(
        children: <Widget>[
          Card(
            elevation: 4,
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(20),
            ),
            child: Padding(
              padding: const EdgeInsets.all(16),
              child: Column(
                children: <Widget>[
                  TextField(
                    controller: _pokemonIdController,
                    keyboardType: TextInputType.number,
                    enabled: !_isLoading,
                    decoration: const InputDecoration(
                      labelText: 'ポケモン番号',
                      hintText: '例: 25',
                      border: OutlineInputBorder(),
                    ),
                  ),
                  const SizedBox(height: 16),
                  SizedBox(
                    width: double.infinity,
                    child: ElevatedButton(
                      onPressed: _isLoading ? null : _searchPokemon,
                      style: ElevatedButton.styleFrom(
                        backgroundColor: const Color(0xFFE53935),
                        foregroundColor: Colors.white,
                        padding: const EdgeInsets.symmetric(vertical: 14),
                        shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(14),
                        ),
                      ),
                      child: Text(_isLoading ? '検索中...' : '検索する'),
                    ),
                  ),
                ],
              ),
            ),
          ),
          const SizedBox(height: 32),
          if (_isLoading)
            const CircularProgressIndicator()
          else if (_errorMessage != null)
            Text(
              _errorMessage!,
              style: const TextStyle(
                fontSize: 18,
                fontWeight: FontWeight.bold,
                color: Colors.red,
              ),
            )
          else if (_pokemonImageUrl != null)
            Card(
              elevation: 6,
              shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(24),
              ),
              child: Padding(
                padding: const EdgeInsets.all(24),
                child: Column(
                  children: <Widget>[
                    Text(
                      'No. $_pokemonIdText',
                      style: const TextStyle(
                        fontSize: 16,
                        color: Colors.grey,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                    const SizedBox(height: 12),
                    Container(
                      width: 180,
                      height: 180,
                      decoration: const BoxDecoration(
                        color: Color(0xFFF5F5F5),
                        shape: BoxShape.circle,
                      ),
                      child: Image.network(
                        _pokemonImageUrl!,
                        fit: BoxFit.contain,
                      ),
                    ),
                    const SizedBox(height: 20),
                    Text(
                      _pokemonName,
                      style: const TextStyle(
                        fontSize: 30,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ],
                ),
              ),
            )
          else
            Text(
              _pokemonName,
              style: const TextStyle(
                fontSize: 20,
                fontWeight: FontWeight.bold,
              ),
            ),
        ],
      ),
    ),
  );
}

動作確認

アプリを起動します。

flutter run

25 と入力して検索します。

pikachu

赤いヘッダー、白い検索カード、丸い画像エリア、結果カードが表示されれば成功です。


よくあるエラー

エラー原因対応
画面が詰まる余白が少ないPadding や SizedBox を増やす
画像が大きすぎるサイズ指定がないContainer の幅と高さを指定する
ボタンの色が変わらないstyle がないElevatedButton.styleFrom() を使う
カードの角が丸くならないshape がないRoundedRectangleBorder を指定する

まとめ

この節では、Flutterアプリをポケモン図鑑風に整えました。

大事なポイントは3つです。

ポイント内容
色赤・白・薄赤で雰囲気を作る
余白Padding と SizedBox で見やすくする
カードUI検索エリアと結果を分ける

機能は同じでも、見た目を整えるだけでアプリの完成度は大きく変わります。

次は、ここまで作った機能を振り返りながら、アプリとして仕上げていきます。

FAQ

よくある質問

Flutterアプリのデザインをポケモン図鑑風に整えるは医療関係者向けだけの内容ですか。
医療分野の例が含まれる場合もありますが、医療関係者だけに限定した内容ではありません。生成AI、AI活用、DX、業務改善、プロトタイプ開発など、一般的なAI学習の事例として読める内容です。
AI初心者でも読めますか。
はい。AIをこれから学ぶ方、数学が苦手な方、仕事でAIを使いたい方にも読み進めやすいように、教材の章と節の流れに沿って整理しています。
サムネイル画像は必ず表示されますか。
はい。教材にcoverUrlが設定されている場合はその画像を表示し、未設定の場合は代替サムネイル画像を表示します。
Flutterアプリケーション開発概論のほかの章も読めますか。
はい。教材トップから章立てを確認でき、前後の節へもページ下部のナビゲーションから移動できます。