■ はじめに
説明
下記のサイトを参考に、Widget の自作(クラス化)について理解を深める。
クラス化をする事で、コードの可読性が良くなり保守性(リファクタリングなどのメンテナンス)も向上する。
手順としては、
- クラス化する部分を決める
- Widget をクラス化する(Extract Widget 機能を使うのが便利)
- コンストラクタの設定(コンストラクタでデータを受け取る)
- プロパティの設定(受け取ったデータをプロパティに格納する)
学習の一環で実際に手を動かしメモとしてまとめたものです。
間違えている箇所やこういうやり方の方が良いよ。などあればコメント等で是非アドバイスいただけますと幸いです!
環境
- 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. クラス化する部分を決める
現状の問題点
- ほとんど同じコードを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'),
),
),
],
),
),
],
),
],
),
),
),
),
);
}
}
2. Extract Widget 機能を使って用意した Widget をクラス化する
2.1 「Flutter Outline」→「該当の Widget を右クリック」→「Extract Widget」をクリック
2.2 Widget の名前を決めて、リファクタリングをクリック
2.4 ソースコードの下部にクラスが作成されてる。今回は common_widget.dart という共通化用のファイル作ったので、そこに貼り付ける。
2.5 「The method 'CommonWidget' isn't defined for the type 'MyWidget」となれば、インポートで解決する。( opt + Enter で 該当のファイルを選択)
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),
),
),
],
),
),
],
);
}
}
以上。
Reference Site