【Flutter】フォーカス時に現れるボックスが角丸な入力欄を作成する
はじめに
DropdownButtonFormFieldやTypeAheadFieldで、入力欄にフォーカスすると現れるドロップダウンリストやサジェストボックスを角丸にする方法を紹介します。
完成後の画面キャプチャは以下です。
ドロップダウンリスト
サジェストボックス
(Flutterバージョン)
> flutter --version
Flutter 3.16.5 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 78666c8dc5 (6 months ago) • 2023-12-19 16:14:14 -0800
Engine • revision 3f3e560236
Tools • Dart 3.2.3 • DevTools 2.28.4
角丸にする前
角丸にする前のコードと画面キャプチャを参考に載せておきます。
角丸にする前の実装
dependencies:
flutter:
sdk: flutter
+ flutter_typeahead: ^4.3.8
// ※GendersやPrefecturesはenumで定義してあります。
class _MyHomePageState extends State<MyHomePage> {
Genders myGender = Genders.none;
Prefectures myPrefecture = Prefectures.hokkaido;
TextEditingController controller = TextEditingController();
void initState() {
super.initState();
controller.text = myPrefecture.text;
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Padding(
padding: const EdgeInsets.all(25),
child: Column(
children: [
DropdownButtonFormField<Genders>(
decoration: const InputDecoration(
border: UnderlineInputBorder(),
labelText: '性別',
),
items: [
for (final gender in Genders.values)
DropdownMenuItem(
value: gender,
child: Text(gender.text),
)
],
onChanged: (value) {
if (value != null) {
setState(() {
myGender = value;
});
}
},
),
TypeAheadField(
textFieldConfiguration: TextFieldConfiguration(
controller: controller,
decoration: const InputDecoration(
border: UnderlineInputBorder(),
labelText: '都道府県',
),
),
suggestionsCallback: (pattern) async {
List<Prefectures> matches = [...Prefectures.values];
matches
.retainWhere((element) => element.text.contains(pattern));
return matches;
},
itemBuilder: (context, suggestion) {
return ListTile(title: Text(suggestion.text));
},
onSuggestionSelected: (suggestion) => setState(() {
myPrefecture = suggestion;
controller.text = suggestion.text;
}),
),
],
),
),
),
);
}
}
ドロップダウンリスト(角丸にする前)
サジェストボックス(角丸にする前)
DropdownButtonFormFieldについて
結論から書くと、PopupMenuButton + InputDecoratorで作成しました。
PopupMenuButton(
itemBuilder: (context) => [
for (final gender in Genders.values)
PopupMenuItem(
value: gender,
child: Text(gender.text),
)
],
initialValue: myGender,
onSelected: (value) => setState(() {
myGender = value;
}),
// 角丸なドロップダウンリストにする
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(8.0))),
child: InputDecorator(
decoration: const InputDecoration(
border: UnderlineInputBorder(),
labelText: '性別',
),
child: Text(myGender.text),
),
),
調べると、角丸なドロップダウンリストはPopupMenuButtonで実現するのが良さそうでした。↓
ただ、入力欄に相当する部分をchild
に指定しなければなりません。
自分は元のDropdownMenuButtonFormFieldに近い見た目にしたかったため、child
にInputDecoratorを用いることにしました。
このWidgetは見た目だけTextFieldのように見せてくれるようです。
TypeAheadFieldについて
TypeAheadFieldは、オプション引数suggestionsBoxDecoration
を用いて簡単に角丸なサジェストボックスを作ることができます。
TypeAheadField(
...
// 角丸なサジェストボックスにする
+ suggestionsBoxDecoration: SuggestionsBoxDecoration(
+ borderRadius: BorderRadius.circular(8.0)),
),
まとめ
DropdownButtonFormFieldはPopupMenuButtonとInputDecoratorを組み合わせることで、TypeAheadFieldはオプション引数で指定してあげるだけで角丸なリストボックスを実現できます。
前者は少し工夫してそれらしい見た目にしましたが、もっとスマートな方法があるような気もします。。。
ともあれ欲しかったWidgetを作れたので満足です。
今回のコードは以下に載せてます。
参考文献
Discussion