さて抽象的な説明が続きましたが、この章ではサンプルアプリの中身をより詳しく見てみましょう。
main.dart
main.dart
は Flutter アプリのエントリーポイントとなるファイルです。flutter run
コマンドで実際に実行しているファイルがこちらのファイルです。
Flutter でアプリを開発していくにあたって重要な要素が詰まっているので1つ1つ見ていきましょう。
main.dart
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
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.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
import
import [インポートするファイルのパス]
でファイル内で使用するパッケージやファイルを読み込んでいます。
import 'package:flutter/material.dart';
上記の material
パッケージはマテリアルデザインの UI コンポーネントを使う為のパッケージで、UI を構成するファイルでは必ずと言って良いほどインポートすることになります。
void main()
ファイルを指定して実行すると呼び出されるのが main
関数です。
flutter run
コマンドでは指定がなければ自動的にlib/main.dart
が実行され、下記の main
関数が呼び出されます。
flutter run -t [ファイル名]
とすることで実行するファイルを指定することも出来、その場合はそのファイルの main
関数が呼び出されます。
void main() {
runApp(const MyApp());
}
runApp()
runApp
関数はアプリを構成する Widget 群を受け取り、描画エンジンに繋げる役割を担います。この 関数に渡される Widget がアプリのルート(根っこ) になります。
runApp(const MyApp());
MyApp
クラス
前述したStatelessWidget
を継承するクラスです。StatelessWidget
の説明は前項でしたとして、ここでは中身についていくつかポイントとなる部分を見ていきましょう。
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
MaterialApp
前述のrunApp
に渡され今回のアプリの出発点となっている Widget です。
このクラスは Google が提供するマテリアルデザインに準拠する Widget とそれらで使う様々な機能を提供してくれる Widget です。
Apple が提供する Cupertino デザインに準拠する Widget と機能を提供するCupertinoApp
もあります。よほど Cupertino デザインに寄せたいなどでなければ、基本MaterialApp
で構いません。
アプリ全体のカラーテーマやアプリのルーティングなど様々な設定を定義することができます。
home
フィールド には最初に表示する Widget を指定します。今回はMyHomePage
を指定しているので、アプリを立ち上げるとMyHomePage
が表示されています。
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
ThemeData
アプリ全体のビジュアルに関するテーマを定義するクラスです。
下記のクラス定義を見ていただければ分かるとおり、非常に多くの引数を取り、アプリ全体の色やフォント、ボタンの形などを定義することができます。
有効に使うことで、アプリ全体のデザインを一括で管理・変更することができます。
ThemeData
ThemeData ThemeData({
bool? applyElevationOverlayColor,
NoDefaultCupertinoThemeData? cupertinoOverrideTheme,
Iterable<ThemeExtension<dynamic>>? extensions,
InputDecorationTheme? inputDecorationTheme,
MaterialTapTargetSize? materialTapTargetSize,
PageTransitionsTheme? pageTransitionsTheme,
TargetPlatform? platform,
ScrollbarThemeData? scrollbarTheme,
InteractiveInkFeatureFactory? splashFactory,
VisualDensity? visualDensity,
bool? useMaterial3,
ColorScheme? colorScheme,
Color? colorSchemeSeed,
Brightness? brightness,
MaterialColor? primarySwatch,
Color? primaryColor,
Color? primaryColorLight,
Color? primaryColorDark,
Color? focusColor,
Color? hoverColor,
Color? shadowColor,
Color? canvasColor,
Color? scaffoldBackgroundColor,
Color? bottomAppBarColor,
Color? cardColor,
Color? dividerColor,
Color? highlightColor,
Color? splashColor,
Color? selectedRowColor,
Color? unselectedWidgetColor,
Color? disabledColor,
Color? secondaryHeaderColor,
Color? backgroundColor,
Color? dialogBackgroundColor,
Color? indicatorColor,
Color? hintColor,
Color? errorColor,
Color? toggleableActiveColor,
String? fontFamily,
Typography? typography,
TextTheme? textTheme,
TextTheme? primaryTextTheme,
IconThemeData? iconTheme,
IconThemeData? primaryIconTheme,
AppBarTheme? appBarTheme,
MaterialBannerThemeData? bannerTheme,
BottomAppBarTheme? bottomAppBarTheme,
BottomNavigationBarThemeData? bottomNavigationBarTheme,
BottomSheetThemeData? bottomSheetTheme,
ButtonBarThemeData? buttonBarTheme,
ButtonThemeData? buttonTheme,
CardTheme? cardTheme,
CheckboxThemeData? checkboxTheme,
ChipThemeData? chipTheme,
DataTableThemeData? dataTableTheme,
DialogTheme? dialogTheme,
DividerThemeData? dividerTheme,
DrawerThemeData? drawerTheme,
ElevatedButtonThemeData? elevatedButtonTheme,
FloatingActionButtonThemeData? floatingActionButtonTheme,
ListTileThemeData? listTileTheme,
NavigationBarThemeData? navigationBarTheme,
NavigationRailThemeData? navigationRailTheme,
OutlinedButtonThemeData? outlinedButtonTheme,
PopupMenuThemeData? popupMenuTheme,
ProgressIndicatorThemeData? progressIndicatorTheme,
RadioThemeData? radioTheme,
SliderThemeData? sliderTheme,
SnackBarThemeData? snackBarTheme,
SwitchThemeData? switchTheme,
TabBarTheme? tabBarTheme,
TextButtonThemeData? textButtonTheme,
TextSelectionThemeData? textSelectionTheme,
TimePickerThemeData? timePickerTheme,
ToggleButtonsThemeData? toggleButtonsTheme,
TooltipThemeData? tooltipTheme,
ExpansionTileThemeData? expansionTileTheme,
bool? useTextSelectionTheme,
Color? textSelectionColor,
Color? cursorColor,
Color? textSelectionHandleColor,
Color? accentColor,
Brightness? accentColorBrightness,
TextTheme? accentTextTheme,
IconThemeData? accentIconTheme,
Color? buttonColor,
bool? fixTextFieldOutlineLabel,
Brightness? primaryColorBrightness,
AndroidOverscrollIndicator? androidOverscrollIndicator,
})
Key
1つ1つの Widget を一意に特定する為の識別子です。
アプリは非常に多くの Widget で構成されます。時には同じ Widget が複数並ぶような場合もあります。このような場合、Flutter はどの Widget を操作であったり、更新すべきかであったりを判断する必要があり、その際に用いられるのが Key
クラス です。
nullable な引数なので、必ず渡す必要はありませんが StatelessWidget、StatefulWidget を定義する際は必ず引数として記述します。
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
...
}
MyHomePage
クラス
前述したStatefulWidget
を継承したクラスです。StatefulWidget
については前項を参照していただくとして、今回はMyHomepage
クラスが返している Widget 群を見ていきましょう。
MyHomePage
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
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.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
Scaffold
Widget
Scaffold
widget はマテリアルデザインのアプリを作る(MaterialApp
を使う)場合に、ページの元となる widget です。「白紙のページ」と考えるとイメージがつきやすいかと思います。body
に渡す Widget がページの中身になります。
その他にもマテリアデザインのページでよく使われれる AppBar
や FloatingActionButton
、Drawer
、BottomNavigationBar
などの Widget を対応するフィールドに渡すことで、それらをページにレイアウトしてくれます。
scaffold
(new) Scaffold Scaffold({
Key? key,
PreferredSizeWidget? appBar,
Widget? body,
Widget? floatingActionButton,
FloatingActionButtonLocation? floatingActionButtonLocation,
FloatingActionButtonAnimator? floatingActionButtonAnimator,
List<Widget>? persistentFooterButtons,
AlignmentDirectional persistentFooterAlignment = AlignmentDirectional.centerEnd,
Widget? drawer,
void Function(bool)? onDrawerChanged,
Widget? endDrawer,
void Function(bool)? onEndDrawerChanged,
Widget? bottomNavigationBar,
Widget? bottomSheet,
Color? backgroundColor,
bool? resizeToAvoidBottomInset,
bool primary = true,
DragStartBehavior drawerDragStartBehavior = DragStartBehavior.start,
bool extendBody = false,
bool extendBodyBehindAppBar = false,
Color? drawerScrimColor,
double? drawerEdgeDragWidth,
bool drawerEnableOpenDragGesture = true,
bool endDrawerEnableOpenDragGesture = true,
String? restorationId,
})
AppBar
Widget
画面上部のアプリバーを表示する Widget です。title
に渡す Widget がアプリバーのタイトルになります。
appBar: AppBar(
title: Text(widget.title),
),
Center
Widget
名前の通り、子 Widget を中央に配置する Widget です。
Center
はAppBar
の様に UI コンポーネントを描画する Widget ではなく、レイアウトのみを行う Widget です。Flutter にはこのようなレイアウトのみを行う Widget も多数用意されています。
body: Center(
child: Widget(),
),
Column
Widget
縦に子 Widget を配置する Widget です。こちらもCenter
と同様に、レイアウトのみを行う Widget です。
Column
は単一の子 Widget ではなく、複数の子 Widget を持つことができます。受け取った複数の子 Widget をカラム(列)に並べます。その他にもその子 Widget をどのように配置するかを指定する様々なプロパティも用意されています。
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Widget(),
Widget(),
],
),
Text
Widget
名前通り、文字列を表示する Widget です。フォントや文字色、文字サイズなどのスタイルを指定するフィールドも用意されています。第一引数に渡された文字列を表示します。
const Text(
'You have pushed the button this many times:',
),
FloatingActionButton
Widget
画面下部の画面の上に浮いたようなボタンを表示する Widget です。
Flutter にはこのFloatingActionButton
という Widget だけでなく、いくつかのボタン Widget が用意されています。これらのボタン Widget は、ユーザーのタップを検知することが出来、タップされた際に実行する処理をonPressed
フィールドに渡すことができます。
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter, // タップ時に実行する処理
tooltip: 'Increment',
child: Icon(Icons.add),
),
...
void _incrementCounter() {
setState(() {
_counter++;
});
}
Icon
Widget
Icon
widget はアイコンを表示する為の Widget です。第一引数に渡している Icons
クラスには、マテリアルデザインのアイコンが多数定義されている ので、手軽にアイコンを使うことができます。
このサンプルアプリでは+
マークのアイコンを表示しています。
Icon(
Icons.add,
color: Colors.white,
),
まとめ
今回は簡単なサンプルアプリの画面にも沢山の Widget が使われていることをお分かり頂けたと思います。
Flutter には非常に多くの Widget が用意されており、全てを覚えておくのはなかなか困難です。ざっくりとどんな Widget が存在するかを把握しておいて、使う際には公式ドキュメントを参照すると良いでしょう。
それでは次は画面遷移について見ていきましょう。