Flutter の5種類のボタンの違いを動かして確かめ、状態で色とアイコンが変わるマイクボタン(FloatingActionButton)と、押せなくする切り替えを作れます。

アプリには、必ずと言っていいほどボタンがあります。Flutter にはボタンの種類がいくつもあり、「どれを使えばいいのか」「押せなくするにはどうするのか」と迷いやすい部品です。
本記事では、よく使う5種類のボタンを並べて押し比べたあと、音声入力の開始と停止に使うマイクボタンを作ります。聞き取り中は赤くなり、スイッチで押せなくもできます。
- Flutter のボタンの種類と使い分けを知りたい人
- 押したときの処理(onPressed)の書き方を知りたい人
- 状態によってボタンの色やアイコンを変えたい人
- ボタンを押せなくする方法を知りたい人
Flutterのボタンの種類
よく使うボタンは、次の5つです。(FilledButton・ElevatedButton・OutlinedButton・TextButton・IconButton)どれも、押したときの処理を onPressed に渡すと動きます。
| ボタン | 見た目 | 使いどころ |
|---|---|---|
| FilledButton | 色で塗りつぶされている | その画面でいちばん大事な操作 |
| ElevatedButton | 影があり、浮いて見える | 目立たせたい操作。背景と区別したいとき |
| OutlinedButton | 枠線だけ | 補助的な操作 |
| TextButton | 文字だけ | 控えめな操作 |
| IconButton | アイコンだけ | ツールバーなど、場所を取りたくないとき |
使い分けの目安は、「目立たせたい操作ほど、塗りつぶしや影のあるボタンにする」ことです。1つの画面に塗りつぶしのボタンを並べすぎると、どれが大事か分からなくなります。
押せなくする:onPressed に null
どのボタンも、onPressed に null を渡すと、押せなくなります。公式の説明でも、onPressed が null のボタンは無効になります。
ElevatedButton(
onPressed: isReady ? () { /* 処理 */ } : null,
child: const Text('送信'),
)条件によって、処理の関数と null を切り替える書き方です。
FloatingActionButton
FloatingActionButton は、画面の上に浮いて見える丸いボタンです。画面でいちばん大事な操作(作る、共有する、録音を始めるなど)に使います。公式の説明では、1つの画面に置くのは多くても1つにするよう案内されています。
Scaffold の floatingActionButton に渡すと、通常は画面の右下に置かれます。
主なプロパティは次のとおりです。
| プロパティ | 役割 |
|---|---|
| onPressed | 押したときの処理。null だと押せなくなる |
| child | ボタンの中身。ふつうはアイコン |
| tooltip | 長押ししたときに出る、ボタンの説明 |
| backgroundColor | ボタンの色 |
参考:FloatingActionButton(Flutter公式)
この記事では、次の画面を作ります。
- 右下のマイクボタンを押すと、聞き取り中(赤)と停止中を切り替わる。アイコンと説明文も変わる
- 「マイクボタン許可」スイッチをオフにすると、マイクボタンを押せなくなる
- 5種類のボタンを押すと、押した回数が増える
ソースコード
- mic_button.dart
マイクボタンの部品です。状態で色とアイコンを変えます。
import 'package:flutter/material.dart';
/// 音声入力の開始/停止ボタン。聞き取り中は赤くなる。
/// onPressed が null のときは押せない。
class MicButton extends StatelessWidget {
const MicButton({
super.key,
required this.isListening,
required this.onPressed,
});
final bool isListening;
final VoidCallback? onPressed;
@override
Widget build(BuildContext context) {
return FloatingActionButton(
onPressed: onPressed,
tooltip: isListening ? '停止' : '音声入力開始',
backgroundColor: isListening ? Colors.red : null,
child: Icon(isListening ? Icons.mic : Icons.mic_none),
);
}
}- button_page.dart
画面です。状態と、5種類のボタンを持ちます。
import 'package:flutter/material.dart';
import '../widgets/mic_button.dart';
class ButtonPage extends StatefulWidget {
const ButtonPage({super.key, required this.title});
final String title;
@override
State<ButtonPage> createState() => _ButtonPageState();
}
class _ButtonPageState extends State<ButtonPage> {
bool _isListening = false;
bool _enabled = true;
int _tapCount = 0;
void _toggleListening() => setState(() => _isListening = !_isListening);
void _countUp() => setState(() => _tapCount++);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget.title)),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(_isListening ? '聞き取り中(デモ)' : '停止中'),
SwitchListTile(
title: const Text('マイクボタン許可'),
value: _enabled,
onChanged: (value) => setState(() => _enabled = value),
),
const Divider(),
Text('ボタンの種類(押した回数: $_tapCount)'),
const SizedBox(height: 12),
Wrap(
spacing: 12,
runSpacing: 12,
children: [
FilledButton(onPressed: _countUp, child: const Text('Filled')),
ElevatedButton(onPressed: _countUp, child: const Text('Elevated')),
OutlinedButton(onPressed: _countUp, child: const Text('Outlined')),
TextButton(onPressed: _countUp, child: const Text('Text')),
IconButton(
onPressed: _countUp,
tooltip: 'Icon',
icon: const Icon(Icons.thumb_up),
),
],
),
],
),
),
floatingActionButton: MicButton(
isListening: _isListening,
onPressed: _enabled ? _toggleListening : null,
),
);
}
}- main.dart
動かすための最小の入口です。mic_button.dart は lib/widgets/、button_page.dart は lib/pages/ に置きます。
import 'package:flutter/material.dart';
import 'pages/button_page.dart';
void main() {
runApp(
const MaterialApp(home: ButtonPage(title: 'ボタン')),
);
}解説
画面(ButtonPage)が、「聞き取り中か」「マイクボタンを押せるか」「押した回数」の3つの状態を持ちます。マイクボタンの見た目は、MicButton が受け取った値だけで決まります。
MicButton:状態で色とアイコンを変える
isListening が true のときだけ赤くし、アイコンとツールチップも切り替えています。
backgroundColor: isListening ? Colors.red : null,
child: Icon(isListening ? Icons.mic : Icons.mic_none),条件が true か false かで値を選ぶ書き方です。backgroundColor に null を渡すと、テーマで決まっている標準の色になります。
色だけでなくアイコンも変えているので、色の違いが見分けにくい人にも、状態が伝わります。
onPressed に null を渡す
MicButton の onPressed は、VoidCallback? という型で受け取ります。? は、null も受け取れるという意味です。
画面側では、スイッチの状態で、処理と null を切り替えます。
onPressed: _enabled ? _toggleListening : null,backgroundColor: onPressed == null
? Colors.grey
: (isListening ? Colors.red : null),部品に切り出す理由
マイクボタンを MicButton として別のクラスに切り出すと、見た目の決まりごと(赤くする、アイコンを変える)を1か所にまとめられます。画面側は、状態を渡すだけで済みます。同じボタンを別の画面で使うときにも、そのまま使えます。
_countUp:5種類のボタンに同じ処理を渡す
5種類のボタンには、すべて同じ _countUp を渡しています。押した回数が増えることで、どのボタンも同じように onPressed で動くことが確かめられます。
実装
- Flutter のプロジェクトを作る(追加するパッケージはありません)
- 2つのファイルを、上の場所に置く
- main.dart を書き換えて、実行する
マイクボタンを押すと赤くなり、もう一度押すと元に戻ります。スイッチをオフにすると、マイクボタンを押せなくなります。
まとめ
- ボタンは FilledButton・ElevatedButton・OutlinedButton・TextButton・IconButton の5種類を使い分ける
- 押したときの処理は onPressed に渡し、null を渡すと押せなくなる
- FloatingActionButton は、画面でいちばん大事な操作に1つだけ置く
- 押せなくするときは、見た目も変えて、押せないと分かるようにする
- 状態で変わる見た目は、部品に切り出して1か所にまとめる


