【Flutter】フォルダ構成からサンプルアプリのコード解説まで

※本サイトで紹介している商品・サービス等の外部リンクには、プロモーションが含まれています。

Flutterは、クロスプラットフォームで使えるUIフレームワークです。

「1つのコードでAndroidやiOS、Webまで幅広く対応できる」ことや、「すべてがウィジェット」という明快な考え方が特徴です。

本記事では、Flutterのフォルダ構成からサンプルアプリのコード解説までを詳しく説明します。

目次

Flutterプロジェクトのフォルダ構成

Flutterで新しいプロジェクトを作成すると、以下のフォルダ構成を持つプロジェクトフォルダが作成されます。。

[プロジェクト名]/
  ├─ android/           // Android向けのネイティブコードや設定ファイル
  ├─ ios/               // iOS向けのネイティブコードや設定ファイル
  ├─ lib/               // Flutterアプリ本体のDartコード
  │   └─ main.dart      // アプリが動き始める「入口」となるDartファイル
  ├─ test/              // テストコードを置く場所
  ├─ web/               // Web向けビルド時に使用
  ├─ pubspec.yaml       // パッケージやアセット(画像、フォント)の設定ファイル
  └─ ...

libディレクトリ内のmain.dartファイルに、メインとなるコードを書きます。

pubspec.yamlには、使いたい外部ライブラリ(機能拡張パッケージ)や画像・フォントの情報を記述します。

最初のうちは、このlibディレクトリ内main.dartファイルだけでUIや機能を実装していくイメージです。

そもそも「Flutter」って何?

FlutterはDartで作られたフレームワーク

そもそもFlutterとは何でしょうか。

今更ですが、Flutterは、Dartというプログラミング言語で作られたフレームワークです。

よって、Flutterでアプリ開発をする際は、Dartを使用します

すべてがウィジェット

Flutterでは、テキストや画像、ボタンはもちろん、画面全体までもを「ウィジェット」という概念で表します。

ウィジェットとは、UI(ユーザインタフェース)を構成する「部品」のようなものです。

ボタンもテキスト表示も「部品」であり、これらを組み合わせることでアプリの画面を作ります。

ウィジェットには大きく2つの種類があります。

StatelessWidget

表示が固定されるウィジェット。

例えば、常に同じテキストやアイコンを表示するときに使います。

StatefulWidget

ユーザー操作やデータの変化によって表示が変わるウィジェット。

例えば、ボタンを押すと数字が増えるカウンター表示などが当てはまります。

このように「ウィジェットを積み上げる」ことで画面が作られるのが、Flutterの大きな特徴です。

Dartの基本概念(クラス・プロパティ・メソッド・インスタンス・コンストラクタ)

ここまで、ウィジェットを組み合わせることで、アプリ画面を構築することが可能だと学びました。

また、FlutterはDartというプログラミング言語で作られていることも学びました。

次に、ウィジェットが具体的に、Dartというプログラミング言語でどのように書かれるかについて学びます。

このDartでは、ウィジェットを「クラス(class)」という設計図を使って定義します

クラス(Class)とは

クラスとは、「設計図」のようなものです。

もしくは、何かを作る「型」だとイメージするとわかりやすいかもしれません。

例えば、「犬」というクラスを作ったとします。

その場合は、「犬」という動物の設計図を作成することになります。

犬には、「名前」や「年齢」、「色」といった特徴がそれぞれあります。

また、「吠える」や「走る」といった動作をします。

このような特徴「名前」「年齢」「色」と、動作「吠える」「走る」を「犬」クラスの中に設定します。

プロパティ(Property)とは

これらの「特徴」を、「プロパティ」といいます。

「犬」クラスの例では、

  • name(名前)
  • age(年齢)
  • color(色)

がプロパティになります。

これらは設計図(クラス)の中にある「情報を入れる箱」、つまりは「変数」です。

後述しますが、

name → ポチ
age → 3歳
color → 茶色

といった実際の値を入れることで、具体的な犬(インスタンス)となります。

メソッド(Method)とは

一方で「動作」を、「メソッド」といいます。

「犬」クラスの例では、

「吠える」「走る」

がメソッドになります。

これらは設計図(クラス)の中にある「関数」です。

ボタンを押したら数字が増える、文字列を画面に表示する、といった動作もメソッドとして定義します。

インスタンス(Instance)とは

インスタンスは、「クラスをもとに実際に作られたもの」のことです。

「犬」クラスから「ポチ」という犬を作ったら、「ポチ」はDogクラスのインスタンスです。

インスタンスとは、「設計図(クラス)から生まれた実体(形になったもの)」と覚えると分かりやすいです。

コンストラクタ(Constructor)とは

コンストラクタは、新しいインスタンス(実体)を作るときに呼ばれる「特殊なメソッド」です。

設計図からモノを作るときに、どんな情報(名前、年齢、色など)を入れるかを指定して、完成品(インスタンス)を作る処理がコンストラクタです。

例えば、「犬」クラスのコンストラクタで、犬のnameagecolorを指定すれば、その情報を持った「ポチ」という犬のインスタンスができます。

(例)

class Dog {
  String name;  // 犬の名前を入れるプロパティ
  int age;      // 犬の年齢を入れるプロパティ
  String color; // 犬の色を入れるプロパティ

  // コンストラクタ:新しい犬(インスタンス)を作るときに呼ばれる
  Dog(this.name, this.age, this.color);
}

