2025年8月25日
FlutterではこんなUIちょちょいのちょい
はじめに
Flutterでは「Widget(ウィジェット)」と呼ばれる部品を組み合わせて、アプリの画面を構築します。HTMLでいえば、div や h1 といったタグのような役割を担っています。
この記事では、Flutterにあらかじめ用意されている一部の標準のWidgetに絞り、それらを使って手軽にどのようなUIが構築できるのかを、最小限のコードと併せてご紹介します。
動作環境
以下の環境で動作確認を行いました。
$ flutter --version
Flutter 3.27.3 • channel stable • https://github.com/flutter/flutter.git
Framework • revision c519ee916e (7 months ago) • 2025-01-21 10:32:23 -0800
Engine • revision e672b006cb
Tools • Dart 3.6.1 • DevTools 2.40.2
目次
ドラッグで入れ替え可能なリスト(ReorderableListView)
リスト項目をドラッグ操作で並べ替えられるWidgetです。TODO管理や並び順変更機能に最適です。
import 'package:flutter/material.dart';
void main() => runApp(const MaterialApp(home: MyList()));
class MyList extends StatefulWidget {
const MyList({super.key});
@override
State<MyList> createState() => _MyListState();
}
class _MyListState extends State<MyList> {
final items = ['りんご', 'ごりら', 'ラッパ', 'パイナップル'];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('asial')),
body: ReorderableListView(
onReorder: (oldIndex, newIndex) {
setState(() {
if (newIndex > oldIndex) newIndex--;
final item = items.removeAt(oldIndex);
items.insert(newIndex, item);
});
},
children: List.generate(items.length, (index) {
return ListTile(
key: ValueKey(items[index]),
title: Text(items[index]),
trailing: ReorderableDragStartListener(
index: index,
child: const Icon(Icons.drag_handle),
),
);
}),
),
);
}
}
タブでの画面切り替え(DefaultTabController、TabBar、TabBarView)
タブをタップやスワイプして画面を切り替えられるWidgetの組み合わせです。 カテゴリ別画面やコンテンツ切り替えに便利です。
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(
home: DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
title: const Text('アシアル'),
bottom: const TabBar(
indicatorSize: TabBarIndicatorSize.tab,
tabs: [
Tab(text: 'タブ1'),
Tab(text: 'タブ2'),
Tab(text: 'タブ3'),
],
),
),
body: const TabBarView(
children: [
Center(child: Text('タブ1の内容')),
Center(child: Text('タブ2の内容')),
Center(child: Text('タブ3の内容')),
],
),
),
),
);
}
}
複数のステップを順番に案内する(Stepper)
複数の手順を段階的に進められるUIを提供します。フォーム入力やチュートリアルの案内に向いています。
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: StepperExample(),
);
}
}
class StepperExample extends StatefulWidget {
const StepperExample({super.key});
@override
State<StepperExample> createState() => _StepperExampleState();
}
class _StepperExampleState extends State<StepperExample> {
int _currentStep = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('アシアル')),
body: Stepper(
currentStep: _currentStep,
onStepContinue: () {
if (_currentStep < 2) {
setState(() => _currentStep += 1);
}
},
onStepCancel: () {
if (_currentStep > 0) {
setState(() => _currentStep -= 1);
}
},
steps: const [
Step(
title: Text('ステップ 1'),
content: Text('ここは最初のステップです。'),
),
Step(
title: Text('ステップ 2'),
content: Text('ここは2番目のステップです。'),
),
Step(
title: Text('ステップ 3'),
content: Text('ここは最後のステップです。'),
),
],
),
);
}
}
リストの展開(ExpansionTile)
タップで項目を展開・折りたたみできるリストUIです。FAQや詳細情報の表示に最適です。
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(
home: Scaffold(
appBar: AppBar(title: const Text('アシアル')),
body: ListView(
children: const [
ExpansionTile(
title: Text('タイトル1'),
children: [
ListTile(title: Text('展開された内容1-1')),
ListTile(title: Text('展開された内容1-2')),
],
),
ExpansionTile(
title: Text('タイトル2'),
children: [
ListTile(title: Text('展開された内容2-1')),
ListTile(title: Text('展開された内容2-2')),
],
),
ExpansionTile(
title: Text('タイトル3'),
children: [
ListTile(title: Text('展開された内容3-1')),
ListTile(title: Text('展開された内容3-2')),
],
),
],
),
),
);
}
}
Pull to Refresh(RefreshIndicator)
リストを下に引っ張って最新データを取得できるUIです。SNSやニュースアプリの更新機能に広く使われています。
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: RefreshExample(),
);
}
}
class RefreshExample extends StatefulWidget {
const RefreshExample({super.key});
@override
State<RefreshExample> createState() => _RefreshExampleState();
}
class _RefreshExampleState extends State<RefreshExample> {
final List<String> items = List.generate(5, (i) => 'アイテム ${i + 1}');
Future<void> _onRefresh() async {
await Future.delayed(const Duration(seconds: 2));
setState(() {
items.add('追加アイテム ${items.length + 1}');
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('アシアル')),
body: RefreshIndicator(
onRefresh: _onRefresh,
child: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) => ListTile(
title: Text(items[index]),
),
),
),
);
}
}
まとめ
Flutter には、今回紹介したような便利な標準Widgetが数多く揃っており、外部パッケージを使わなくても高度な UI を短いコードで実装できます。もしまだ Flutter を触ったことがないなら、まずは今回のWidgetを試してみてください。