Flutter,インデント(ネスト)を減らす方法について

0,目次

  1. はじめに
  2. コードの分割
    1. メソッド化
    2. 別クラス化
    3. 別ファイル化
  3. おわりに
  4. 参考文献

1,はじめに

最近Flutterでアプリ開発をしています。

Flutterでの開発は、ウィジェットを大量に記述することが多いです。

すると、問題点として、

ソースコードのインデントが深くなることが挙げられます。

おそらく、Flutterの開発者たちは、

意図的にインデントが深くなるように設計をしています。

そこで本稿では、Flutterのコードをメソッド化したり、別クラス化したり、

ソースコードを別ファイル化する方法について、記載します。

2,コードの分割

(1)メソッド化(関数化)

Flutterでの開発では、ウィジェットオブジェクトについて、

大量の記述をしばしば行います。

そのため、インデントが深くなり、コードが見辛くなります。

ここで、発想の転換として、

ウィジェットオブジェクトを返す関数を作成するという方法が使用できます。

(A)メソッド化前

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Sysrigar Sample',
      theme: ThemeData.dark(),
      home: MyHomePage(title: 'Sysrigar Sample'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Card(
              child: Column(children: [
                ListTile(
                  title: Text("保有カブ数:10 カブ")
                ),
                ListTile(
                  title: Text("平均取得額:10 ベル")
                ),
                ListTile(
                  title: Text("評価損益額:")
                ),
                ListTile(
                  title: Text("利益率  :")
                )
              ])
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

ちなみに、このコードをFlutterで解釈すると、こんな感じです。

実行結果

(B)メソッド化後

(i)メソッド

下記の内容のメソッドを「MyHomePage」クラス内に追記します。

// Cardウィジェットを返すメソッド
Card _createHomePageCardStocksInfo() {
  return (
    Card(
      child: Column(children: [
        ListTile(
          title: Text("保有カブ数:10 カブ")
        ),
        ListTile(
          title: Text("平均取得額:10 ベル")
        ),
        ListTile(
          title: Text("評価損益額:")
        ),
        ListTile(
          title: Text("利益率  :")
        )
      ])
    )
  );
}
(ii)メソッド呼びだし

追記したコードを呼び出すために、

元々のコードでCardウィジェットを記載していたところを、

メソッド呼び出しに置き換えます。

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),

            // Cardウィジェット部分(メソッド化)
            _createHomePageCardStocksInfo(),

            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }

まぁ、このサイトを読まれるであろう方の実力から考えると、

こんなことは当然ですよね。。。

(2)別クラス化

上述の通り、ウィジェットオブジェクトを、

戻り値とするメソッドを作成することで、

ソースコード内のインデントの削減が可能です。

しかし、メソッド化でもコードは肥大化します。

それを回避し、見やすいコードを書くために、

処理ごとに別々のクラスでまとめることが可能です。

クラス分けのサンプル実行結果

具体的には「StatefulWidget」又は、

StatelessWidget」を継承したクラスを作成します。

(A)クラス化

// 例えば、トップ画面を構成するウィジェットについてまとめたもの
class PageWidgetOfHome extends StatefulWidget {
  PageWidgetOfHome({
    Key key
  }) : super(key: key);

  @override
  PageWidgetOfHomeState createState() => PageWidgetOfHomeState();
}

class PageWidgetOfHomeState extends State<PageWidgetOfHome> {
  @override
  Widget build(BuildContext context) {
    return (_createHomePageCardStocksInfo(context));
  }

  // Cardウィジェットを返すメソッド
  Card _createHomePageCardStocksInfo(BuildContext context) {
    return (
      Card(
        child: Column(children: [
          ListTile(
            title: Text("保有カブ数:10 カブ")
          ),
          ListTile(
            title: Text("平均取得額:10 ベル")
          ),
          ListTile(
            title: Text("評価損益額:")
          ),
          ListTile(
            title: Text("利益率  :")
          )
        ])
      )
    );
  }
}

