はじめに
Flutterを網羅的に学習するにあたってRoadmapを使って学習を進めることにしました。
この記事では、Flutter初学者やこれからFlutterを学習し始める方に向けて、Widgetsについてまとめています。
RoadmapはFlutterだけでなく、他の言語やスキルのロードマップも提供されており、何から学習して良いか分からないと悩んでいる方にとって有用なサイトになっています。
ぜひRoadmapを利用して学習してみてください。
Roadmapとは
簡潔に言えば、Roadmap.shは学習者にとってのガイドブックであり、学習の方向性を提供する学習ロードマップサイトです。
初心者から上級者まで、ステップバイステップでスキルを習得するための情報が提供されています。
学習の進め方が分かりやすく示されているだけでなく、個々の項目に参考資料やリソースへのリンクも提供されているので、学習者は目標を設定し、自分自身のペースで学習を進めることができます。
Flutter IDE
FlutterロードマップWidgetsでは以下の21のサイトが紹介されています。興味のある方はぜひお読みください。
- Introduction to widgets: https://docs.flutter.dev/ui
- Widget catalog: https://docs.flutter.dev/ui/widgets
- Flutter Widgets Explained: https://www.youtube.com/watch?v=FU2Eeizo95o
- Official flutter responsive widget: https://docs.flutter.dev/ui/layout/responsive/adaptive-responsive
- Creating responsive and adaptive apps: https://docs.flutter.dev/ui/layout/responsive/adaptive-responsive
- InheritedWidget Official Guide: https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html
- StatelessWidget class: https://api.flutter.dev/flutter/widgets/StatelessWidget-class.html
- Flutter – Stateful vs Stateless Widgets: https://www.geeksforgeeks.org/flutter-stateful-vs-stateless-widgets/
- How to Create Stateless Widgets: https://medium.com/flutter/how-to-create-stateless-widgets-6f33931d859
- StatefulWidget class: https://api.flutter.dev/flutter/widgets/StatefulWidget-class.html
- Flutter – Stateful vs Stateless Widgets: https://www.geeksforgeeks.org/flutter-stateful-vs-stateless-widgets/
- Flutter Tutorial - Stateful Widgets: https://www.youtube.com/watch?v=p5dkB3Mrxdo
- Styling widgets in Flutter: https://docs.flutter.dev/ui/widgets/styling
- Style Your Flutter Widgets: https://www.youtube.com/watch?v=kcq8AbVyMbk
- Material Components widgets: https://docs.flutter.dev/ui/widgets/material
- Flutter – Material Design: https://www.geeksforgeeks.org/flutter-material-design/
- Widget catalog in Flutter: https://docs.flutter.dev/ui/widgets
- Material Designs Guidlines: https://docs.flutter.dev/ui/widgets
- Cupertino (iOS-style) widgets: https://docs.flutter.dev/ui/widgets/cupertino
- Flutter Cupertino Tutorial: https://blog.logrocket.com/flutter-cupertino-tutorial-build-ios-apps-native/
- Flutter Cupertino Widgets: https://www.youtube.com/watch?v=L-TY_5NZ7z4
Widgetとは
Widgetは、アプリのビューを構築するための要素です。画面上に表示されるコンポーネント1、レイアウト、スタイルなどを表現します。Flutterでは、Widgetを組み合わせることによって、複雑なUIを作成することができます。
それぞれのWidget毎にプロパティ2が予め用意されており、色を変えたり、大きさを調整したりなどはすべてWidgetが持つプロパティに設定していきます。
基本 Widget
Text
テキストを表示するための基本的なウィジェットです。
-
Textコンテンツ
文字列を表示するためにtextプロパティにテキストコンテンツを指定します。
Text("Flutter");
-
Textスタイル
テキストのスタイル(フォント、サイズ、色など)をカスタマイズするために、styleプロパティを使用します。
Text(
"カスタムテキストスタイル",
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
color: Colors.blue,
),
);
-
Textの配置
テキストウィジェットのデフォルトの配置は左寄せですが、textAlignプロパティを使用してテキストの配置を調整できます。
Text(
"中央揃えテキスト",
textAlign: TextAlign.center,
);
-
Textの改行
デフォルトでは、長いテキストは自動的に改行されます。\n
を使用して手動で改行を挿入することもできます。
Text(
"1行目\n2行目\n3行目",
);
-
Textの装飾
decorationプロパティを使用して、テキストに下線や取り消し線などの装飾を追加できます。また、decorationColorやdecorationStyleを使用して、それらの装飾の色やスタイルをカスタマイズすることもできます。
Text(
"下線付きテキスト",
style: TextStyle(
decoration: TextDecoration.underline,
decorationColor: Colors.red,
decorationStyle: TextDecorationStyle.dotted,
),
);
-
フォントのカスタマイズ
fontFamilyプロパティを使用して、特定のフォントファミリーを指定できます。
Text(
"カスタムフォント",
style: TextStyle(
fontFamily: "MyCustomFont",
),
);
Image
画像を表示するために使用されるウィジェットです。アプリケーション内のローカル画像や、ネットワークからのリモート画像を表示するために利用できます。
-
ローカル画像の表示
ローカルに保存された画像を表示する場合、プロジェクト内のassetsフォルダなどから画像を読み込みます。AssetImageを使用して、画像を指定します。
Image(
image: AssetImage('assets/images/my_image.png'),
)
また、画像を表示するにはpubspec.yamlファイルでアセットを指定する必要があります。
-
ネットワークからの画像の表示
ネットワーク上の画像を表示する場合、NetworkImageを使用します。URLを指定して画像を読み込みます。
Image(
image: NetworkImage('https://example.com/my_image.jpg'),
)
-
画像のサイズ変更
widthおよびheightプロパティを使用して、画像のサイズを変更できます。
Image(
image: AssetImage('assets/images/my_image.png'),
width: 200.0,
height: 150.0,
)
-
フィットモード
fitプロパティを使用して、画像のフィットモードを設定できます。例えば、BoxFit.coverは画像をアスペクト比3を保持したまま最大まで表示します。
Image(
image: AssetImage('assets/images/my_image.png'),
width: 200.0,
height: 150.0,
fit: BoxFit.cover,
)
-
エラープレースホルダー
errorBuilderプロパティを使用して、画像の読み込みに失敗した場合に表示するカスタムのウィジェットを指定できます。これにより、エラー処理をカスタマイズできます。
Image(
image: NetworkImage('https://example.com/my_image.jpg'),
errorBuilder: (BuildContext context, Object exception, StackTrace? stackTrace) {
return Text('画像を読み込めませんでした');
},
)
Button
ユーザーがアプリケーション内でアクションを実行する際に使用するウィジェットです。ボタンをタップすることで、特定の動作や処理がトリガーされます。
onPressed
プロパティを使用してボタンが押されたときに実行されるコールバック関数を指定します。また、child
プロパティを使用してボタン内に表示されるコンテンツ(テキストまたはアイコン)を指定します。
ボタンウィジェットを選択する際には、アプリケーションのUIやUXに合わせて適切なタイプを選択することが重要です。
-
ElevatedButton
標準的な浮き上がったボタンを表現するためのウィジェットです。通常は、重要なアクションや主要な操作を示すために使用されます。
ElevatedButton(
onPressed: () {
// ボタンが押されたときの処理
},
child: Text('Elevated Button'),
)
-
TextButton
テキストスタイルのボタンを表現するためのウィジェットです。通常は、補助的なアクションやリンクを示すために使用されます。
TextButton(
onPressed: () {
// ボタンが押されたときの処理
},
child: Text('Text Button'),
)
-
OutlinedButton
ボタンの外側にアウトラインを持つウィジェットです。通常は、中程度のアクションを示すために使用されます。
OutlinedButton(
onPressed: () {
// ボタンが押されたときの処理
},
child: Text('Outlined Button'),
)
-
IconButton
アイコンを含むボタンを表現するためのウィジェットです。通常は、アイコンをタップしてアクションをトリガーするために使用されます。
IconButton(
onPressed: () {
// ボタンが押されたときの処理
},
icon: Icon(Icons.star),
)
Container
他のウィジェットを包むコンテナやレイアウトの要素として使用されます。
Containerの基本プロパティ
プロパティ | 内容 |
---|---|
child | 単一のWidgetを作成 |
color | 色の指定 |
alignment | child Widgetの位置を指定 |
height/width | 高さ/幅の指定 |
margin | 外側の余白を指定 |
padding | 内側の余白を指定 |
decoration | 外観をカスタマイズ |
Container(
width: 200.0,
height: 150.0,
alignment: Alignment.center,
margin: EdgeInsets.all(20.0),
padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
decoration: BoxDecoration(
color: Colors.blue,
border: Border.all(color: Colors.black, width: 2.0),
borderRadius: BorderRadius.circular(10.0),
boxShadow: [
BoxShadow(
color: Colors.grey,
blurRadius: 5.0,
),
],
),
child: Text(
'Container',
style: TextStyle(
fontSize: 18.0,
color: Colors.white,
),
),
);
Card
カードを表示するために使用されるウィジェットです。通常、情報をコンパクトに表示し、影や角丸などのスタイルを持つ要素として利用されます。
Cardの基本プロパティ
プロパティ | 説明 |
---|---|
child | カード内に表示するコンテンツを指定 |
elevation | カードの影の深さを設定 |
shape | カードの形状をカスタマイズ |
margin | カードの周りの余白を設定 |
color | カードの背景色を指定 |
-
child
Card内に表示するコンテンツを指定します。Text、Imageなどのウィジェットを含めることが多いですが、他のウィジェットも含めることができます。
Card(
child: Column(
children: <Widget>[
Text('カードのタイトル'),
Text('カードの内容'),
],
),
)
-
elevation
カードの影の深さを設定します。値を大きくするほど、カードが浮き上がって見えます。デフォルト値は2.0です。
Card(
elevation: 5.0,
child: /* ... */,
)
-
shape
カードの形状をカスタマイズできます。RoundedRectangleBorderやBeveledRectangleBorderを使用して、角丸や斜めの角を持つカードを作成します。
Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
child: /* ... */,
)
-
margin
カードの周りの余白を設定します。他の要素との間にスペースを追加するために使用されます。
Card(
margin: EdgeInsets.all(10.0),
child: /* ... */,
)
-
color
カードの背景色を指定できます。通常、カードに色を設定することはありませんが、必要に応じて使用できます。
Card(
color: Colors.blue,
child: /* ... */,
)
Column / Row
画面上のウィジェットの配置と整列を制御するために使用されます。
Columnウィジェット
子要素を垂直に配置するためのウィジェットです。縦に並ぶウィジェットのグループを作成するのに使用されます。childrenプロパティにColumn内に配置するウィジェットをリストで指定します。
Column(
children: <Widget>[
Text('項目1'),
Text('項目2'),
Text('項目3'),
],
)
子要素が上から下に順番に配置され、親要素の幅に合わせて伸縮します。
Rowウィジェット
子要素を水平に配置するためのウィジェットです。横に並ぶウィジェットのグループを作成するのに使用されます。childrenプロパティにRow内に配置するウィジェットをリストで指定します。
Row(
children: <Widget>[
Text('アイコン'),
Text('テキスト'),
],
)
子要素が左から右に順番に配置され、親要素の高さに合わせて伸縮します。
ColumnとRowウィジェットを使用したサンプルコード
Column(
children: <Widget>[
Text('タイトル'),
Text('サブタイトル'),
Row(
children: <Widget>[
Icon(Icons.star),
Text('5.0'),
],
),
],
)
ListView
スクロール可能なリストを作成するためのウィジェットです。大量のアイテムをスクロール可能なリストとして表示することができます。
ListViewの基本プロパティ
プロパティ | 説明 |
---|---|
children | ListView内に配置する子要素のリストを指定 |
scrollDirection | ListViewのスクロール方向を設定 |
itemBuilder | 動的なリストを生成する |
itemCount | ListView.builderを使用する場合、生成するアイテムの総数を指定 |
physics | スクロールの挙動を制御する |
-
children
childrenプロパティは、ListView内に配置する子要素(ウィジェット)のリストを指定します。これらの子要素は通常、リスト内に表示される個々のアイテムです。
ListView(
children: <Widget>[
ListTile(title: Text('アイテム1')),
ListTile(title: Text('アイテム2')),
// 他のアイテム...
],
)
-
scrollDirection
ListViewのスクロール方向を設定します。デフォルトでは垂直方向(Axis.vertical)ですが、水平方向にスクロールしたい場合はAxis.horizontalを使用します。
ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
ListTile(title: Text('アイテム1')),
ListTile(title: Text('アイテム2')),
// 水平に並ぶアイテム...
],
)
-
itemBuilder
動的なリストを生成する場合にカスタムアイテムを生成する関数を指定できます。ListView.builder
と組み合わせて使用されます。
ListView.builder(
itemCount: items.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(title: Text(items[index]));
},
)
-
itemCount
ListView.builderを使用する場合に生成するアイテムの総数を指定します。
ListView.builder(
itemCount: items.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(title: Text(items[index]));
},
)
itemBuilder
とitemCount
に関してわかりやすい記事があったので、是非読んでみてください。
-
physics
スクロールの挙動を制御するために使用されます。例えば、スクロールの動きやバウンスなどをカスタマイズできます。
ListView(
physics: BouncingScrollPhysics(),
children: <Widget>[
// アイテム...
],
)
AppBar
アプリケーションの上部に表示されるアプリケーションバーを作成するためのウィジェットです。アプリケーションのタイトル、アイコン、アクションボタン、その他メニューアイテムを配置することが一般的です。
AppBarの基本プロパティ
プロパティ | 説明 |
---|---|
title | アプリケーションバーに表示されるタイトルを設定 |
actions | アプリケーションバーに表示されるアイコンボタンやメニューアイテムのリストを指定 |
leading | アプリケーションバーの左端に表示される要素を指定 |
backgroundColor | アプリケーションバーの背景色を設定 |
elevation | アプリケーションバーの影の深さを設定 |
-
title
アプリケーションバーに表示されるタイトルを設定します。
AppBar(
title: Text('My App'),
)
-
actions
アプリケーションバーに表示されるアクションボタン(アイコンボタンやメニューアイテム)のリストを指定します。
AppBar(
actions: <Widget>[
IconButton(
icon: Icon(Icons.search),
onPressed: () {
// 検索アクションの処理
},
),
IconButton(
icon: Icon(Icons.settings),
onPressed: () {
// 設定アクションの処理
},
),
],
)
-
leading
アプリケーションバーの左端に表示される要素を指定します。ハンバーガーメニューアイコンなどを配置する際に多く使用されます。
AppBar(
leading: IconButton(
icon: Icon(Icons.menu),
onPressed: () {
// メニューアクションの処理
},
),
)
-
backgroundColor
アプリケーションバーの背景色を設定します。
AppBar(
backgroundColor: Colors.blue,
)
-
elevation
アプリケーションバーの影の深さを設定します。値を大きくするほど、アプリケーションバーが浮き上がって見えます。
AppBar(
elevation: 4.0,
)
Scaffold
Scaffoldは「足場」という意味になりますが、アプリ画面でよく使われるメニュー表示方法を含めて画面全体を管理するウィジェットです。
Scaffoldの基本プロパティ
プロパティ | 説明 |
---|---|
appBar | AppBarウィジェットを指定 |
body | 画面の本文コンテンツを指定 |
drawer | ハンバーガーメニューを指定 |
floatingActionButton | 画面のフローティングアクションボタンを指定 |
floatingActionButtonLocation | フローティングアクションボタンの位置を設定 |
persistentFooterButtons | 画面の下部に固定されるボタンのリストを指定 |
backgroundColor | Scaffoldの背景色を設定 |
resizeToAvoidBottomInset | キーボードが表示されたときにコンテンツをスクロールするかどうかを設定 |
extendBody | bodyコンテンツを画面の下部まで拡張するかどうかを制御 |
extendBodyBehindAppBar | appBarの下にコンテンツを表示するかどうかを制御 |
-
appBar
AppBarウィジェットを指定します。アプリケーションの上部に表示され、通常はタイトルやアクションボタンを含みます。
Scaffold(
appBar: AppBar(
title: Text('My App'),
),
// 他のウィジェットを含む
)
-
body
画面の本文コンテンツを指定します。ページの中身やリストビュー、フォームなどを含みます。
Scaffold(
body: Center(
child: Text('Hello, World!'),
),
// 他のウィジェットを含む
)
-
drawer
ハンバーガーメニューを指定します。通常、サイドバーのナビゲーションメニューや設定メニューを表示するのに使用されます。
Scaffold(
appBar: AppBar(
title: Text('My App'),
),
drawer: Drawer(
// ハンバーガーメニューの内容を指定
),
// 他のウィジェットを含む
)
-
floatingActionButton
画面のフローティングアクションボタンを指定します。主要なアクションや追加操作を実行するために使用されます。
Scaffold(
appBar: AppBar(
title: Text('My App'),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// フローティングアクションの処理
},
child: Icon(Icons.add),
),
// 他のウィジェットを含む
)
-
floatingActionButtonLocation
フローティングアクションボタンの配置を制御します。設定には次のようなものがあります。- FloatingActionButtonLocation.endFloat: デフォルト設定。画面の右下に配置されます。
- FloatingActionButtonLocation.centerFloat: 画面の中央下に配置されます。
- FloatingActionButtonLocation.miniStartTop: 画面の左上に小さなサイズで配置されます。
Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {
// フローティングアクションの処理
},
child: Icon(Icons.add),
),
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
// 他のウィジェットを含む
)
-
persistentFooterButtons
画面の下部に固定されるボタン(コンテンツとは独立して表示されるアクションボタン)を指定します。
Scaffold(
persistentFooterButtons: <Widget>[
ElevatedButton(
onPressed: () {
// ボタンの処理
},
child: Text('ボタン1'),
),
ElevatedButton(
onPressed: () {
// ボタンの処理
},
child: Text('ボタン2'),
),
],
// 他のウィジェットを含む
)
-
backgroundColor
Scaffoldの背景色を設定します。通常はColorsクラスの色を指定しますが、任意のColorオブジェクトを使用することもできます。
Scaffold(
backgroundColor: Colors.grey[200],
// 他のウィジェットを含む
)
-
resizeToAvoidBottomInset
キーボードが表示された際の画面のリサイズを制御します。trueに設定すると、キーボードが表示されたときにコンテンツが自動的にスクロールして隠れないようになります。
Scaffold(
resizeToAvoidBottomInset: false, // スクロールなし
// 他のウィジェットを含む
)
-
extendBody
bodyコンテンツを画面の下部まで拡張するかどうかを制御します。trueに設定すると、背景色やデザインがbodyまで広がり、下部ナビゲーションバーを含めた全体の高さになります。
Scaffold(
extendBody: true,
// 他のウィジェットを含む
)
-
extendBodyBehindAppBar
appBarの下にコンテンツを表示するかどうかを制御します。trueに設定すると、appBarの下にbodyコンテンツが表示され、appBarの背後に配置されます。
Scaffold(
extendBodyBehindAppBar: true,
// 他のウィジェットを含む
)
Scaffoldサンプルコード
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyScaffoldApp(),
);
}
}
class MyScaffoldApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('My App'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.search),
onPressed: () {
// 検索アクションの処理
},
),
],
),
body: Center(
child: Text('Hello, World!'),
),
drawer: Drawer(
child: ListView(
children: <Widget>[
ListTile(
title: Text('メニュー1'),
onTap: () {
// メニュー1の処理
},
),
ListTile(
title: Text('メニュー2'),
onTap: () {
// メニュー2の処理
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// フローティングアクションの処理
},
child: Icon(Icons.add),
),
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
persistentFooterButtons: <Widget>[
ElevatedButton(
onPressed: () {
// ボタン1の処理
},
child: Text('ボタン1'),
),
ElevatedButton(
onPressed: () {
// ボタン2の処理
},
child: Text('ボタン2'),
),
],
backgroundColor: Colors.grey[200],
resizeToAvoidBottomInset: true,
extendBody: true,
extendBodyBehindAppBar: false,
);
}
}
InheritedWidget
ウィジェットツリー内でデータを共有するための仕組みです。親ウィジェットから子ウィジェットにデータを渡す際に使用します。データをInheritedWidgetに持たせることで、依存関係がInheritedWidgetの下にあるWidgetならどこからでもデータを参照できるようになります。
Providerパッケージ
やRiverpodパッケージ
の普及によりInheritedWidgetを使用する機会はほとんど無くなってきていますが、InheritedWidgetの仕組みを理解することでProviderパッケージやRiverpodパッケージへの理解を深めることができます。
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
// カウンターの状態を提供するカスタムInheritedWidget
class CounterProvider extends InheritedWidget {
final int counter; // カウンターの値
final Function() increment; // カウンターを増やす関数
const CounterProvider({
super.key,
required this.counter, // 初期カウンターの値
required this.increment, // カウンターを増やす関数
required Widget child, // 子ウィジェット
}) : super(child: child);
// InheritedWidgetを使ってカウンターの状態を取得するためのメソッド
static CounterProvider? of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<CounterProvider>();
}
@override
bool updateShouldNotify(covariant InheritedWidget oldWidget) {
return false; // このメソッドは更新通知の制御に使われますが、この例では常にfalseを返しています
}
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: CounterApp(),
);
}
}
class CounterApp extends StatefulWidget {
const CounterApp({super.key});
@override
CounterAppState createState() => CounterAppState();
}
class CounterAppState extends State<CounterApp> {
int _counter = 0; // カウンターの初期値
// カウンターを増やす関数
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return CounterProvider(
counter: _counter, // カウンターの初期値を設定
increment: _incrementCounter, // カウンターを増やす関数
child: Scaffold(
appBar: AppBar(
title: const Text('Counter App'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'Count:',
style: TextStyle(fontSize: 20.0),
),
Builder(
builder: (context) {
final counterProvider = CounterProvider.of(context);
return Text(
'${counterProvider?.counter}', // カウンターの値を表示
style: const TextStyle(fontSize: 40.0),
);
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
child: const Icon(Icons.add),
),
),
);
}
}
StatelessWidget
状態を持たないウィジェットです。一度作成されたらその内容や見た目が変更されないウィジェットになりますので、通常、静的なコンテンツを表示するために使用されます。ウィジェットツリー内での再構築の必要がないため、効率的に動作します。
StatelessWidgetのサンプルコード
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Hello Flutter Example',
home: Scaffold(
appBar: AppBar(
title: Text('Hello Flutter Example'),
),
body: Center(
// Stateless Widgetを呼び出す
child: HelloFlutter(),
),
),
);
}
}
class HelloFlutter extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Text(
'Hello, Flutter!',
style: TextStyle(fontSize: 24),
);
}
}
StatefulWidget
状態を持つウィジェットです。状態(State)は、ウィジェットが再描画されるときに変更することができます。ユーザー入力や時間の経過に応じて画面の情報を変更する際などに使用されます。
StatefulWidget
は不変であるWidgetを継承しているので、StatefulWidget
自体は不変である必要があります。ではなぜStatefulWidget
が状態を持つウィジェットなのか? その理由はState
です。State
に可変の要素を持たせています。
Flutter SDKはStatefulWidget
を何度も再作成することができ、それに対しStateは1度だけ作成されます。そして、再作成されたStatefulWidgetは既に作成されているStateを参照することで、Widgetの再作成(画面の描画)を行うことができます。
StatefulWidgetのサンプルコード
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Counter App Example',
home: CounterApp(),
);
}
}
class CounterApp extends StatefulWidget {
@override
_CounterAppState createState() => _CounterAppState();
}
class _CounterAppState extends State<CounterApp> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Counter App'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Counter Value:',
style: TextStyle(fontSize: 20),
),
Text(
'$_counter',
style: TextStyle(fontSize: 48, fontWeight: FontWeight.bold),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
Material Widgets
FlutterのデザインライブラリであるMaterial Design
に基づいて設計されたウィジェットのセットです。Material Designは、Googleが提供するデザインガイドラインで、アプリケーションの外観と動作を構築するのに使用されます。
例
-
RaisedButton
タップすると反応するデザインで、ユーザーアクションを促します。 -
TextField
ユーザーがテキストを入力できるウィジェットで、バリデーションやテキスト操作に対応します。 -
Card
情報を整理して表示し、視覚的な階層を作成するのに使用されます。 -
AppBar
アプリケーションの上部にタイトルやアクションボタンを表示し、ナビゲーションメニューを提供します。 -
ListView
スクロール可能なリストを表示し、大量のデータを効果的に表示できます。 -
SnackBar
一時的なメッセージや通知を表示するためのウィジェットです。 -
BottomNavigationBar
アプリケーションの下部にナビゲーションメニューを提供し、異なる画面間を移動できます。
Cupertino Widgets
iOSのデザインガイドラインに従ったFlutterのウィジェットの一部で、iOSアプリケーションを開発する際、iOSのネイティブな外観と動作を構築するために使用されます。
例
-
CupertinoButton
タップすると反応するデザインで、iOSアプリケーションに一般的に使用されます。 -
CupertinoTextField
テキスト入力フィールド。iOSのテキスト入力フィールドの外観と動作を提供します。 -
CupertinoNavigationBar
アプリケーションの上部にタイトルやアクションボタンを表示し、iOSアプリケーションに一般的に使用されます。 -
CupertinoAlertDialog
メッセージやアクションボタンを含むアラートを表示します。iOSアプリケーションに一般的に使用されます。 -
CupertinoPicker
ドロップダウンリストや選択ウィジェットとして使用され、iOSアプリケーションに一般的に使用されます。
Responsive Widgetとは
Responsive Widgetとは異なる画面サイズやデバイスに対応したウィジェット(コンポーネント)のことです。Flutterにおいて、Responsive Widgetを作成するためには、以下のようなアプローチがあります。
MediaQueryを使用する
MediaQueryクラスは、デバイスの画面サイズ、方向、ピクセル比率などの情報にアクセスするために使用されます。これを使用して、画面幅に基づいて異なるウィジェットを表示するなどの条件分岐を行うことができます。
final double screenWidth = MediaQuery.of(context).size.width;
if (screenWidth > 600) {
// 大画面向けのウィジェットを表示
return DesktopWidget();
} else {
// スマートフォン向けのウィジェットを表示
return MobileWidget();
}
LayoutBuilderを使用する
LayoutBuilderウィジェットは、親ウィジェットのサイズに基づいて子ウィジェットを構築するのに使用されます。親ウィジェットのサイズに合わせて子ウィジェットの配置やサイズを動的に調整できるため、ウィンドウの幅に応じて列の数を調整する際などに使用します。
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 600) {
// 大画面向けの表示
return Row(
children: <Widget>[
Expanded(child: Widget1()),
Expanded(child: Widget2()),
],
);
} else {
// スマートフォン向けの表示
return Column(
children: <Widget>[
Widget1(),
Widget2(),
],
);
}
},
)
Responsiveパッケージを使用する
Flutterには、レスポンシブデザインを簡素化するためのパッケージが多数存在します。例えば、responsive_framework
やflutter_responsive
などのパッケージを使用すると、簡単にレスポンシブなレイアウトを作成できます。プロジェクトや使用感などご自身に合ったパッケージを選択してみてください。
FlexやExpandedを使用する
FlexウィジェットやExpandedウィジェットを活用することで、ウィジェットのサイズや配置を調整できます。これらのウィジェットを使用することで、利用可能なスペースを最大限に活用することができます。
FlexibleとExpandedの主な違いは、サイズ調整の方法にあります。Flexibleはウィジェットのサイズを柔軟に調整できるのに対して、Expandedは利用可能な空間をすべて埋めるようにウィジェットを拡張します。
参考資料
-
コンポーネント
単体では使用せず、他のプログラムから呼び出されたり連結されたりして使用されるプログラム部品のこと
こちらにわかりやすい記事があったので、是非読んでみてください。 ↩ -
プロパティ
取り扱う対象(オブジェクト)の持つ設定や状態、属性などの情報のことです。
こちらにわかりやすい記事があったので、是非読んでみてください。 ↩ -
アスペクト比
アスペクト比とは、画像や動画等の映像の縦横比のことを指します。一般的にワイド(16:9)とスタンダード(4:3)の2つが基本的なアスペクト比とされています。
https://gimo.jp/glossary/details/aspect_ratio.html ↩