Reputation: 1650
I have a page in Flutter with a couple of widgets including a TextField (lets call this View1). When the user clicks the TextField I rebuild the page showing only the TextField and keyboard (lets call this View2). When the user finishes with the TextField I rebuild the page again showing all the widgets as before (lets call this View3 although note that it is the same as View1). This works fine except for one thing. I get a temporary yellow/black indicator (in debug mode) showing that there is not enough room to display all of the widgets in View3. The indicator only lasts a short time and I eventually worked out that it appears becasue Flutter is trying to display all the widgets while the keyboard has not yet finished animating away. Once the keyboard has finished animating away the yellow/black bar disappears and this explains I think why it only appears briefly.
It would be neat to request the build of View3 in a callback that executes when the keyboard has finished animating away but I don't see any way of doing that. Perhaps I'm missing something?
Another way I can think of to work around this would be to insert a delay before building View3 to allow time for the keyboard to disappear but this seems a little hacky. Has anyone any other ideas?
EDIT
I added a delay as follows and it works. Still seems a bit hacky though.
Timer(Duration(milliseconds: 500),(){setState((){});});
Upvotes: 10
Views: 5412
Reputation: 513
When I put all mentioned solutions together, it works well for me:
class KeyboardTogglePage extends StatefulWidget {
@override
_KeyboardTogglePageState createState() => _KeyboardTogglePageState();
}
class _KeyboardTogglePageState extends State<KeyboardTogglePage>
with WidgetsBindingObserver {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
// This routine is invoked when the window metrics have changed.
@override
void didChangeMetrics() {
final value = WidgetsBinding.instance.platformDispatcher.views.first.viewInsets.bottom;
bool isVisible = value > 0;
print("KEYBOARD VISIBLE: ${isVisible}");
}
@override
Widget build(BuildContext context) {
return Container(
child: Center(
child: TextField(),
),
);
}
}
Upvotes: 1
Reputation: 1
this usually happens when the view1 that is the previous screen that the navigator is popping to has a column in it. try changing your column to listview and this should fix the issue for you.
Upvotes: 0
Reputation: 103351
Try using WidgetsBindingObserver
and override the didChangeMetrics
method like this:
class KeyboardTogglePage extends StatefulWidget {
@override
_KeyboardTogglePageState createState() => _KeyboardTogglePageState();
}
class _KeyboardTogglePageState extends State<KeyboardTogglePage>
with WidgetsBindingObserver {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
var isKeyboardOpen = false;
///
/// This routine is invoked when the window metrics have changed.
///
@override
void didChangeMetrics() {
final value = MediaQuery.of(context).viewInsets.bottom;
if (value > 0) {
if (isKeyboardOpen) {
_onKeyboardChanged(false);
}
isKeyboardOpen = false;
} else {
isKeyboardOpen = true;
_onKeyboardChanged(true);
}
}
_onKeyboardChanged(bool isVisible) {
if (isVisible) {
print("KEYBOARD VISIBLE");
} else {
print("KEYBOARD HIDDEN");
}
}
@override
Widget build(BuildContext context) {
return Container(
child: Center(
child: TextField(),
),
);
}
}
Upvotes: 15