math_keyboard logo

math keyboard GitHub repo math_keyboard Flutter web demo math_keyboard on Pub

math_keyboard is a Flutter package that allows editing math expressions using a typeset input field (so-called "math field") and a custom-made fully integrated math keyboard in Flutter only - no plugins, no web views.

Features

  • Editing math expressions using a custom on-screen software keyboard
  • Editing via physical keyboard input (with shortcuts for functions and constants)
  • Support for both number and expression mode
  • Advanced operators and trigonometric functions (e.g. sqrt, ln, sin, etc.)
  • View insets support (on-screen keyboard overlay pushes up e.g. the body in Scaffold)
  • Full focus tree integration: works with regular text fields, manual FocusNodes, tabbing, etc.
  • Autofocus support
  • Form field support
  • Decimal separator based on locale
  • Converting TeX from and to math expressions

You can view all features in action in the demo app.

Usage

To use this plugin, follow the installing guide.

Implementation

The most basic way of integrating the math keyboard is by just adding a MathField somewhere in your app. This works exactly like Flutter TextFields do - even with the same InputDecoration decoration functionality!

@override
Widget build(BuildContext context) {
  return MathField(
    // No parameters are required.
    keyboardType: MathKeyboardType.expression, // Specify the keyboard type (expression or number only).
    variables: const ['x', 'y', 'z'], // Specify the variables the user can use (only in expression mode).
    decoration: const InputDecoration(), // Decorate the input field using the familiar InputDecoration.
    onChanged: (String value) {}, // Respond to changes in the input field.
    onSubmitted: (String value) {}, // Respond to the user submitting their input.
    autofocus: true, // Enable or disable autofocus of the input field.
  );
}

Now, tapping inside of the math field (or focusing it via the focus tree) will automatically open up the math keyboard and start accepting physical keyboard input on desktop.

Note that physical keyboard input on mobile causes weird behavior due to a Flutter issue.

View insets

A very useful feature of the math keyboard is the fact that it tries to mirror the regular software keyboard as closely as possible. Part of that is reporting its size to the MediaQuery in the form of view insets. This will seamlessly integrate with widgets like Scaffold and the existing view insets reporting of software keyboards.

All you have to do to use this feature is making sure that your Scaffold (that your MathFields live in) are wrapped in MathKeyboardViewInsets:

@override
Widget build(BuildContext context) {
  return MathKeyboardViewInsets(
    child: Scaffold(
      // ...
    ),
  );
}

Please see the documentation for more advanced use cases - this part of the docs is quite detailed :)

Furthermore, the package provides some convenience functions for detecting whether a keyboard is showing:

Form support

In order to use a MathField in a Flutter Form, you can simply use a MathFormField in place of a regular MathField. This mirrors the regular field with extended functionality and behaves exactly like TextFormField from the framework. See the latter for advanced documentation.

@override
Widget build(BuildContext context) {
  return MathFormField(
    // ...
  );
}

Custom controller

You can always specify a custom MathFieldEditingController. This allows you to clear all input for example. Make sure to dispose the controller.

class FooState extends State<FooStatefulWidget> {
  late final _controller = MathFieldEditingController();

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  void _onTapClear() {
    _controller.clear();
  }

  @override
  Widget build(BuildContext context) {
    return MathField(
      controller: _controller,
      decoration: InputDecoration(
        suffix: MouseRegion(
          cursor: MaterialStateMouseCursor.clickable,
          child: GestureDetector(
            onTap: _onTapClear,
            child: const Icon(
              Icons.highlight_remove_rounded,
              color: Colors.grey,
            ),
          ),
        ),
      ),
    );
  }
}

Custom focus node

You can always specify your own FocusNode if you wish to manage focus yourself. This works like any other focus-based widget (like TextField). Note that autofocus still works when supplying a custom focus node.

class FooState extends State<FooStatefulWidget> {
  late final _focusNode = FocusNode(debugLabel: 'Foo');

  @override
  void dispose() {
    _focusNode.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MathField(
      focusNode: _focusNode,
    );
  }
}

Decimal separators

Note that not all countries use a dot . as decimal separator (see reference). If the locale obtained via Localizations.localeOf uses a comma , as decimal separator, both the separator in the math field as well as the symbol on the keyboard are adjusted. Otherwise, a dot . is used. You can override the locale using the Localizations.override widget (wrap your MathFields with it).

Note that physical keyboard input always accepts both . and ,.

Math expressions

To convert the TeX strings returned by the math keyboard into math expressions, you can make use of the provided TeXParser:

final mathExpression = TeXParser(texString).parse();

For the opposite operation, i.e. converting a math Expression to TeX, you can make use of the provided convertMathExpressionToTeXNode:

final texNode = convertMathExpressionToTeXNode(expression);

Note that this returns an internal TeXNode format, which you can convert to a TeX string:

final texString = texNode.buildTexString();

Libraries

math_keyboard