// インスタンス化(実体化)
Dog myDog = Dog("ポチ", 3, "茶色");

// こうしてmyDogには、nameに"ポチ"、ageに3、colorに"茶色"が入った犬オブジェクトができあがる

このように、myDogDogクラス(設計図)から作り出した、具体的な犬(インスタンス)です。

FlutterのTextウィジェットも、同じ仕組みです。

Textクラス(設計図)に表示したい文字(”Hello, Flutter!”)やテキストのスタイルをコンストラクタで渡して、新しいTextインスタンスを作っています。

命名規則(UpperCamelCaseとlowerCamelCase)

Dartでは、クラス名やメソッド名などに一定の書き方ルール(コーディング規約)があります。

UpperCamelCase

クラス名や型名はMyClassMyHomePageのように、単語の頭文字を大文字で繋げます。

lowerCamelCase

変数名やメソッド名はmyVariablebuildContextのように、最初の単語は小文字、2つ目以降の単語の先頭を大文字にします。

これらの決まりを守ると、コードが読みやすくなります。

サンプルアプリの基本構造

まず、新規Flutterプロジェクトを作成すると、以下のようなコードが書かれています。

これを、「サンプルアプリ」といいます。

(「//」と書かれている行はコメントです。)

// ------------------------------------------------
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓①↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
import 'package:flutter/material.dart';
// ------------------------------------------------

// ------------------------------------------------
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓②↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
void main() {
  runApp(const MyApp());
}
// ------------------------------------------------

// ------------------------------------------------
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓③↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}
// ------------------------------------------------

// ------------------------------------------------
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓④↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}
// ------------------------------------------------

順番に解説していきます。

① import ‘package:flutter/material.dart’;

最初の1文は、FlutterでMaterialデザイン(後述)を使ってアプリを作るためのウィジェットや機能がまとまったパッケージを読み込んでいます。

flutter/material.dartには、ボタンやテキスト表示など標準的なUIウィジェットがたくさん揃っており、Flutterアプリ開発では最もよく使われます。

② main関数

void main() {
  runApp(const MyApp());
}

Dart言語では、「main()関数」がプログラムのスタート地点になります。

main関数の中には、runApp関数が呼び出されており、引数にMyAppウィジェット(MyAppクラス)が渡されています。

③ MyAppウィジェット(MyAppクラス)

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

MyAppウィジェット(MyAppクラス)は、StatelessWidgetを継承して作成されているウィジェットです。

MyAppウィジェットは、MaterialAppウィジェットを使用しています。

MaterialAppウィジェット

これは、Materialデザインのアプリを作成するためのウィジェットです。Materialデザインとは、Googleが推奨するデザインです。詳細は、以下のページをご確認ください。

https://api.flutter.dev/flutter/material/MaterialApp-class.html

そして、MaterialAppウィジェットは、3つのプロパティ「title」「theme」「home」を設置して、それぞれにウィジェットを定義しています。

titleプロパティとは、アプリのタイトルを定義するものです。

themeプロパティとは、アプリのテーマを定義するものです。

homeプロパティとは、アプリのホーム画面を定義するものです。

ホーム画面として、MyHomePageウィジェット(MyHomePageクラス)を呼び出しています。

④ MyHomePageウィジェット(MyHomePageクラス)

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {

// ------------------------------------------------
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓【ここだけ簡単に解説】↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
// ------------------------------------------------
  }
}

MyHomePageウィジェットは、StatefulWidgetウィジェットを継承して作成されているウィジェットです。

ここの部分は、大事な箇所ですが理解するのは非常に難しいので、本記事では【ここだけ簡単に解説】部分だけ触れることにします。

ここでは、Scaffoldウィジェットが呼び出されて、3つのプロパティ「appBar」「body」「floatingActionButton」が設置されています。

Scaffoldウィジェット

これは、Materialデザインのレイアウトを作成するウィジェットです。「足場」という意味ですが、まさに画面の土台部分です。詳しくは、以下のページをご確認ください。

https://api.flutter.dev/flutter/material/Scaffold-class.html

3つのプロパティ「appBar」「body」「floatingActionButton」には、以下のようにウィジェットが指定されています。

appBarプロパティ → AppBarウィジェット
bodyプロパティ → Centerウィジェット
floatingActionButtonプロパティ → FloatingActionButtonウィジェット

また、それぞれに対応するアプリの画面は以下の通りです。

appBarプロパティ → ①
bodyプロパティ → ②Centerウィジェット
floatingActionButtonプロパティ → ③

まとめ

本記事では、以下の点を解説しました。

  • Flutterプロジェクトのフォルダ構造
  • Flutterでのアプリ開発は、ウィジェットを組み合わせて行う
  • Flutterは、Dartというプログラミング言語で作られたフレームワークである
  • サンプルアプリの簡単な構造

次回からは、サンプルアプリを改造するかたちで、様々なウィジェットを学んでいきましょう。


これにて、Flutterのフォルダ構成からサンプルアプリのコード解説までの説明を終わります。

次は、Textウィジェットについてです。

shimaのおすすめ書籍

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

shimaのアバター shima ライター

IT企業に勤める会社員。
テクニカルライター/プログラマー。
ITやソフトウェアに関することをわかりやすくまとめ、多くの人にそれらを知ってもらおうと活動しています。
ご質問やご要望、お仕事依頼がございましたらお問合せフォームよりお願いいたします。

コメント

コメントする

CAPTCHA



reCaptcha の認証期間が終了しました。ページを再読み込みしてください。

目次