Flutter - Detect Keyboard is Open or Closed

This tutorial shows you how to detect the visibility of the on-screen keyboard in Flutter, whether it's open or closed.

When an application is running, there can be a soft keyboard displayed on the screen, typically when the user is editing a field. Sometimes, an application may need to detect whether the keyboard is visible or not. In this tutorial, I'm going to show you how to do it in Flutter by using a third party package.

Using flutter_keyboard_visibility

There is a plugin named flutter_keyboard_visibility that provides the capability to detect whether the keyboard is open or closed. You need to add it as a dependency

  flutter pub add flutter_keyboard_visibility

Then, you can use it by adding the following import statement.

  import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart';

The library provides some different ways to get the visibility of the keyboard as shown below.

Using KeyboardVisibilityBuilder

First, you can use a class named KeyboardVisibilityBuilder. It requires you to pass a function as the builder argument which will be invoked when the keyboard visibility changes. The passed function must return a widget and accept two parameters whose types in order are BuildContext and bool. The latter indicates that the keyboard is visible if the value is true.

  class Example1 extends StatelessWidget {
  
    const Example1({super.key});
  
    @override
    Widget build(BuildContext context) {
      return Padding(
        padding: const EdgeInsets.all(20.0),
        child: Column(
          children: [
            const TextField(),
            const SizedBox(height: 20.0),
            KeyboardVisibilityBuilder(
              builder: (BuildContext context, bool isKeyboardVisible) {
                return Text('Is Visible: $isKeyboardVisible');
              },
            ),
          ],
        ),
      );
    }
  }

Using KeyboardVisibilityProvider

Another way is using the KeyboardVisibilityProvider widget. It's a widget that can report to its descendants whether the keyboard is visible. This way, you have to add a KeyboardVisibilityProvider widget with another widget as the child. When the keyboard visibility changes, the child widget will be rebuilt. In the child widget that's below KeyboardVisibilityProvider in the tree, you can call isKeyboardVisible method by passing the current BuildContext.

  class Example2 extends StatelessWidget {
  
    const Example2({super.key});
  
    @override
    Widget build(BuildContext context) {
      return const KeyboardVisibilityProvider(
        child: MyWidget(),
      );
    }
  }
  
  class MyWidget extends StatelessWidget {
  
    const MyWidget({super.key});
  
    @override
    Widget build(BuildContext context) {
      final bool isKeyboardVisible = KeyboardVisibilityProvider.isKeyboardVisible(context);
  
      return Padding(
        padding: const EdgeInsets.all(20.0),
        child: Column(
          children: [
            const TextField(),
            const SizedBox(height: 20.0),
            Text('Is Visible: $isKeyboardVisible'),
          ],
        ),
      );
    }
  }

Using KeyboardVisibilityController

Another alternative is to use a KeyboardVisibilityController, which allows you to pass one or more functions as listeners. First, you need to create an instance of it. To get the initial state, access the isVisible property of the instance.

The KeyboardVisibilityController has onChange getter which returns a Stream. Then, you can call the Stream's listen method to pass a listener function. The passed function needs to have one parameter, in this case a bool whose value is true if the keyboard is opened or false otherwise. Every time the keyboard becomes visible or hidden, the function will be invoked. In the example below, the passed function updates a state variable when it's invoked.

  class Example3 extends StatefulWidget {
  
    const Example3({super.key});
  
    @override
    State<StatefulWidget> createState() {
      return _Example3State();
    }
  }
  
  class _Example3State extends State<Example3> {
  
    late StreamSubscription<bool> _subscription; // import 'dart:async';
    late bool _isKeyboardVisible;
  
    @override
    void initState() {
      super.initState();
  
      final keyboardVisibilityController = KeyboardVisibilityController();
      _isKeyboardVisible = keyboardVisibilityController.isVisible;
  
      _subscription = keyboardVisibilityController.onChange.listen((bool isKeyboardVisible) {
        setState(() {
          _isKeyboardVisible = isKeyboardVisible;
        });
      });
    }
  
    @override
    void dispose() {
      _subscription.cancel();
      super.dispose();
    }
  
    @override
    Widget build(BuildContext context) {
      return Padding(
        padding: const EdgeInsets.all(20.0),
        child: Column(
          children: [
            const TextField(),
            const SizedBox(height: 20.0),
            Text('Is Visible: $_isKeyboardVisible'),
          ],
        ),
      );
    }
  }

Summary

If you need to detect the keyboard visibility when a Flutter application runs, you can use the functionality provided by flutter_keyboard_visibility. The package has several ways to do it. Keep in mind that, it may not be able to detect that a floating keyboard is shown.