AppBarにボタンを配置
まずは、AppBarにボタンをたくさん配置してみます。
AppBarにボタンを配置する方法は2種類あります。
- titleプロパティに配置
- actionsプロパティに配置
今回は一般的なactionsにボタンを4つ配置してみます。
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: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
// これでデバック用のリボンを消せる
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
// ボタンを配置
actions: [
ElevatedButton(onPressed: () {}, child: const Text('AAA')),
ElevatedButton(onPressed: () {}, child: const Text('BBB')),
ElevatedButton(onPressed: () {}, child: const Text('CCC')),
ElevatedButton(onPressed: () {}, child: const Text('DDD')),
],
),
);
}
}
これで、AppBarにボタンの配置ができました。
ちなみに、titleプロパティにボタンを置きたい場合はこのようになります。
appBar: AppBar(
title: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(widget.title),
const SizedBox(width: 30,),
ElevatedButton(onPressed: () {}, child: const Text('AAA')),
ElevatedButton(onPressed: () {}, child: const Text('BBB')),
ElevatedButton(onPressed: () {}, child: const Text('CCC')),
ElevatedButton(onPressed: () {}, child: const Text('DDD')),
],
),
),
エラー発生
actionsにボタンを配置できましたが、問題点があります。
※titleプロパティにボタンを置いた場合も同様です。
画面サイズが小さいときに以下のエラーが発生します。
このエラーは、ボタンなどのウィジェットが描画できなくなった際に発生します。
Webなら勝手にスクロールしてくれたりしますが、Flutterではそうはいきません。
自分で対応しなくてはなりません。
今回はその対応策を紹介します。
エラー対応策
エラーの対応策としては、「画面サイズが一定のサイズ以下になったら消す」です。
ただ、消すとそのボタンの役割をどこかで対応する必要があります。
このような対応を「レスポンシブ対応」と呼びます。
今回は、画面サイズが一定以下になったら
ドロワーを追加してそこにボタンを移動させたいと思います。
画面サイズによって描画内容を変更
まずは、画面サイズによってボタンを描画したり、しなかったらするコードを書きます。
画面サイズは「MediaQuery」を使用して取得します。
actions: [
MediaQuery.of(context).size.width > 600
?
Row(
children: [
ElevatedButton(onPressed: () {}, child: const Text('AAA')),
ElevatedButton(onPressed: () {}, child: const Text('BBB')),
ElevatedButton(onPressed: () {}, child: const Text('CCC')),
ElevatedButton(onPressed: () {}, child: const Text('DDD')),
],
)
:
Container()
],
ドロワーにボタンを移動
次は、画面サイズが小さいときにAppBarのボタンを描画せずに、
ドロワーにボタンを作成してみます。
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: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
actions: [
MediaQuery.of(context).size.width > 600
?
Row(
children: [
ElevatedButton(onPressed: () {}, child: const Text('AAA')),
ElevatedButton(onPressed: () {}, child: const Text('BBB')),
ElevatedButton(onPressed: () {}, child: const Text('CCC')),
ElevatedButton(onPressed: () {}, child: const Text('DDD')),
],
)
:
Container()
],
),
// ドロワーの設定
drawer: MediaQuery.of(context).size.width > 600
?
null // null を返すとドロワーのアイコンが表示されない
:
Drawer(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
ElevatedButton(onPressed: () {}, child: const Text('AAA')),
ElevatedButton(onPressed: () {}, child: const Text('BBB')),
ElevatedButton(onPressed: () {}, child: const Text('CCC')),
ElevatedButton(onPressed: () {}, child: const Text('DDD')),
],
)
),
);
}
}
これでAppBarのレスポンシブ対応は完了です。
あとはデザインですね!
デザイン調整
最後にデザインがデフォルトのままなので、修正しておきます。
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: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
backgroundColor: Colors.white,
foregroundColor: Colors.black54,
actions: [
MediaQuery.of(context).size.width > 600
?
Row(
children: [
Container(
padding: const EdgeInsets.all(10),
child: TextButton.icon(
onPressed: () {},
icon: const Icon(Icons.add),
label: const Text('AAA'),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.black45),
foregroundColor: MaterialStateProperty.all(Colors.white)
),
),
),
Container(
padding: const EdgeInsets.all(10),
child: TextButton.icon(
onPressed: () {},
icon: const Icon(Icons.search),
label: const Text('BBB'),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.black45),
foregroundColor: MaterialStateProperty.all(Colors.white)
),
),
),
Container(
padding: const EdgeInsets.all(10),
child: TextButton.icon(
onPressed: () {},
icon: const Icon(Icons.settings),
label: const Text('CCC'),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.black45),
foregroundColor: MaterialStateProperty.all(Colors.white)
),
),
),
Container(
padding: const EdgeInsets.all(10),
child: TextButton.icon(
onPressed: () {},
icon: const Icon(Icons.task_alt),
label: const Text('DDD'),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.black45),
foregroundColor: MaterialStateProperty.all(Colors.white)
),
),
),
],
)
:
Container()
],
),
drawer: MediaQuery.of(context).size.width > 600
?
null
:
Drawer(
child: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: [Colors.blue, Colors.amber],
begin: Alignment.topLeft,
end: Alignment.bottomRight
)
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Container(
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(vertical: 30), // 縦方向にスペース
decoration: const BoxDecoration(
color: Colors.transparent // 背景を透明に
),
child: Text(widget.title, style: TextStyle(color: Colors.white, fontSize: 20, fontStyle: FontStyle.italic)),
),
Container(
padding: const EdgeInsets.all(10),
child: TextButton.icon(
onPressed: () {},
icon: const Icon(Icons.add),
label: const Text('AAA'),
style: ButtonStyle(
foregroundColor: MaterialStateProperty.all(Colors.white)
),
),
),
Container(
padding: const EdgeInsets.all(10),
child: TextButton.icon(
onPressed: () {},
icon: const Icon(Icons.search),
label: const Text('BBB'),
style: ButtonStyle(
foregroundColor: MaterialStateProperty.all(Colors.white)
),
),
),
Container(
padding: const EdgeInsets.all(10),
child: TextButton.icon(
onPressed: () {},
icon: const Icon(Icons.settings),
label: const Text('CCC'),
style: ButtonStyle(
foregroundColor: MaterialStateProperty.all(Colors.white)
),
),
),
Container(
padding: const EdgeInsets.all(10),
child: TextButton.icon(
onPressed: () {},
icon: const Icon(Icons.task_alt),
label: const Text('DDD'),
style: ButtonStyle(
foregroundColor: MaterialStateProperty.all(Colors.white)
),
),
),
],
),
)
),
);
}
}
最後に
どうでしたでしょうか?
解決策になれば幸いです。
エラー対応は面倒ですが、そのあとのデザイン変更を楽しみに頑張ってください!
コメント