skip to Main Content

Struggling to find the right approach to reducing keyboard open/close lag

I am a long-time Flutter dev since the beta days, so it feels kinda weird to be asking something that should be so straight forward to get right, but I just can’t.

I’m quite happy with performance in most areas of my app, especially since the latest Flutter update. However, I have a chat screen and of course the keyboard here is vital, being used, opened and closed all the time. I’ve tried multiple approaches, but all of them show varying degrees of low frame rate or lag:

Used the default route of Scaffold with resizeToAvoidBottomInset set to true – this is the worst performance, as the widgets on screen take considerable time to rebuild again.

Tried WidgetsBindingObserver to control a size animation to push the screen up when WidgetsBinding.instance.window.viewInsets.bottom increases above zero. Even with all the screen contents in the child of an AnimatedBuilder, this isn’t a huge gain from 1).

Tried the package keyboard_attachable. This has been the best result so far, but there’s still some delay between the keyboard state changing and the screen moving.

For context, my company went native for iOS, so this only concerns Android. I’ve tested the above methods on release, using shader warm-up.

All I’ve seen on matters relating to this on S/O are vague suggestions to "improve your build methods" so that the tree being rebuilt is not doing too much work. That may be true for some apps sure, but I think I’ve done enough to mitigate this. I don’t use widget functions, everything is well divided into classes with none of the state changing during the build (I use blocs, and the same bloc instance is passed to the children each time), and very little computationally aside from some positional values being worked out in the build.

Is it really just a case of some inefficiencies in the build? It’s driving me crazy not seeing this talked about much. Any pointers on what to try or investigate?

2

Answers


  1. I would recommend using Stack and Positioned Widget. Stack Widget will allow you to overlay widgets on top of each other and then use Positioned widget inside the Stack to position the input area at the bottom of the screen. It removes a lot of widget rebuilds that may occur in other approaches.

    Login or Signup to reply.
  2. I have been struggling with the same issue of yours and this is how I handled it:

    first, replace all MediaQuery.of(context).size to MediaQuery.sizeOf(context)
    the reason is that some properties (other than size) of MediaQuery change when the keyboard is open and close and its trigger unnecessary build.

    second, in android the keyboard can be customized so flutter cannot know its height, so I used the package keyboard_height_plugin and used it to animate the bottom padding of my screen myself:

    final keyboardHeightPlugin = KeyboardHeightPlugin();
    keyboardHeightPlugin.onKeyboardHeightChanged((double height) {
      setState(() => keyboardHeight = height);
      if (height == 0) {
        animation.reverse();
      } else {
        animation.forward();
      }
    });
    

    I have chosen the duration of the animation to be 200 milliseconds and the curve to be Curves.easeOutSine

    lastly, the performance in apk is much better than in debug mode

    Edit

    if you find the height of the keyboard to not be correct is because when the keyboard is open, the MediaQuery.of(context).padding.bottom becomes 0.0 so you need to consider it when calculating the keyboardHeight

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search