🦍
【Flutter】BottomSheet を使ってテキスト入力する
BottomSheet とは
下からシュッと出てくるカードのような Widget です。
ダイアログなどでよくあるモーダルですね。(モーダル:背景が暗くなり対象がハイライトされる機能)
基本的には showModalBottomSheet()で呼べば良いと思います。
builder の中身は BottomSheet Widget もありますが、Container でカスタマイズしても良いです。
個人的には後者の方が扱いやすいです。
showModalBottomSheet
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return Container(
height: 200,
color: Colors.blue[200],
child: const Center(
child: Text("BottomSheet"),
),
);
},
);
showModalBottomSheet のパラメータ
パラメータ | 型 | 説明 |
---|---|---|
context |
BuildContext |
現在のBuildContext を指定。ウィジェットツリー内の位置情報などが含まれる。 |
builder |
WidgetBuilder |
ボトムシートの中身を構築するための関数。BuildContext を引数に取り、表示するウィジェットを返す。 |
backgroundColor |
Color |
ボトムシートの背景色。 |
elevation |
double |
ボトムシートの影の深さ。影をつけることで立体感を出す。 |
shape |
ShapeBorder |
ボトムシートの形状。角の丸みなどをカスタマイズ可能。 |
isScrollControlled |
bool |
ボトムシートが全画面に広がるかどうかを制御。true で全画面表示。 |
isDismissible |
bool |
ボトムシート外側をタップした時に閉じるかどうか。デフォルトはtrue 。 |
enableDrag |
bool |
ユーザーがボトムシートをドラッグして閉じることができるかどうか。デフォルトはtrue 。 |
barrierColor |
Color |
モーダルの背景色。ボトムシート以外の UI を覆う色。 |
clipBehavior |
Clip |
ボトムシートのコンテンツが枠を越えた場合のクリッピングの挙動を制御。 |
BottomSheet に TextField を配置
TextField配置
final TextEditingController _textEditingController = TextEditingController();
String? text1;
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return Container(
height: 250,
color: Colors.blue[200],
child: Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
children: [
const SizedBox(height: 32.0),
TextField(
controller: _textEditingController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'テキスト',
),
),
ElevatedButton(
onPressed: () {
setState(() {
text1 = _textEditingController.text;
});
_textEditingController.clear();
Navigator.pop(context);
},
child: const Text('OK')),
],
),
)),
);
},
);
キーボード出現時の注意点
テキスト入力をする際にキーボードが現れますが、テキスト入力部がキーボードで隠れてしまいます。
これを改善するために、MediaQuery.of(context).viewInsets.bottom を使ってキーボードの高さを取得します。
Container に高さにキーボード高さを足すことで BottomSheet の高さが可変になります。
viewInsets.bottom
Container(
height: 250 + MediaQuery.of(context).viewInsets.bottom,
)
実装サンプル
コード全文
import 'package:flutter/material.dart';
class BottomSheetSample extends StatefulWidget {
const BottomSheetSample({super.key});
State<BottomSheetSample> createState() => _BottomSheetSampleState();
}
class _BottomSheetSampleState extends State<BottomSheetSample> {
final TextEditingController _textEditingController = TextEditingController();
String? text1;
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
decoration: BoxDecoration(
color: Colors.blue[200],
border: Border.all(
color: Colors.black,
width: 1,
),
borderRadius: const BorderRadius.all(
Radius.circular(10.0),
),
),
width: 200,
padding: const EdgeInsets.all(16.0),
margin: const EdgeInsets.only(bottom: 16.0),
child: Text(text1 ?? ' ')),
ElevatedButton(
onPressed: () {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return Container(
height: 250 + MediaQuery.of(context).viewInsets.bottom,
decoration: BoxDecoration(
color: Colors.blue[200],
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(20.0),
topRight: Radius.circular(20.0),
),
),
child: Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
children: [
const SizedBox(height: 32.0),
TextField(
controller: _textEditingController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'テキスト',
),
),
ElevatedButton(
onPressed: () {
setState(() {
text1 = _textEditingController.text;
});
_textEditingController.clear();
Navigator.pop(context);
},
child: const Text('OK')),
],
),
)),
);
},
);
},
child: const Text('Show Bottom Sheet')),
],
),
),
);
}
}
Discussion