title: Flutter Custom Keyboard ('Fake' soft keyboard)
body: <p>I'm working on a finance app and I'd like a custom textentry field and keyboard for currency entry with an inbuilt calculator.</p>
  
  <p>I've tried using a BottomSheet, both persistent and modal. The modal behaviour is ideal, but it always shows a barrier. The persistent one is what I have now, using a focus node to show and hide it, but it's throwing strange errors:  </p>
  
  <pre><code>I/flutter (30319): The following NoSuchMethodError was thrown while dispatching notifications for FocusNode:
  I/flutter (30319): The method 'removeLocalHistoryEntry' was called on null.
  I/flutter (30319): Receiver: null
  I/flutter (30319): Tried calling: removeLocalHistoryEntry(Instance of 'LocalHistoryEntry')
  I/flutter (30319):
  I/flutter (30319): When the exception was thrown, this was the stack:
  I/flutter (30319): #0      Object.noSuchMethod (dart:core/runtime/libobject_patch.dart:46:5)
  I/flutter (30319): #1      LocalHistoryEntry.remove (package:flutter/src/widgets/routes.dart:296:12)
  I/flutter (30319): #2      _NumpadFieldState.initState.&lt;anonymous closure&gt; (file:///D:/code/financepie/lib/widgets/numpad/numpadfield.dart:30:32)
  ...
  </code></pre>
  
  <p>In any case, the bottom sheet behaviour (dragging down) isn't really ideal to copy the android/ios soft keyboard. Any better solutions? Current code below:</p>
  
  <pre><code>import 'package:flutter/material.dart';
  import 'numpad.dart';
  
  class NumpadField extends StatefulWidget {
  
    @override
    _NumpadFieldState createState() {
      return new _NumpadFieldState();
    }
  }
  
  class _NumpadFieldState extends State&lt;NumpadField&gt; {
    ValueNotifier&lt;List&lt;String&gt;&gt; state;
    FocusNode focusNode;
    PersistentBottomSheetController bottomSheetController;
  
    @override initState() {
      super.initState();
      state = ValueNotifier&lt;List&lt;String&gt;&gt;([]);
      state.addListener(() =&gt; setState((){}));
      focusNode = FocusNode();
      focusNode.addListener(() {
        print(focusNode);
        if (focusNode.hasFocus) {
          bottomSheetController = showBottomSheet(
            context: context,
            builder: (context) =&gt; Numpad(state: state),
          );
        } else {
          bottomSheetController?.close(); ///this line causing the error
        }
      }); 
    }
    @override dispose() {
      state.dispose();
      focusNode.dispose();
      super.dispose();
    }
  
    @override
    Widget build(BuildContext context) {
      return GestureDetector(
        onTap: () {
          FocusScope.of(context).requestFocus(focusNode);
        },
        child: Container(
          child: Text(state.value.fold&lt;String&gt;("", (str, e) =&gt; "$str $e")),
          constraints: BoxConstraints.expand(height: 24.0),
          decoration: BoxDecoration(
            border: BorderDirectional(bottom: BorderSide())
          ),
        ),
      );
    }
  }
  </code></pre>