[Flutter] ウィジェット

2021-04-07 hit count image

Flutterを使ってアプリを開発してみましょう。今回のブログポストではFlutterで使えるウィジェットに関して説明します。

概要

Flutterを使ってアプリを開発してみようかと思います。今回のブログポストではFlutterの基本要素であるウィジェットに関して説明します。

このブログポストで紹介したソースコードは下記のリンクで確認することができます。

ウィジェット

Flutterはウィジェットで始まってウィジェットでお終わります。Flutterで画面に表示される全ての要素がウィジェットで、目に見えないけど画面の構造であるレイアウト(Layout)もウィジェットです。

したがってFlutterでアプリを開発するためにはウィジェットを理解する必要があります。

ウィジェットは大きく二つで分類されております。

  • Stateful Widget
  • Stateless Widget

それじゃ、各ウィジェットを詳しく見て見ましょう。

Stateful Widget

FlutterでStateful Widgetはどのような状態の値を持っており、その状態の値による画面の動きや変化を表現する時使います。

  • 例:テキストフィールド、ボタン、サーバからもらったデータを表示するウィジェットなど

上のようにStateful Widgetはユーザとのインタラクションによって模様や形が変わる時使います。Stateful WidgetはStatefulWidgetを継承して生成します。

Stateless Widget

Stateless WidgetはStateful Widgetとは違って、どんな状態も持ってない静的なウィジェットです。どんな状態の値も持ってないので、Stateless Widgetは画面上でどんな動きも変化もありません。

  • 例:テキスト、イメージなど

上のようにStateless Widgetは画面には表示されるが、ユーザとはどんなインタラクションもしなくて、どんな動きや変化もしないです。Stateless WidgetはStatelessWidgetを継承して生成します。

Widget tree

基本的にはFlutterはウィジェットを使って開発をします。一つのウィジェットは複数のウィジェットを含むことができますし、全てのウィジェットは親子関係を持ってます。このように親子関係を持ってると、これをTree構造で表現や管理することができます。

例えば、HTMLがウェブブラウザに表示される時、ブラウザはHTMLの要素をDOMツーリを生成して管理してます。これと同じようにFlutterは全てのウィジェットをWidgetツーリを生成して管理します。

全てのウィジェットは親ウィジェットと子ウィジェットで構成されて、親のウィジェットはParent WidgetまたはWidget Containerと呼ばれます。

コーディング

それじゃ、今から簡単にコーディングをしてウィジェットを理解してみましょう。

Stateless widget コーディング

Stateless widgetを理解するため、次のコマンドを実行してFlutterプロジェクトを生成します。

flutter create stateless_widget

そして次のコマンドを使ってVSCodeを実行します。

cd stateless_widget
code .

VSCodeが立ち上がったら、lib/main.dartファイルを開いて次のように修正します。

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomeWidget(),
    );
  }
}

class HomeWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Stateless Widget'),
      ),
      body: Center(
        child: Text('Hello world'),
      ),
    );
  }
}

それじゃ、ソースコードを一つづつ詳しくみてみましょう。

import 'package:flutter/material.dart';

まず、私たちはFlutterが提供するmaterialデザインを使ってプログラムを作成する予定です。

void main() {
  runApp(MyApp());
}

Dartを勉強した方は、main関数に慣れてると思います。main関数はDartのプログラムを実行するための関数で、Flutterではこの関数でrunApp関数をコールする必要があります。

Dartに関してよく分かってない方は、下記のリンクでDartに関して確認してみてください。

runApp関数は一つのウィジェットをパラメータでうけっております。ここでセットされるウィジェットが私たちが作るFlutterアプリを構成する開始点になり、このウィジェットがウィジェットツーリの一番上に位置することになります。

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomeWidget(),
    );
  }
}

MyAppは私たちが作ったカスタムウィジェットです。ウィジェットの名前は何でもいいですが、ここではMyAppと指定します。このウィジェットはStatelessWidgetを継承しました。つまり、このウィジェットは動的な値を持ってないことになります。

全てのウィジェットは基本的build関数を持ってます。このビルド関数はまた他のウィジェットをリターンする構造を持ってます。このようにウィジェット中でウィジェットを含めることで親子関係が形成され、ウィジェットツーリが生成されます。

今回の例題ではflutter/material.dartが提供するMaterialAppウィジェットを使ってアプリを構成しました。MaterialApphomeと言うパラメータを持ってます。

このhomeはアプリが実行されて初めて画面に表示されることを意味し、このパラメータでセットされたウィジェットが最初表示されます。

それじゃ、アプリの最初画面で表示されるHomeWidgetをみてみましょう。HomeWidgetはMyAppと同じようにStatelessWidgetを継承して作ったカスタムウィジェットで、どんな名前を使ってもいいですが、ここではHomeWidgetと指定しました。

class HomeWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('HOME'),
      ),
      body: Center(
        child: Text('Hello world'),
      ),
    );
  }
}

