LoginSignup
1
0

重複コードを避け独自の Widget クラスを作成する

Posted at

■ はじめに

説明

下記のサイトを参考に、Widget の自作(クラス化)について理解を深める。
クラス化をする事で、コードの可読性が良くなり保守性(リファクタリングなどのメンテナンス)も向上する。

手順としては、

  1. クラス化する部分を決める
  2. Widget をクラス化する(Extract Widget 機能を使うのが便利)
  3. コンストラクタの設定(コンストラクタでデータを受け取る)
  4. プロパティの設定(受け取ったデータをプロパティに格納する)

学習の一環で実際に手を動かしメモとしてまとめたものです。
間違えている箇所やこういうやり方の方が良いよ。などあればコメント等で是非アドバイスいただけますと幸いです!

環境

  • Mac
% sw_vers 
ProductName:            macOS
ProductVersion:         14.0
BuildVersion:           23A344
%
  • Dart & Flutter
% dart --version ; flutter --version
Dart SDK version: 3.3.3 (stable) (Tue Mar 26 14:21:33 2024 +0000) on "macos_arm64"
Flutter 3.19.5 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 300451adae (7 weeks ago) • 2024-03-27 21:54:07 -0500
Engine • revision e76c956498
Tools • Dart 3.3.3 • DevTools 2.31.1
%

■ 手順

1. クラス化する部分を決める

現状の問題点

  1. ほとんど同じコードを2回書いている。(修正する時に同じ作業を2回繰り返す必要がある)
  2. 上記理由により、コードが無駄に長くなり階層も深くなっているため、見辛くなっている。
  • widget_create_practice.dart
import 'package:flutter/material.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: MyWidget(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Widget自作練習'),
      ),
      body: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 16),
        child: SafeArea(
          child: SingleChildScrollView(
            child: Column(
              children: [
                Container(
                  height: 200,
                  color: Colors.red[100],
                  child: const Center(
                    child: Text('メインコンテンツ'),
                  ),
                ),
                const SizedBox(height: 40),

                // ここから
                Row(
                  children: [
                    Padding(
                      padding: const EdgeInsets.only(right: 16),
                      child: Container(
                        height: 110,
                        width: 100,
                        color: Colors.green[100],
                        child: const Center(
                          child: Text('1'),
                        ),
                      ),
                    ),
                    Expanded(
                      child: Column(
                        children: [
                          Padding(
                            padding: const EdgeInsets.only(bottom: 10),
                            child: Container(
                              height: 50,
                              color: Colors.yellow[100],
                              child: const Center(
                                child: Text('2'),
                              ),
                            ),
                          ),
                          Container(
                            height: 50,
                            width: double.infinity,
                            color: Colors.orange[100],
                            child: const Center(
                              child: Text('3'),
                            ),
                          ),
                        ],
                      ),
                    ),
                  ],
                ),
                // ここまでをクラス化する

                const SizedBox(height: 20), // カンマを追加

                Row(
                  children: [
                    Padding(
                      padding: const EdgeInsets.only(right: 16),
                      child: Container(
                        height: 110,
                        width: 100,
                        color: Colors.green[100],
                        child: const Center(
                          child: Text('4'),
                        ),
                      ),
                    ),
                    Expanded(
                      child: Column(
                        children: [
                          Padding(
                            padding: const EdgeInsets.only(bottom: 10),
                            child: Container(
                              height: 50,
                              color: Colors.yellow[100],
                              child: const Center(
                                child: Text('5'),
                              ),
                            ),
                          ),
                          Container(
                            height: 50,
                            width: double.infinity,
                            color: Colors.orange[100],
                            child: const Center(
                              child: Text('6'),
                            ),
                          ),
                        ],
                      ),
                    ),
                  ],
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

  • 実行結果
    1.png

2. Extract Widget 機能を使って用意した Widget をクラス化する

2.1 「Flutter Outline」→「該当の Widget を右クリック」→「Extract Widget」をクリック
2.png

2.2 Widget の名前を決めて、リファクタリングをクリック
3.png

2.3 さっきのコード部分に、クラス名が記載されている
4.png

2.4 ソースコードの下部にクラスが作成されてる。今回は common_widget.dart という共通化用のファイル作ったので、そこに貼り付ける。
5.png

2.5 「The method 'CommonWidget' isn't defined for the type 'MyWidget」となれば、インポートで解決する。( opt + Enter で 該当のファイルを選択)
6.png
7.png

3. プロパティの設定

ウィジェットの状態や表示内容を保持するための変数。
コンストラクタで受け取ったデータ(値)をプロパティとして保持し、ウィジェット内で使用するために必要。

// プロパティの設定
final String subImage;
final String subTitle;
final String text;

4. コンストラクタの設定

ウィジェットのインスタンスを作成するときに、必要なデータを受け取って初期化するためのメソッド。
これにより、ウィジェットが必要とするデータを受け取ることができる。

// コンストラクタの設定
required this.subImage,
required this.subTitle,
required this.text,

5. 変更後のコードと実行結果

  • widget_create_practice.dart
import 'package:flutter/material.dart';
import '../common_widget.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Widget自作練習'),
      ),
      body: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 16),
        child: SafeArea(
          child: SingleChildScrollView(
            child: Column(
              children: [
                Container(
                  height: 200,
                  color: Colors.red[100],
                  child: const Center(
                    child: Text('メインコンテンツ'),
                  ),
                ),
                const SizedBox(height: 40),
                const CommonWidget(subImage: '1', subTitle: '2', text: '3'),
                const SizedBox(height: 20),
                const CommonWidget(subImage: '4', subTitle: '5', text: '6'),
              ],
            ),
          ),
        ),
      ),
    );
  }
}
  • common_widget.dart
import 'package:flutter/material.dart';

class CommonWidget extends StatelessWidget {
  const CommonWidget({
    super.key,
    // コンストラクタの設定
    required this.subImage,
    required this.subTitle,
    required this.text,
  });
  // プロパティの設定
  final String subImage;
  final String subTitle;
  final String text;

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        Padding(
          padding: const EdgeInsets.only(right: 16),
          child: Container(
            height: 110,
            width: 100,
            color: Colors.green[100],
            child: Center(
              child: Text(subImage),
            ),
          ),
        ),
        Expanded(
          child: Column(
            children: [
              Padding(
                padding: const EdgeInsets.only(bottom: 10),
                child: Container(
                  height: 50,
                  color: Colors.yellow[100],
                  child: Center(
                    child: Text(subTitle),
                  ),
                ),
              ),
              Container(
                height: 50,
                width: double.infinity,
                color: Colors.orange[100],
                child: Center(
                  child: Text(text),
                ),
              ),
            ],
          ),
        ),
      ],
    );
  }
}

  • 実行結果(ソースコードを共通化しただけなので実行結果はもちろん変わらない)
    8.png

以上。

Reference Site

1
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0