目次
Dartファイルの構造 – 家を建てる順番!
比喩で言うと: コードは家を建てるようなもの。土台→柱→壁→屋根の順番が決まっています! 🏠
順番(テンプレート)
// ========================================
// 1. import 文(外部から材料を持ってくる)
// ========================================
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:io';
// 自作ファイルのimportは最後
import 'models/student.dart';
import 'utils/helpers.dart';
// ========================================
// 2. クラス定義
// ========================================
class StudentPage extends StatefulWidget {
// ========================================
// 2-1. 定数(const)
// ========================================
static const String routeName = '/student';
// ========================================
// 2-2. final 変数(コンストラクタで初期化)
// ========================================
final String studentId;
final String studentName;
// ========================================
// 2-3. コンストラクタ
// ========================================
const StudentPage({
Key? key,
required this.studentId,
required this.studentName,
}) : super(key: key);
// ========================================
// 2-4. createState (StatefulWidgetの場合)
// ========================================
@override
State<StudentPage> createState() => _StudentPageState();
}
// ========================================
// 3. State クラス
// ========================================
class _StudentPageState extends State<StudentPage> {
// ========================================
// 3-1. 通常の変数(状態)
// ========================================
int _counter = 0;
String _message = '';
List<String> _items = [];
// ========================================
// 3-2. late 変数
// ========================================
late TextEditingController _controller;
// ========================================
// 3-3. ライフサイクルメソッド(決まった順番!)
// ========================================
// 初期化(一番最初に呼ばれる)
@override
void initState() {
super.initState();
_controller = TextEditingController();
_loadData();
}
// 依存関係が変わったとき
@override
void didChangeDependencies() {
super.didChangeDependencies();
// 必要なら処理
}
// Widget が更新されたとき
@override
void didUpdateWidget(StudentPage oldWidget) {
super.didUpdateWidget(oldWidget);
// 必要なら処理
}
// 破棄される前(最後に呼ばれる)
@override
void dispose() {
_controller.dispose();
super.dispose();
}
// ========================================
// 3-4. build メソッド(UI を作る)
// ========================================
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.studentName),
),
body: Center(
child: Column(
children: [
Text('$_counter'),
ElevatedButton(
onPressed: _incrementCounter,
child: Text('増やす'),
),
],
),
),
);
}
// ========================================
// 3-5. プライベートメソッド(内部で使う関数)
// ========================================
// データ読み込み
Future<void> _loadData() async {
final prefs = await SharedPreferences.getInstance();
setState(() {
_counter = prefs.getInt('counter') ?? 0;
});
}
// カウンター増加
void _incrementCounter() {
setState(() {
_counter++;
});
}
// データ保存
Future<void> _saveData() async {
final prefs = await SharedPreferences.getInstance();
await prefs.setInt('counter', _counter);
}
// 計算処理
int _calculateTotal() {
return _counter * 2;
}
}
📚 各セクションの詳細説明
1、import 文の順番
// (1) Dart標準ライブラリ
import 'dart:io';
import 'dart:async';
// (2) Flutterライブラリ
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
// (3) 外部パッケージ
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
// (4) 自分のファイル(相対パス)
import 'models/student.dart';
import 'screens/home_page.dart';
import 'utils/constants.dart';
順番の理由:
- 標準 → Flutter → パッケージ → 自作の順
- 関連性の高いものをグループ化
- 読みやすさのため
2、クラス内の変数の順番
class MyWidget extends StatefulWidget {
// (1) 定数(static const)
static const String title = 'マイアプリ';
// (2) final 変数(外部から受け取る)
final String studentId;
final int age;
// (3) コンストラクタ
const MyWidget({
required this.studentId,
required this.age,
});
// (4) createState
@override
State<MyWidget> createState() => _MyWidgetState();
}
順番の理由:
- 変わらないもの(定数)が先
- 外部から受け取るもの(final)が次
- 初期化処理(コンストラクタ)
- 最後に createState
3、State クラス内の順番
class _MyWidgetState extends State<MyWidget> {
// (1) 変数(状態)
int _counter = 0;
String _name = '';
// (2) late 変数
late TextEditingController _controller;
// (3) ライフサイクルメソッド
@override
void initState() { ... }
@override
void dispose() { ... }
// (4) build メソッド
@override
Widget build(BuildContext context) { ... }
// (5) プライベートメソッド
void _myMethod() { ... }
Future<void> _loadData() async { ... }
}
順番の理由:
- データ(変数)を最初に定義
- ライフサイクル(初期化・破棄)
- UI構築(build)
- ヘルパー関数(メソッド)
🔄 ライフサイクルメソッドの順番
これは決まった順番があります!
class _MyPageState extends State<MyPage> {
// ========================================
// 呼ばれる順番:
// 1. initState (最初の1回だけ)
// 2. didChangeDependencies (初回 + 依存変更時)
// 3. build (何度も呼ばれる)
// 4. didUpdateWidget (親から更新された時)
// 5. dispose (最後、破棄される時)
// ========================================
@override
void initState() {
super.initState();
print('1. initState');
// 初期化処理(1回だけ)
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
print('2. didChangeDependencies');
}
@override
Widget build(BuildContext context) {
print('3. build');
return Scaffold(...);
}
@override
void didUpdateWidget(MyPage oldWidget) {
super.didUpdateWidget(oldWidget);
print('4. didUpdateWidget');
}
@override
void dispose() {
print('5. dispose');
super.dispose();
}
}
ポイント:
- initState → super.initState() を最初に
- dispose → super.dispose() を最後に
📐 build メソッド内の順番
@override
Widget build(BuildContext context) {
return Scaffold(
// (1) AppBar(上部)
appBar: AppBar(
title: Text('タイトル'),
),
// (2) body(メインコンテンツ)
body: Center(
child: Column(
children: [
Text('Hello'),
ElevatedButton(
onPressed: () {},
child: Text('ボタン'),
),
],
),
),
// (3) FloatingActionButton(右下のボタン)
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.add),
),
// (4) bottomNavigationBar(下部ナビ)
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'ホーム'),
BottomNavigationBarItem(icon: Icon(Icons.search), label: '検索'),
],
),
// (5) drawer(サイドメニュー)
drawer: Drawer(
child: ListView(...),
),
);
}
Scaffoldの順番:
- appBar → body → floatingActionButton → bottomNavigationBar → drawer
- 上から下、メインから補助の順
メソッド名の付け方ルール
プライベートメソッド(内部で使う):
// アンダースコア(_)で始める
void _incrementCounter() { ... }
Future<void> _loadData() async { ... }
int _calculateTotal() { ... }
パブリックメソッド(外部から呼ぶ):
// アンダースコアなし
void incrementCounter() { ... }
Future<void> loadData() async { ... }
99%の場合、State内のメソッドは _ 付き(プライベート)
コツを調べてみた!
コメントでセクション分け
class MyPage extends StatefulWidget {
// ========================================
// Variables
// ========================================
final String title;
// ========================================
// Constructor
// ========================================
const MyPage({required this.title});
// ========================================
// Create State
// ========================================
@override
State<MyPage> createState() => _MyPageState();
}
見やすくなる! ✨
関連メソッドをまとめる
// ========================================
// データ関連
// ========================================
Future<void> _loadData() async { ... }
Future<void> _saveData() async { ... }
void _clearData() { ... }
// ========================================
// UI関連
// ========================================
Widget _buildHeader() { ... }
Widget _buildBody() { ... }
Widget _buildFooter() { ... }
// ========================================
// イベントハンドラ
// ========================================
void _onButtonPressed() { ... }
void _onTextChanged(String text) { ... }
分かりやすい! ✨
メソッドは短く
// ❌ 長すぎる
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Container(
// 100行のコード...
),
ListView(
// 100行のコード...
),
// ...
],
),
);
}
// ✅ メソッドに分ける
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
_buildHeader(),
_buildList(),
_buildFooter(),
],
),
);
}
Widget _buildHeader() { ... }
Widget _buildList() { ... }
Widget _buildFooter() { ... }
1メソッド = 20-30行まで が目安!
async/await の順番
// Future<void> は非同期
Future<void> _loadData() async {
// await を使う
final data = await fetchFromDatabase();
setState(() {
_data = data;
});
}
// void は同期
void _updateCounter() {
setState(() {
_counter++;
});
}
まとめ: 順番の全体像
// 1. import (材料を集める)
import 'package:flutter/material.dart';
// 2. StatefulWidget (設計図)
class MyPage extends StatefulWidget {
// 2-1. 定数
// 2-2. final変数
// 2-3. コンストラクタ
// 2-4. createState
}
// 3. State (実際の家)
class _MyPageState extends State<MyPage> {
// 3-1. 変数(状態)
// 3-2. late変数
// 3-3. ライフサイクル(決まった順番!)
@override void initState() { super.initState(); }
@override void dispose() { super.dispose(); }
// 3-4. build(UI)
@override Widget build(BuildContext context) {
return Scaffold(...);
}
// 3-5. メソッド(機能)
Future<void> _loadData() async { ... }
void _updateUI() { ... }
}
一言まとめ:
コードの順番は家を建てる順番と同じ!
import(材料) → クラス定義(設計図) → 変数(部品) → ライフサイクル(組み立て) → build(完成) → メソッド(機能)。この順番を守ると、読みやすく、メンテしやすい!
