Skip to content

基本構文

1. MyApp ウィジェットの詳細解説

Section titled “1. MyApp ウィジェットの詳細解説”

MyAppは、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'),
);
}
}
  • runApp(): アプリケーションを起動し、指定されたウィジェット(通常はMyApp)を画面に表示します。
  • MaterialApp: アプリのルートウィジェットとして使われます。titleやthemeといったアプリ全体の情報を設定し、マテリアルデザインのウィジェットを使えるようにします。
  • home: アプリの最初の画面を定義します。

Scaffoldは、マテリアルデザインの基本的なレイアウト構造を提供するウィジェットです。

Scaffold(
appBar: AppBar(
title: const Text('タイトル'),
),
body: const Center(
child: Text('Hello, Flutter!'),
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: const Icon(Icons.add),
),
)
  • appBar: アプリの上部に表示されるバーです。タイトルやアクションを配置できます。
  • body: メインコンテンツを配置する領域です。
  • floatingActionButton: 画面の右下に表示されるアクションボタンです。

ColumnとRowは、ウィジェットを縦または横に並べるための最も基本的なレイアウトウィジェットです。

Column(
mainAxisAlignment: MainAxisAlignment.center, // 垂直方向の中央揃え
children: const <Widget>[
Text('First'),
Text('Second'),
Text('Third'),
],
)
  • Column: ウィジェットを縦に並べます。
  • Row: ウィジェットを横に並べます。

これらのウィジェットを組み合わせることで、複雑なレイアウトを構築できます。

状態管理は最初に決めておくべし 🧠

Section titled “状態管理は最初に決めておくべし 🧠”

プロジェクトを始める前に、状態管理の方法を決めておかないと、後で大変なことになります。

  • 小規模なアプリならProviderから始めるのがおすすめです。学習コストが低く、シンプルに扱えます。
  • 大規模アプリやチーム開発では、RiverpodやBlocといった、より厳密な状態管理が可能なライブラリを検討すべきです。これらのライブラリは、コードの予測可能性とテスト容易性を高めてくれます。

StatelessWidgetとStatefulWidgetの使い分けを理解する 🤔

Section titled “StatelessWidgetとStatefulWidgetの使い分けを理解する 🤔”

Flutterのウィジェットは、状態を持つか持たないかで2種類に分けられます。

  • StatelessWidget: 状態を持たないウィジェットです。一度描画されたら、再描画されることはありません。ボタンやアイコンなど、変化しないUI要素に使います。
  • StatefulWidget: 状態を持つウィジェットです。ユーザーの操作などによって状態が変化し、再描画されます。テキスト入力フォームやチェックボックスなど、状態が変わるUI要素に使います。

最初のうちはStatefulWidgetばかり使ってしまいがちですが、可能な限りStatelessWidgetを使うことで、アプリのパフォーマンスとメンテナンス性が向上します。

レスポンシブデザインの工夫 📐

Section titled “レスポンシブデザインの工夫 📐”

モバイルアプリは、様々な画面サイズで使われます。

画面サイズに応じてレイアウトを調整するために、MediaQueryやLayoutBuilderを積極的に使いましょう。LayoutBuilderは、親ウィジェットが提供する制約(幅や高さ)に基づいてUIを構築できるため、特に柔軟なUIを組むのに便利です。

依存関係の競合とpubコマンド 🐛

Section titled “依存関係の競合とpubコマンド 🐛”

パッケージを大量に追加すると、バージョンの競合が頻繁に起こります。

  • flutter pub outdated: どのパッケージに新しいバージョンがあるかを確認できます。
  • flutter pub get: 依存関係を最新の状態に更新します。
  • flutter pub upgrade: pubspec.yamlに指定されたバージョン範囲内で、パッケージを最新のものにアップグレードします。
  • flutter clean: どうにもならなくなったときは、まずこのコマンドを試してみましょう。ビルドキャッシュをクリアし、依存関係を再構築してくれます。

複雑なウィジェットの組み合わせ例 🧩

Section titled “複雑なウィジェットの組み合わせ例 🧩”

これらの基本ウィジェットを組み合わせることで、より複雑なUIを構築できます。

Scaffold(
appBar: AppBar(
title: const Text('ウィジェットの組み合わせ'),
),
body: SingleChildScrollView( // 画面がスクロールできるようにする
child: Column(
children: [
const Text('縦に並ぶウィジェット'),
Row( // 横に並ぶウィジェット
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: const [
Icon(Icons.star, color: Colors.yellow),
Icon(Icons.star, color: Colors.yellow),
Icon(Icons.star, color: Colors.yellow),
],
),
Container(
height: 150,
color: Colors.blue,
child: const Center(
child: Text('コンテナ'),
),
),
],
),
),
);

