「TextField」や「TextFormField」に、入力候補を表示してくれる「Autocomplete」は、とても便利で、かつ外部パッケージではなく、Flutter標準のクラスなので、よく使っています。
しかし、テキスト入力欄が画面の下の方にある場合を想定して、入力候補の表示を、入力欄の下方ではなく上方に表示させようとしたところ、思いのほか、苦労しました。
ネット情報やChat-GPTを活用しても、スムーズには解決できなかったので、その過程を簡単に共有します。
前提とする環境
- PC:MacBook Pro(Intel Core i5)
- OS:macOS Sonoma 14.5
- Flutter:3.27.1、3.19.6(複数アプリで2種類のバージョンを使用)
- Android Studio:Koala 2024.1.1 Patch 1
「OptionsViewOpenDirection.up」を設定すると表示されなくなる
調べたところ、下記スレッドに情報があり、「Autocomplete」の「optionsViewOpenDirection」というプロパティに、「OptionsViewOpenDirection.up」を設定すれば良いと分かりました。
しかし、これを設定すると、なぜか候補が表示されなくなりました。。
Chat-GPTに尋ねると、「optionsViewOpenDirection」プロパティを使用するのではなく、
「optionsViewBuilder」プロパティに設定している「ListView」を、
「FractionalTranslation(translation: const Offset(0, -1.0),・・・)」でラップして、表示位置を上にズラすと良い
という手法を提案されました。
やってみると、確かに上にズレて表示はできましたが、今後は、表示された候補リストの部分を触っても、スクロールや選択ができません。
どうやらこの方法だと、表示自体はズレるのですが、タッチ判定の位置は上にズレてくれないようです。。
Alignの設定を組み合わせて解決
その後、試行錯誤しましたが、結論としては、
- 「OptionsViewOpenDirection.up」を使用しつつ、
- 候補表示の「ListView」を「Align」でラップし、
- 「alignment」プロパティを「Alignment.bottomLeft」
※「Alignment.bottomCenter」や「Alignment.bottomRight」でも可
にすれば、上方に表示できました。
元々、「Align」でラップしてはいたのですが、「Alignment.topLeft」にしてしまっていたのが、不具合の要因だったようです。
その後、色々と試して分かったのですが、例えば、入力欄が画面最下部にあり、かつ、キーボードを非表示の状態にすると、「Alignment.topLeft」(「topRight」や「topCenter」も同じ)では、画面の上端に候補が表示され、「Alignment.centerLeft」にすると、画面の中央あたりに候補が表示されました。
この状態でキーボードが表示されたり、入力欄を画面中央に置いたりすれば、更に全体が上にズレるので、「Alignment.topLeft」や「Alignment.centerLeft」にすると、候補リストが画面から見えない位置に飛んでしまう、という事のようです。
ご参考に、今回作成した、DartPad上で挙動を試せる「Autocomplete」上方表示のコード例を掲載します。
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(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Autocomplete<String>(
optionsViewOpenDirection: OptionsViewOpenDirection.up,
optionsBuilder: (TextEditingValue textEditingValue) {
if (textEditingValue.text == '') {
return const Iterable<String>.empty();
}
return ['apple', 'banana', 'cherry']
.where((String option) {
return option.contains(textEditingValue.text.toLowerCase());
});
},
fieldViewBuilder: (BuildContext context,
TextEditingController textEditingController,
FocusNode focusNode,
VoidCallback onFieldSubmitted) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: TextField(
controller: textEditingController,
focusNode: focusNode,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'フルーツを入力',
),
),
);
},
optionsViewBuilder: (BuildContext context,
AutocompleteOnSelected<String> onSelected,
Iterable<String> options) {
return Align(
alignment: Alignment.bottomLeft, // ←これが重要:リストを上方向に展開
child: Material(
elevation: 4.0,
child: SizedBox(
height: 200.0,
child: ListView.builder(
itemCount: options.length,
itemBuilder: (BuildContext context, int index) {
final String option = options.elementAt(index);
return ListTile(
title: Text(option),
onTap: () {
onSelected(option);
},
);
},
),
),
),
);
},
),
const SizedBox(height: 50.0),
],
),
),
),
);
}
}
実際に実装する際には、画面内の「Autocomplete」の縦方向の位置に応じて、下方表示(OptionsViewOpenDirection.down)と、上方表示(OptionsViewOpenDirection.up)を切替えると、ユーザビリティが高いと思われます。
以上、どなたかのご参考になりましたら幸いです。
リリースしたアプリ(全てFlutterで開発)
個人アプリ開発で役立ったもの
おすすめの学習教材
\超初心者向けでオススメな元Udemyの講座/
\キャンペーン時を狙えば安価で網羅的な内容が学べる(日本語訳あり)/
\Gitの基礎について無料で学べる/
おすすめの学習書籍
\実用的。image_pickerに関してかなり助けられた/
\Dartの基礎文法を素早くインプットできる/








コメント