HomeWidgetはflutter/material.dartが提供するScaffoldと言うウィジェットをリターンしてます。Scaffoldウィジェットはmaterialアプリで基本的使えるウィジェットで、このウィジェットを使うとappBarbodyなど、画面を簡単に構成することができます。

Scaffold(
  appBar: AppBar(
    title: Text('HOME'),
  ),
  ...,
);

今回の例題にはこのScaffoldを使ってアプリのステータスバーを表示しました。appBarパラメータへAppBarウィジェットをパラメータで渡して、AppBarウィジェットにはtitleパラメータにTextウェジェットを使ってHOMEと言う文字を表示しました。

Scaffold(
  ...,
  body: Center(
    child: Text('Hello world'),
  ),
);

アプリのbodyにはCenterと言うウィジェットを使ってこウィジェットを画面の真ん中に表示するようにして、Textウィジェットを使ってHello worldと言う文字を表示しました。

Stateful widgetコーディング

Stateful widgetを理解するため、次のコマンドを実行してFlutternoプロジェクトを生成します。

flutter create stateful_widget

そして次のコマンドを使ってVSCodeを実行します。

cd stateful_widget
code .

このようにVSCodeが実行されたら、lib/main.dartファイルを開いて下記のように修正します。

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HomeWidget(),
    );
  }
}

class HomeWidget extends StatefulWidget {
  @override
  _HomeWidgetState createState() => _HomeWidgetState();
}

class _HomeWidgetState extends State<HomeWidget> {
  int counter = 0;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Stateful Widget')),
      body: Center(
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
                onPressed: () => setState(() => {counter++}),
                child: Icon(Icons.add)),
            Container(
              child: Text('$counter'),
              margin: EdgeInsets.fromLTRB(30.0, 0.0, 30.0, 0.0),
            ),
            ElevatedButton(
                onPressed: () => setState(() => {counter--}),
                child: Icon(Icons.remove)),
          ],
        ),
      ),
    );
  }
}

それじゃ、ソースコードを一つづつ詳しくみてみましょう。Stateless Widgetで説明した内容は省略します。

Statefulウィジェットを作る方法について説明します。Statefulウィジェットを生成するためにはまずStatefulWidgetを継承してウィジェットを作る必要があります。

class HomeWidget extends StatefulWidget {
  @override
  _HomeWidgetState createState() => _HomeWidgetState();
}

Statelessとは違ってbuildを使わなくcreateStateを使います。createStateはStateと言うクラスを継承したカスタムStateをリターンする必要があります。

ここでリターンするカスタムStateは変更できる状態を持ってますし、変更できる状態によるウィジェットも持ってます。

class _HomeWidgetState extends State<HomeWidget> {
  int counter = 0;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      ...
      body: Center(
        child: Row(
          ...,
          children: [
            ...,
            Container(
              child: Text('$counter'),
              margin: EdgeInsets.fromLTRB(30.0, 0.0, 30.0, 0.0),
            ),
            ...,
          ],
        ),
      ),
    );
  }
}

まず、変更されるStateを保存する変数を宣言します。ここではint couter = 0;と言う変数を宣言しました。このように宣言した変数はTextウィジェットを使ってText('$counter')をついて画面に表示するようにしました。

このState値を変更するためにはsetStateと言う関数を使う必要があります。この関数を使わないとStateを変更しても、画面に反映されないです。

ElevatedButton(
  onPressed: () => setState(() => {counter++}),
  child: Icon(Icons.add))

Stateについてのメカニズムは結構複雑なので、ここでは使う方法についてだけ説明します。メカニズムについて気になる方は公式サイトを参考してください。

Closing Label

今まで例題をコーディングした時、次のように私たちが追加してないのに、自動で追加されたコメントが確認できます。

Flutter - Closing Label

Flutterはたくさんのウィジェットを使ってアプリを作成します。このようにたくさんのウィジェットとたくさんのソースコードのせいで、一つのウィジェットがどこからどこまでかよく分からなくなります。この問題を解決するためFlutterはClosing Labelと言う機能をして、自動でウィジェットが終わるところにコメントを入れます。これで私たちはウィジェットがどこから初めてどこで終わるかもっと簡単に分かることができます。

このコメントは私たちは追加することも修正することもできません。

確認

これで簡単なコーディングをしてFlutterアプリの画面を構成する方法について調べてみました。コードを確認したら分かると思いますが、アプリを構成する全てのものがウィジェットだったことが分かります。

それじゃ、このように修正したアプリを実行してみます。アプリを実行するため、エミュレーターを実行して、Flutterプロジェクトを実行する方法については下記のリンクを確認してください。

このようにアプリを実行すると次のように私たちが作ったアプリが画面に表示されることが確認できます。

Flutter - First App

完了

これでFlutterを使って新しいプロジェクトを生成してみて、簡単な例題を使ってFlutterの主な要素であるウィジェットについて詳しくみてみました。Flutterはこのウィジェットを使って全てのアプリを構成するので、よく覚えておきましょう。

私のブログが役に立ちましたか?下にコメントを残してください。それは私にとって大きな大きな力になります!

Posts