StatefulWidgetとStateの関係については、

参考文献の1に丁寧な説明の資料へのリンクを記載しましたので、

ご参照ください。

(B)呼び出し方法

import 'package:flutter/material.dart';

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

// 例えば、トップ画面を構成するウィジェットについてまとめたもの
class PageWidgetOfHome extends StatefulWidget {
  PageWidgetOfHome({
    Key key
  }) : super(key: key);

  @override
  PageWidgetOfHomeState createState() => PageWidgetOfHomeState();
}

class PageWidgetOfHomeState extends State<PageWidgetOfHome> {
  @override
  Widget build(BuildContext context) {
    return (_createHomePageCardStocksInfo(context));
  }

  // Cardウィジェットを返すメソッド
  Card _createHomePageCardStocksInfo(BuildContext context) {
    return (
      Card(
        child: Column(children: [
          ListTile(
            title: Text("保有カブ数:10 カブ")
          ),
          ListTile(
            title: Text("平均取得額:10 ベル")
          ),
          ListTile(
            title: Text("評価損益額:")
          ),
          ListTile(
            title: Text("利益率  :")
          )
        ])
      )
    );
  }
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Sysrigar Sample',
      theme: ThemeData.dark(),

      routes: <String, WidgetBuilder> {
        '/': (BuildContext context) => new PageWidgetOfHome(),
      }
    );
  }
}

こんな感じで、使います。

(3)別ファイル化

これまで見てきた中で、ウィジェットについて、

メソッドでまとめる方法や、クラスでまとめる方法を記載しました。

次に、1つのソースコードに全てを記入ではなく、

複数のファイルにコードを分けて記入する方法について記載します。

結論からいうと、Dartのimport文を使用します。

(A)使用例

上述の「PageWidgetOfHome」オブジェクトについて、

「homepage.dart」に記載している場合、下記の通りインポートします。

import 'package:flutter/material.dart';
import 'homepage.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Sysrigar Sample',
      theme: ThemeData.dark(),

      routes: <String, WidgetBuilder> {
        '/': (BuildContext context) => new PageWidgetOfHome(),
      }
    );
  }
}

(B)homepage.dart

import 'package:flutter/material.dart';

// 例えば、トップ画面を構成するウィジェットについてまとめたもの
class PageWidgetOfHome extends StatefulWidget {
  PageWidgetOfHome({
    Key key
  }) : super(key: key);

  @override
  PageWidgetOfHomeState createState() => PageWidgetOfHomeState();
}

class PageWidgetOfHomeState extends State<PageWidgetOfHome> {
  @override
  Widget build(BuildContext context) {
    return (_createHomePageCardStocksInfo(context));
  }

  // Cardウィジェットを返すメソッド
  Card _createHomePageCardStocksInfo(BuildContext context) {
    return (
      Card(
        child: Column(children: [
          ListTile(
            title: Text("保有カブ数:10 カブ")
          ),
          ListTile(
            title: Text("平均取得額:10 ベル")
          ),
          ListTile(
            title: Text("評価損益額:")
          ),
          ListTile(
            title: Text("利益率  :")
          )
        ])
      )
    );
  }
}

3,おわりに

本稿を読まれた方は、私のように1つのファイルに、

大量のウィジェットの記述をつらつらと書かないように、

エンジョイいただければ幸いです。

私の使用感としては、学習難度が結構高いなと感じています。

FlutterはFlutterのルールに従って書く必要があります。

そのため、フレームワークについてしっかりと知ることが、

使いこなす前提だと、感じています。

4,参考文献

  1. 【Flutter入門】StatefulWidgetはなぜ2つに分かれているのかについて解説するよ。 | TECHRISE
  2. 面遷移(Navigator) | Flutter Doc JP
  3. FlutterのNavigationとRoutingを理解する
  4. Flutterで画面遷移させてみた!!| 開発者ブログ | 株式会社アイソルート
  5. How to reference another file in Dart? – Stack Overflow

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA