iBob101
iBob101

Reputation: 1650

Flutter detect end of keyboard hide animation

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

Answers (3)

Rafa2602
Rafa2602

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

Deev.saini
Deev.saini

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

diegoveloper
diegoveloper

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

Related Questions