🤫

Flutterでコンストラクターを使う

2023/01/14に公開

どんなふうに使う?

Dartの学習をしたときに、コンストラクターを勉強したけどFlutterのWidgetではどう使えばいいのかイメージがわかなかった?
やることは、単純で外部の値をクラスに渡すのに使います。
分かりやすい例を出すと、ボタンのWidgetを切り分けてコンポーネント化して、色とサイズを変更できるものを作って学んでみました。

よくある例が、ボタンを一個ずつ追加していって色やサイズを変える方法。でもこれは何だか冗長ですね。
冗長とは、重複していたり不必要に長かったりして無駄が多いこと。
はい、私のことです😅

これをいくつも書いて、styleを追加していく。

ElevatedButton(onPressed: (){}, child: Text('Button')),

でも使いませたら便利じゃない?

VScodeでWidgetを切り分けるときは、ElevatedButtonを選択した状態で、command + . を押して、Widgetを切り分ける操作ができます。

ソースコードはこんな感じです。でもこれだけだと物足りない。
なので、外部から値を渡してボタンの色と名前を変更できるようにします。

class ButtonComponent extends StatelessWidget {
  const ButtonComponent({
    Key? key,
  }) : super(key: key);

  
  Widget build(BuildContext context) {
    return ElevatedButton(
        style: ElevatedButton.styleFrom(
            backgroundColor: Colors.red,
            foregroundColor: Colors.black,
            fixedSize: Size(100, 50)),
        onPressed: () {},
        child: Text('Button'));
  }
}

変数を定義して、コンストラクターを追加すると引数を渡せるようになります。今回だと、渡しているのは文字に見えますが、変数の型は、Colorにしないと、エラー吐いちゃいます!
マウスをホバーすると、backgroundColorの型が確認できるので、Colorを変数の型に指定しましょう。
変数を追加すると、エラーがコンストラクターの箇所で出てくるので、コードの保管機能で追加します。

class BaseButton extends StatelessWidget {
  const BaseButton({
    Key? key,
    required this.background,
    required this.foreground,
    required this.buttonName,
  }) : super(key: key);

  final Color background;// ボタンの背景色.
  final Color foreground;// ボタンの文字色.
  final String buttonName;// ボタンの名前.

  
  Widget build(BuildContext context) {
    return ElevatedButton(
        style: ElevatedButton.styleFrom(
            backgroundColor: background,// 変数を使用する.
            foregroundColor: foreground,// 変数を使用する.
            fixedSize: Size(100, 50)),
        onPressed: () {},
        child: Text(buttonName)// 変数を使用する.
        );
  }
}

全体のコード

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

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const ButtonApp(),
    );
  }
}

class ButtonApp extends StatelessWidget {
  const ButtonApp({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Button'),
      ),
      body: Center(
        child: Column(children: [
          SizedBox(height: 20),
          ButtonComponent(),
          SizedBox(height: 20),
          BaseButton(
            background: Colors.blue,
            foreground: Colors.amber,
            buttonName: "Button1",
          ),
          SizedBox(height: 20),
          BaseButton(
            background: Colors.amber,
            foreground: Colors.black,
            buttonName: "Button2",
          )
        ]),
      ),
    );
  }
}

class ButtonComponent extends StatelessWidget {
  const ButtonComponent({
    Key? key,
  }) : super(key: key);

  
  Widget build(BuildContext context) {
    return ElevatedButton(
        style: ElevatedButton.styleFrom(
            backgroundColor: Colors.red,
            foregroundColor: Colors.black,
            fixedSize: Size(100, 50)),
        onPressed: () {},
        child: Text('Button'));
  }
}

class BaseButton extends StatelessWidget {
  const BaseButton({
    Key? key,
    required this.background,
    required this.foreground, required this.buttonName,
  }) : super(key: key);

  final Color background;// ボタンの背景色.
  final Color foreground;// ボタンの文字色.
  final String buttonName;// ボタンの名前.

  
  Widget build(BuildContext context) {
    return ElevatedButton(
        style: ElevatedButton.styleFrom(
            backgroundColor: background,// 変数を使用する.
            foregroundColor: foreground,// 変数を使用する.
            fixedSize: Size(100, 50)),
        onPressed: () {},
        child: Text(buttonName)// 変数を使用する.
        );
  }
}

最後に

パーツは使いませるように、コンポーネント化しないと無駄なコードがどんどん増えていって肥大化する。
以前は、これを解決できてなかったので、何度も同じWidgetを書いておりました😅

Discussion