KeyboardDetector : HelperWidget to detect keyboard state

Dr_Skele·2022년 11월 15일
0

Flutter

목록 보기
3/19

How to check if keyboard is visible?

When you're working with TextField or TextFormField, keyboard keeps poping up from the bottom, and you would like to know when it pops up and goes back down.

Unfortunatly, there's no way of knowing only with the TextField. It's possible to know keyboard popup with using onTap, but there's no event for closing keyboard.

To know if keyboard is up, you'll need to check if the TextField is no longer focused, OR...

MediaQuery.of(context).viewInsets.bottom != 0

You can check if the view has changed. Keyboard changes the view when it shows up, so when it's visible, the value will be above 0. Otherwise, it'll be positive value.

Now, we know how to check visibility of a keyboard, it's time to use it.

@override
  Widget build(BuildContext context) {
  	keyboardVisiblity = MediaQuery.of(context).viewInsets.bottom != 0
    return widget;
  }

You can just use that line of code inside build() method of a widget.
But, I thought I'd make a custom widget for it.

Making Custom Widget for keyboard detection

Like the GestureDetector, I made my version of a detector widget for keyboard.

class KeyboardDetector extends StatefulWidget {
  const KeyboardDetector({
    Key? key,
    this.onOpenKeyboard,
    this.onCloseKeyboard,
    required this.child,
  }) : super(key: key);

  final Function()? onOpenKeyboard;
  final Function()? onCloseKeyboard;
  final Widget child;

  @override
  State<KeyboardDetector> createState() => _KeyboardDetectorState();
}

This custom widget has events for opening keyboard, and closing it.
Also, it needs to be wrapping the widgets that calls keyboard to detect it just like the GestureDetector, so it has a child.

class _KeyboardDetectorState extends State<KeyboardDetector> with WidgetsBindingObserver{

  bool previousState = false;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {
    // TODO: implement dispose
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangeMetrics(){
    bool currentState = MediaQuery.of(context).viewInsets.bottom != 0;
    if(previousState != currentState){
      previousState = currentState;
      if(currentState){
        print('open');
        widget.onOpenKeyboard?.call();
      }
      else{
        print('close');
        widget.onCloseKeyboard?.call();
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return widget.child;
  }
}

I've used the WidgetsBindingObserver to observe the change in the view. In the above code, there's didChangeMetrics(), and it's called when the screen dimensions changes. It's called several times while keyboard is poping up, so it's important to call the events only when the value changes.

Here's how it's used.

return KeyboardDetector(
      onOpenKeyboard: (){ setState((){ _isKeyboardVisible = true;} );  },
      onCloseKeyboard: (){ setState((){ _isKeyboardVisible = false; }); },
      child: Scaffold(
        appBar: AppBar(
          ...
        ),
        body: ...
        
        	TextField(
                controller: _textController,
                decoration: InputDecoration(
                  fillColor: Colors.transparent,
                  hintText: 'title'
                ),
              ),
        bottomSheet: Offstage(
          offstage: !_isKeyboardVisible,
          child: ...
        ),
      ),
    );
profile
Tireless And Restless Debugging In Source : TARDIS

0개의 댓글