この例では、SingleChildScrollView、Column、Row、Containerといったウィジェットを組み合わせて、より豊かなレイアウトを実現しています。

Containerは、Flutterで最も汎用的なウィジェットの一つです。パディング、マージン、色、ボーダー、角丸などの装飾を施したり、サイズを指定したりするのに使われます。

Container(
margin: const EdgeInsets.all(16), // 外側の余白(マージン)
padding: const EdgeInsets.all(16), // 内側の余白(パディング)
height: 100, // 高さを指定
width: 100, // 幅を指定
decoration: BoxDecoration( // コンテナの装飾
color: Colors.blue,
borderRadius: BorderRadius.circular(12), // 角を丸くする
border: Border.all(color: Colors.red, width: 2), // ボーダー
boxShadow: const [ // 影をつける
BoxShadow(
color: Colors.black26,
blurRadius: 10,
offset: Offset(0, 5),
),
],
),
child: const Center(
child: Text('コンテナ'),
),
)

2. Expanded と Flexible ウィジェット

Section titled “2. Expanded と Flexible ウィジェット”

RowやColumnの子ウィジェットを、利用可能なスペースに合わせて拡張または調整するために使われます。レスポンシブなレイアウトを構築する上で非常に重要です。

  • Expanded: 親ウィジェットの残りのスペースをすべて占有します。flexプロパティを使って、複数のExpandedウィジェット間でスペースを分配できます。
Row(
children: <Widget>[
Container(width: 50, color: Colors.red),
Expanded( // 残りのスペースをすべて占有
child: Container(color: Colors.green),
),
Container(width: 50, color: Colors.blue),
],
)
  • Flexible: 親ウィジェットの残りのスペースを、子ウィジェットのコンテンツサイズに合わせて柔軟に調整します。fitプロパティでフィット方法を制御できます。ExpandedはFlexibleの特殊なケース(fit: FlexFit.tight)です。
Row(
children: <Widget>[
Flexible( // コンテンツサイズに合わせてスペースを調整
child: Text('長いテキストを折り返す'),
),
Flexible(
child: Container(color: Colors.orange, height: 50),
),
],
)

Stackウィジェットは、複数のウィジェットを重ねて配置するために使われます。ウィジェットをz軸方向(手前/奥)に重ねたい場合に便利です。

Stack(
alignment: Alignment.center, // 子ウィジェットを中央に配置
children: <Widget>[
Container(
width: 200,
height: 200,
color: Colors.red,
),
Container(
width: 150,
height: 150,
color: Colors.blue,
),
Positioned( // 特定の位置に子ウィジェットを配置
bottom: 10,
right: 10,
child: Icon(Icons.star, size: 50, color: Colors.yellow),
),
],
)

PositionedウィジェットをStackの子として使うことで、上、下、左、右からの距離を指定してウィジェットを正確に配置できます。

SizedBoxは、特定のサイズの空きスペースや、子ウィジェットのサイズを固定したいときに使う、非常にシンプルなウィジェットです。widthとheightプロパティを使って、簡単にサイズを調整できます。特に、RowやColumnの中で、ウィジェット間に一定のスペースを空けるのに便利です。

Row(
children: const <Widget>[
Text('商品名'),
SizedBox(width: 8), // 8ピクセルの横の余白
Text('¥1,200'),
SizedBox(width: 16), // 16ピクセルの横の余白
Text('在庫あり'),
],
)

Paddingは、子ウィジェットの外側に一定の余白(パディング)を追加するウィジェットです。これにより、ウィジェット間の見栄えを整えることができます。EdgeInsetsを使って、上下左右のパディングを細かく設定できます。

Padding(
padding: const EdgeInsets.all(16), // 上下左右に16ピクセルのパディング
child: Container(
color: Colors.blue,
child: const Text('パディング付きのコンテナ'),
),
)
  • EdgeInsets.all(double): 全方向に同じパディングを適用します。
  • EdgeInsets.symmetric(horizontal: double, vertical: double): 垂直方向と水平方向のパディングを個別に設定します。
  • EdgeInsets.fromLTRB(left, top, right, bottom): 上下左右のパディングをすべて個別に設定します。

FlexibleとExpandedは、RowやColumn内でのウィジェットのサイズを動的に調整するのに不可欠です。特に、flexプロパティを使うことで、子ウィジェット間のスペース配分をより細かく制御できます。

Column(
children: <Widget>[
Flexible(
flex: 1, // 1/3のスペースを占有
child: Container(color: Colors.red),
),
Flexible(
flex: 2, // 2/3のスペースを占有
child: Container(color: Colors.blue),
),
],
)

この例では、Columnの利用可能なスペース全体を3つの部分に分け、赤いコンテナが1つの部分を、青いコンテナが2つの部分を占めるようにしています。