FocusScope class Flutterでkeyboardを閉じる
📕Overview
FocusScope は Focus と似ていますが、その子孫のスコープとしても機能し、 フォーカスのトラバーサルをスコープされたコントロールに制限します。
たとえば、ルートがプッシュされると新しい FocusScope が自動的に作成され、フォーカスのトラバーサルが前のルートのコントロールに移動しないようにします。
ウィジェットをグループ化し、特定の順序でトラバースされるようにしたいが、フォーカスがグループから離れる可能性がある場合は、FocusTraversalGroup を使用します。
Focus と同様に、FocusScope にも onFocusChange があり、このウィジェットにフォーカスが移ったときや、このウィジェットからフォーカスが外れたときに通知されます。
onKey 引数では、このノードまたはその子ノードのいずれかがフォーカスを持ったときに呼び出されるキー・イベント・ハンドラを指定できます。キーは、最初にフォーカスが当たった主ウィジェットに渡され、その後、そのノードの祖先を通して伝搬し、そのうちの 1 つが onKey から KeyEventResult.handled を返し、イベントを処理したことを示すと停止します。
FocusScopeNode を管理することは、そのライフサイクルを管理し、フォーカスの変化をリッスンし、必要に応じて再ペアレントして、フォーカス階層とウィジェット階層を同期させることを意味します。このウィジェットは、これらすべてを行います。FocusScope ウィジェットを使用せず、ノード管理を自分で行う必要がある場合の詳細については、FocusScopeNode を参照してください。
FocusScopeNode は、その子孫の中で最後にフォーカスされた FocusNode を記憶しており、そのフォーカスを次/前のノードや特定の
🧷summary
使うことが想定されるusecaseは、ボタンを押したときに、keyboardを閉じるロジックを実装したいときでした。皆ためかっこよくないですが、このようなUIを作って試してみました。
❌ボタンを押すか、コメントするボタンを押すと、FocusScope.of(context).unfocus();
が実行され、keyboardが閉じます。標準機能で閉じれると思ったのですが、改行できるTextFieldにすると、使えませんでした!
サンプルコード:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final List<String> items = [
'aaaa',
'aaaa',
'aaaa',
];
TextEditingController _textEditingController = TextEditingController();
void dispose() {
_textEditingController.dispose();
super.dispose();
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: const Text('Cook Book'),
),
body: Stack(
children: [
Container(
color: Colors.green,
child: ListView.builder(
itemCount: items.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(items[index]),
);
},
)),
Align(
alignment: Alignment.bottomCenter,
child: Container(
color: Colors.white,
height: 100,
child: Row(
children: [
const SizedBox(width: 30),
SizedBox(
width: 150,
child: TextField(
controller: _textEditingController,
decoration: InputDecoration(
suffixIcon: IconButton(
onPressed: () => FocusScope.of(context).unfocus(),
icon: const Icon(Icons.clear, color: Colors.grey, size: 15),
),
border: OutlineInputBorder(),
),
maxLines: null,
)),
const SizedBox(
width: 15,
),
ElevatedButton(
child: const Text("コメントする"),
onPressed: () {
setState(() {
items.add(_textEditingController.text);
});
FocusScope.of(context).unfocus();
_textEditingController.clear();
},
),
],
),
),
)
],
),
);
}
}
🧑🎓thoughts
今回は、keyboardを閉じる方法を調べていたときに、メモ書きですが記事を書くことにしました。Swiftとかだと設定しないと閉じれなかったような。SwiftUIは問題なかったかな🤔
必要な場面があると思うので、参考になりそうでしたが使ってみてください。
Discussion