Contents
Flutter 3.19 と Dart 3 のインストール・セットアップ
Flutter 3.19 と Dart 3 は、最新のモバイル・デスクトップ開発に必要な機能がすべてパッケージ化されています。この章では 公式サイトから SDK を取得 → 環境変数を設定 → flutter doctor で依存ツールを自動インストール の流れを、OS 別に分かりやすく解説します。初心者でも途中でつまずきにくいよう、各ステップの注意点と実行例を併記しています。
公式サイトからの取得
Flutter と Dart は同一リポジトリに含まれているため、公式インストールページ(flutter.dev/install)から OS に合わせた zip/tar.gz をダウンロードします。
- Windows:flutter_windows_3.19.x-stable.zip
- macOS:flutter_macos_3.19.x-stable.tar.xz
- Linux:flutter_linux_3.19.x-stable.tar.xz
SDK の解凍と PATH 設定
- 任意のディレクトリに展開(例:
C:\src\flutter/$HOME/flutter)。 - 展開したフォルダ内の
binディレクトリをシステム環境変数 PATH に追加します。
|
1 2 3 |
# macOS / Linux の例 (~/.zshrc などに追記) export PATH="$HOME/flutter/bin:$PATH" |
ポイント:ターミナルで
flutter --versionが正しく表示されれば設定完了です。
flutter doctor の実行と依存ツールの自動インストール
|
1 2 |
flutter doctor |
flutter doctor は以下をチェックし、足りないものはインストール手順へのリンクを提示します。
| 項目 | 主な不足ツール | インストール例 |
|------|----------------|----------------|
| Android toolchain | Android SDK, Command‑line tools, Java JDK | sdkmanager --install "platform-tools" "platforms;android-34" |
| Xcode (macOS) | Xcode 本体、Command Line Tools、iOS シミュレータ | App Store から Xcode をインストール → xcode-select --install |
| Chrome | Web 開発用の Chrome ブラウザ | 公式サイトからダウンロード |
重要:flutter doctor が緑色で完了するまで、指示されたツールを必ず導入してください。これが欠けていると flutter run が失敗します。
macOS 向け iOS シミュレータのセットアップ
iOS アプリは macOS のみ でシミュレータが利用可能です。以下の手順で確認・起動できます。
|
1 2 3 4 5 6 |
# 利用可能なデバイス一覧を表示 xcrun simctl list devices # デフォルトシミュレータ (iPhone 15) を起動 open -a Simulator --args -CurrentDeviceUDID <device‑udid> |
Windows / Linux では iOS シミュレータは提供されません。その代わり、Flutter の Web/Android エミュレータ を使用してください。
Windows / Linux 向け Android エミュレータのセットアップ
- Android Studio をインストールし、SDK Manager から「Android SDK」「Android Virtual Device (AVD)」を選択。
- AVD Manager で「Pixel 6 API 34」など好きなデバイスを作成し、
Launchボタンで起動。
|
1 2 3 |
# エミュレータの CLI 起動例 $ANDROID_HOME/emulator/emulator -avd Pixel_6_API_34 |
Dart 3 の新機能と互換性注意点
| 変更点 | 内容 | 移行時の留意点 |
|---|---|---|
パターンマッチング (switch 拡張) |
case var (x, y) でタプル分解が可能 |
古い if/else ロジックは削除不要だが、IDE が最新バージョンか確認 |
| レコード型 & 名前付きレコード | (int id, String name) → ({int id, String name}) |
JSON シリアライズ時に手動変換が必要 |
| 強化された null safety | 非 nullable 型への暗黙的キャストがコンパイルエラーに | 既存コードの ! 演算子を減らすリファクタリングが推奨 |
dart run のデフォルトビルドモード変更 |
デバッグ実行時は --no-pause-isolates-on-exit が自動付与 |
テストスクリプトで期待通りに終了しないケースがあるので確認 |
Dart 3 は Flutter 3.19 の最小サポートバージョン です。既存プロジェクトをアップグレードする際は、pub upgrade --major-versions を実行し、dart analyze と flutter test で全体の整合性を確認してください。
IDE の推奨設定(VS Code / Android Studio)
IDE が提供するコード補完・デバッグ機能は開発速度に直結します。この章では、Flutter & Dart 拡張のインストール → デバイス/エミュレータ認識確認 → Hot Reload/Restart の正しいキー設定 までを順番に解説します。
VS Code の初期設定
- 拡張機能
Flutter(公式)-
Dart(自動でインストールされます) -
デバッグ構成の確認
Run > Add Configuration...で生成された.vscode/launch.jsonが以下のようになっているかチェックします。
|
1 2 3 4 5 6 7 8 9 10 |
{ "configurations": [ { "name": "Flutter", "request": "launch", "type": "dart" } ] } |
- Hot Reload / Hot Restart のデフォルトキー
| 操作 | デフォルトキーバインド |
|---|---|
| Hot Reload | r (ターミナル上)または Ctrl+Shift+F5(デバッグビューのボタン) |
| Hot Restart | R (ターミナル上)または Shift+F5(デバッグビュー) |
キーがカスタマイズされている場合は、Keyboard Shortcuts (Ctrl+K Ctrl+S) で「Flutter: Hot Reload」・「Flutter: Hot Restart」を検索し、目的の組み合わせに変更してください。
Android Studio の初期設定
- プラグイン
-
Flutter→ 自動的にDartが有効化されます。 -
AVD / iOS シミュレータのリンク確認
Tools > Flutter > Open Android Emulator、もしくはRun > Select Deviceでデバイスが一覧表示されることを確認します。 -
Hot Reload / Hot Restart のデフォルトキー
| 操作 | デフォルトキーバインド |
|---|---|
| Hot Reload | Ctrl+\\(Windows/Linux)または ⌘+\(macOS) |
| Hot Restart | Shift+F10(Windows/Linux)または ⇧+⌘+R(macOS) |
注意:Android Studio のツールバーにも「Flash」アイコンがあり、クリックで同等の操作が可能です。
ウィジェットの基本概念と Stateless / Stateful の使い分け
Flutter の UI は ウィジェットツリー と呼ばれる階層構造で描画されます。このセクションでは、ツリーの生成プロセスと状態管理の観点から StatelessWidget と StatefulWidget を選択すべきタイミングを示します。
ウィジェットツリーとビルドプロセス
ウィジェットは不変(immutable)オブジェクトで、build() が呼ばれるたびに 新しい子ウィジェットのインスタンス が生成されます。フレームワークは前回のツリーとの差分を計算し、最小限の描画指示だけを GPU に送ります。この差分更新が高速な UI 体験の根幹です。
StatelessWidget と StatefulWidget の選択基準
- StatelessWidget
- プロパティのみで表示が決まるシンプル UI(アイコン、固定テキストなど)に適しています。
-
再描画は外部から渡された新しいインスタンスが作られたときだけ発生します。
-
StatefulWidget
- ユーザー操作や非同期処理で内部状態が変化する場合に使用します。
setState()が呼ばれると、該当Stateオブジェクトのbuild()が再実行されます。
ベストプラクティス:状態は可能な限り UI の外部(Provider、Riverpod など)へ切り出し、ウィジェット自体は
StatelessWidgetに保つことでテスト容易性とパフォーマンスが向上します。
カスタムウィジェット作成のベストプラクティス
独自コンポーネントを実装する際に意識すべきポイントは const コンストラクタ、key の受け渡し、そして Composition による再利用性 です。以下では可読性とパフォーマンスの両立を目指したコード例を示します。
const コンストラクタと key の正しい扱い
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import 'package:flutter/material.dart'; class MyBadge extends StatelessWidget { final String label; final Color color; const MyBadge({ Key? key, required this.label, this.color = Colors.blue, }) : super(key: key); // 必ず super に渡す @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: color, borderRadius: BorderRadius.circular(12), ), child: Text(label, style: const TextStyle(color: Colors.white)), ); } } |
constが付くことで コンパイル時にウィジェットが確定 し、再描画コストが削減されます。keyはリストやアニメーションで要素位置が変わるときの識別子として必須です。
Composition による汎用レイアウト例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
class InfoCard extends StatelessWidget { final Widget header; final Widget body; final List<Widget>? actions; const InfoCard({ Key? key, required this.header, required this.body, this.actions, }) : super(key: key); @override Widget build(BuildContext context) { return Card( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ header, const Divider(), Padding(padding: const EdgeInsets.all(8.0), child: body), if (actions != null) ButtonBar(children: actions!), ], ), ); } } |
headerとbodyを外部から差し替えるだけで、通知カード・プロフィールカードなど多様な UI に流用できます。- Composition は「単一責任」原則を自然に満たす設計手法です。
setState の安全な使用と最小化テクニック
setState() は UI 更新の入り口ですが、過剰に呼び出すと描画コストが増大します。ここでは mounted チェック と 状態分割 によるパフォーマンス改善手法を紹介します。
mounted の確認と非同期処理
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
class Counter extends StatefulWidget { const Counter({Key? key}) : super(key: key); @override _CounterState createState() => _CounterState(); } class _CounterState extends State<Counter> { int _value = 0; Future<void> _incrementAsync() async { final result = await fetchIncrement(); // 任意の非同期処理 if (!mounted) return; // ウィジェットが破棄されていないか確認 setState(() => _value += result); } @override Widget build(BuildContext context) { return ElevatedButton( onPressed: _incrementAsync, child: Text('$_value'), ); } } |
mountedがfalseの場合は UI がツリーから外れているため、setState()を呼んでも例外が発生しません。
状態分割による setState の削減
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
final counter = ValueNotifier<int>(0); class CounterButton extends StatelessWidget { const CounterButton({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return ValueListenableBuilder<int>( valueListenable: counter, builder: (_, value, __) => Text('Count: $value'), ); } } |
ValueNotifierが変化したときだけCounterButtonが再描画され、他のウィジェットは影響を受けません。- 大規模アプリでは Provider や Riverpod の
ChangeNotifier系も同様に有効です。
カスタム描画:CustomPainter と RenderObjectWidget
高度な UI(グラフ、ゲーム UI、カスタムトランジション)を実装する場合は CustomPainter または RenderObjectWidget を活用します。以下では基本的な実装パターンとアクセシビリティ対応方法を示します。
CustomPainter の最小実装
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
class GradientCircle extends CustomPainter { final Color startColor; final Color endColor; const GradientCircle({required this.startColor, required this.endColor}); @override void paint(Canvas canvas, Size size) { final rect = Offset.zero & size; final gradient = RadialGradient(colors: [startColor, endColor]); final paint = Paint()..shader = gradient.createShader(rect); canvas.drawCircle(size.center(Offset.zero), size.shortestSide / 2, paint); } @override bool shouldRepaint(covariant GradientCircle oldDelegate) { return startColor != oldDelegate.startColor || endColor != oldDelegate.endColor; } } |
shouldRepaintが true を返すときだけ再描画が走ります。プロパティが変わらない限り、Flutter は同じペインターを使い回します。
RenderObjectWidget の概要
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
class SimpleBox extends SingleChildRenderObjectWidget { const SimpleBox({Key? key, Widget? child}) : super(key: key, child: child); @override RenderSimpleBox createRenderObject(BuildContext context) => RenderSimpleBox(); } class RenderSimpleBox extends RenderProxyBox { @override void performLayout() { size = constraints.constrain(const Size(100, 100)); // 固定サイズ例 if (child != null) child!.layout(constraints, parentUsesSize: true); } @override void paint(PaintingContext context, Offset offset) { final paint = Paint()..color = Colors.orange; context.canvas.drawRect(offset & size, paint); super.paint(context, offset); // 子があれば描画 } } |
performLayoutでサイズを決定し、paintで実際の描画処理を記述します。大量アイテムのリストや独自レイアウトエンジンが必要なケースに有効です。
アクセシビリティとテーマ対応
|
1 2 3 4 5 6 7 8 9 10 |
final primary = Theme.of(context).colorScheme.primary; Semantics( label: 'Loading indicator', child: CustomPaint( size: const Size(120, 120), painter: GradientCircle(startColor: primary, endColor: Colors.transparent), ), ); |
Theme.ofで全体デザインに合わせ、Semanticsによってスクリーンリーダー向けの説明文を付与します。
テスト・パッケージ化・次のステップ
作成したウィジェットは unit test / golden test / integration test で品質を担保し、必要に応じて pub.dev に公開できます。
widgetTest と golden test の例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
testWidgets('MyBadge shows the correct label', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Scaffold(body: MyBadge(label: 'NEW')), )); expect(find.text('NEW'), findsOneWidget); }); testGoldens('MyBadge golden snapshot', (WidgetTester tester) async { final builder = GoldenBuilder.column() ..addScenario('default', const MyBadge(label: 'Test')); await tester.pumpWidget(builder.build()); await screenMatchesGolden(tester, 'mybadge_default'); }); |
integration test のベーシックフロー
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); testWidgets('Full app flow', (WidgetTester tester) async { await tester.pumpAndSettle(); // アプリ起動待ち final button = find.byType(ElevatedButton); await tester.tap(button); await tester.pumpAndSettle(); expect(find.textContaining('Count'), findsOneWidget); }); } |
パッケージ公開までの手順
pubspec.yamlに environment をsdk: ">=3.0.0 <4.0.0"と記載し、Dart 3 を明示。dart pub publish --dry-runでエラーを事前チェック。- GitHub リポジトリにコードをプッシュし、
flutter pub publish(もしくはdart pub publish) で公開。
ヒント:README にインストール例と簡単なサンプルコード(上記の
MyBadgeなど)を掲載すると利用者が増えやすくなります。
まとめ
この記事では、Flutter 3.19 と Dart 3 の正しいインストール手順 → IDE 設定 → 基本ウィジェット概念 → カスタムウィジェット実装 → パフォーマンス最適化 → テスト・公開 までを体系的に解説しました。
- flutter doctor 後は必ず提示された依存ツールをインストールし、iOS 開発は macOS のみで行うこと。
- Hot Reload/Restart のデフォルトキーは VS Code が r/R(ターミナル)/Android Studio が Shift+F10 など実際のショートカットを使用してください。
- Dart 3 の新機能に目を通し、既存コードの互換性チェックを忘れずに。
これらの手順を踏めば、最新環境で安定した Flutter アプリ開発がすぐに始められます。ぜひ実際にプロジェクトを作成し、独自ウィジェットやパッケージ化に挑戦してみてください。