【Flutter】 コンポーネント化でWidgetを共通管理する

Flutter

今回は、FlutterのWidgetをわかりやすく管理するコンポーネント化の方法を解説していきます。

2つの方法を順に紹介していきますのでぜひ最後までご覧ください。

スポンサーリンク

コンポーネント化でWidgetを管理するメリットとは

まずはコンポーネント化の方法を解説する前にコンポーネント化するメリットを解説していきます。

コンポーネント化するメリットはいくつかありますが、私が思う大きなメリットは以下の二つです。

  • コードの記述がわかりやすくなり、可読性が上がる
  • 同じUIを共通化して使い回すことができるようになる

同じような記述を何回も書いていて無駄だなと感じている人や、デザインの修正を一括で行いたいと思っている方にはぜひ取り入れていただきたい管理方法です。

コンポーネント化の方法

おすすめするコンポーネント化の方法は大きく二つあります。

  • classで管理
  • メソッドで管理

次に、実際の活用場面を見ながら、それぞれのメリットを実感していただこうと思います。

コードの記述がわかりやすくなり、可読性が上がる

コードの記述がわかりやすくなり、可読性が上がる」というメリットを実感していただくために、ここでは、Flutterのデモコードであるカウンターアプリのコードを元に解説を進めていきます。

元のコードは以下です。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  @override
  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;

  @override
  State<MyHomePage> 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>[
            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のbody内の表示をコンポーネント化してわかりやすくしていきます。

それぞれの方法での記述方法で実践していきましょう。

コンポーネント化の方法① classで管理

まずはclassで管理する方法を解説していきます。

Scaffoldのbodyに記述している「Center」ウィジェットを表示するWidget classを作成します。

今回は「StatelessWidget」を継承した、「BodyText」というクラスを作成してみます。

コードは以下です。

class BodyText extends StatelessWidget {
  final int counter;
  const BodyText({Key? key, required this.counter}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return 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,
          ),
        ],
      ),
    );
  }
}

こちらの「BodyText」クラスを用いて、「_MyHomePageState」のbuildメソッドの内容を修正すると以下のようになります。

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text(widget.title),
    ),
    body: BodyText(counter: _counter), //こちらを変更
    floatingActionButton: FloatingActionButton(
      onPressed: _incrementCounter,
      tooltip: 'Increment',
      child: const Icon(Icons.add),
    ),
  );
}

Scaffoldのbodyの内容を先ほど作成した「BodyText」クラスに書き換えています。

こうすることでコードがすっきりして見やすくなったかと思います。

コンポーネント化の方法② メソッドで管理

次はメソッドで管理していく方法を解説していきます。

こちらもclassの時と同様、Scaffoldのbodyの「Center」ウィジェットをreturnするメソッドを作成します。

今回は「_MyHomePageState」の中に「buildBodyText」というメソッドを定義していきます。

コードは以下です。

Widget buildBodyText() {
  return 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,
        ),
      ],
    ),
  );
}

こちらの「buildBodyText」メソッドを用いて、「_MyHomePageState」のbuildメソッドの内容を修正すると以下のようになります。

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text(widget.title),
    ),
    body: buildBodyText(), //こちらを変更
    floatingActionButton: FloatingActionButton(
      onPressed: _incrementCounter,
      tooltip: 'Increment',
      child: const Icon(Icons.add),
    ),
  );
}

Scaffoldのbodyの内容を先ほど作成した「buildBodyText」メソッドに書き換えています。

メソッドの管理でもコードがすっきりして見やすくなったかと思います。

同じUIを共通化して使い回すことができるようになる

次に、同じUIを共通化して使い回すメリットを実践していこうと思います。

今回はオリジナルボタンのようなデザインしたボタンを使いまわせるようにします。

以下のようなボタンをデザインしたとします。

ElevatedButton(
  child: const Text('タップしてね'),
  style: ElevatedButton.styleFrom(
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(20),
    ),
    side: const BorderSide(),
  ),
  onPressed: () {},
),

こちらの文字やボタンタップの処理だけを状況に応じて変えたい場合は、以下のようにコンポーネント化することでデザインを使い回して使用することができます。

class OriginalButton extends StatelessWidget {
  final String txt;
  final VoidCallback onPressed;

  TestButton({required this.txt, required this.onPressed});

  @override
  Widget build(BuildContext context) {
    return
      ElevatedButton(
        child: Text(txt),
        style: ElevatedButton.styleFrom(
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(20),
          ),
          side: const BorderSide(),
        ),
        onPressed: onPressed,
      );
  }
}

このOriginalButtonクラスを以下のように使用することでデザインを使い回すことができます。

OriginalButton(
  txt: 'タップしてね',
  onPressed: () {
    //タップされた時の処理を記述
  }
),

おわりに

今回は、FlutterのWidgetをわかりやすく管理するコンポーネント化の方法を解説させていただきました。

コンポーネント化を実施することでWidgetを色々な場所で使い回すことができるようになり、記述するコード量を削減することができます。

それによりコード自体もすっきりするため、コードの可読性が向上するのも大きなメリットの一つです。

今作成しているアプリのコードが見にくいなと感じている方は一度このコンポーネント化の実施を検討してみてください。

当ブログではプログラミングの学習に関する内容を執筆しています。FlutterのWidgetの前につけるconstの意味を解説している記事などもあります。興味がある方はぜひこちらも合わせてご覧ください。

最後まで読んでくださりありがとうございました。

コメント

タイトルとURLをコピーしました