
Flutterを触っていて、ここで
印象がガラッと変わる人が多いのがこのSTEPです。
環境構築やDartの理解までは、「まあ普通の準備だな」という感覚でしたが、
UIを書き始めると、
Flutterがなぜ評価されているのかが一気に腑に落ちます。
特に、WebエンジニアとしてCSSに散々悩まされてきた人ほど、「これは確かに楽だな」と感じるはずです。
そして、FlutterのUIはなぜCSSより楽なのかを理解することができるでしょう。
Widget = View + ロジックという考え方
FlutterのUIは、すべて
Widgetで構成されます。
この時点で重要なのは、Widgetを「ただの見た目」と思わないことです。
Widgetは、
画面表示の単位であり、その表示に
必要なロジックを含む単位でもあります。
HTML+CSS+JavaScriptのように、ファイルや役割が分散する構造ではありません。
UIに関する責務が、1つのWidgetにまとまっています。
この考え方に慣れると、
「この画面は何をしているのか」
「どこを修正すれば影響が出るのか」
が、コードから直感的に分かるようになります。
StatelessWidget / StatefulWidget
最初に必ず出てくるのが、この2つ。
名前だけ見ると難しそうですが、役割はとても単純です。
StatelessWidgetは、状態を持たないWidget。
与えられたデータを元に、同じ見た目を描画し続けます。
StatefulWidgetは、状態を持つWidgetです。
ボタンを押した、入力が変わった、といった変化に応じて、画面の見た目が変わります。
ここで大事なのは、「どちらを使うかで悩みすぎない」こと。
最初は、
「変わらないなら Stateless」
「変わるなら Stateful」
この判断だけで十分です。
後のSTEPで、状態管理を整理するときに、この違いが自然と効いてきます。
Column / Row / Expanded / Padding
Flutterのレイアウトは、最初こそ独特に見えますが、実はCSSよりもかなり単純です。
Columnは縦並び、
Rowは横並び。これだけ覚えれば、レイアウトの大半は組めます。
Expandedは、「余ったスペースをどう使うか」を制御するためのWidgetです。
Flexboxを使ったことがある人なら、役割としてはかなり近いものがあります。
Paddingは、その名の通り余白を付けるためのWidget。
CSSのmarginやpaddingの指定で悩むことがなく、
「このWidgetに余白を足す」という感覚で書けます。
重要なのは、
レイアウトもすべてWidgetであるという点です。
CSSのように、「レイアウトだけ別の言語で考える」必要がないのがシンプルでいいですね。
FlutterのUIはなぜCSSより楽なのか
理由はとてもシンプルです。
Flutterでは、「見た目が壊れる要因が少ない」からです。
・ブラウザ差異がない
・OS差異が少ない
・親要素の影響で突然レイアウトが崩れない
UIがコード通りに描画されるため、「なぜこうなったのか分からない」という瞬間が圧倒的に減ります。
また、UIがツリー構造で表現されるため、画面構造を頭の中で追いやすいのも大きなメリットですね。
成果物:静的な業務画面モック
このSTEPで作る成果物は、動かなくて構いません。
入力フォームや一覧画面など、よくある業務画面を静的に組んでみるだけで十分です。
重要なのは、「このUIはどういう構造のWidgetでできているか」を意識しながら書くことです。
ここでUI構築に慣れておくと、次のSTEP以降でロジックを足すときに、頭が混乱しなくなります。
dart
lib/main.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 MaterialApp(
title: 'Business Mock',
home: const DashboardPage(),
debugShowCheckedModeBanner: false,
);
}
}
class DashboardPage extends StatelessWidget {
const DashboardPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('顧客管理ダッシュボード'),
),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 検索エリア
const Text(
'検索条件',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: TextField(
decoration: const InputDecoration(
labelText: '顧客名',
border: OutlineInputBorder(),
),
),
),
const SizedBox(width: 12),
ElevatedButton(
onPressed: null,
child: const Text('検索'),
),
],
),
const SizedBox(height: 24),
// 一覧エリア
const Text(
'顧客一覧',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Expanded(
child: ListView(
children: const [
CustomerTile(
name: '株式会社サンプル',
email: 'sample@example.com',
),
CustomerTile(
name: 'テスト商事',
email: 'test@example.com',
),
CustomerTile(
name: 'デモ株式会社',
email: 'demo@example.com',
),
],
),
),
],
),
),
);
}
}
class CustomerTile extends StatelessWidget {
final String name;
final String email;
const CustomerTile({
super.key,
required this.name,
required this.email,
});
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.only(bottom: 8),
child: Padding(
padding: const EdgeInsets.all(12),
child: Row(
children: [
const Icon(Icons.business),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
name,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
Text(
email,
style: const TextStyle(color: Colors.grey),
),
],
),
),
],
),
),
);
}
}
このモックのポイント
・UIはすべてWidgetの組み合わせ
・レイアウト制御はColumn / Row / Expandedだけ
・CSS的な「崩れ方」を一切考えなくていい
・業務画面の構造がコードからそのまま読める
このステップのあとがき
このSTEPで得られる一番の収穫は、「FlutterでUIを書くのは怖くない」という感覚です。
CSSで悩んできた時間を思い返すと、UIをコードで制御できる安心感は、かなり大きな武器になると思います。
0 件のコメント:
コメントを投稿