Skip to content

fluttercandies/extended_keyboard

Repository files navigation

extended_keyboard

pub package GitHub stars GitHub forks GitHub license GitHub issues flutter-candies

Language: English| 中文简体

Flutter plugin for create custom keyboards quickly.

Install

Run flutter pub add extended_keyboard, or add extended_keyboard to pubspec.yaml dependencies manually.

dependencies:
  extended_keyboard: ^latest_version

Use

SystemKeyboard

A singleton class that manages system keyboard height and provides functionality to handle keyboard layout changes.

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await SystemKeyboard().init();
  runApp(const MyApp());
}

KeyboardBuilder

if we want to close the keyboard without losing textfield focus, we can't use SystemChannels.textInput.invokeMethod<void>('TextInput.hide') any more. related issue flutter/flutter#16863

Following code is a workaround.

TextField(
  showCursor: true,
  readOnly: true,
)

KeyboardTypeBuilder

A widget that listens to changes in the CustomKeyboardController and builds a widget accordingly.

   KeyboardTypeBuilder(
     builder: (
       BuildContext context,
       CustomKeyboardController controller,
     ) =>
         ToggleButton(
       builder: (bool active) => Icon(
         Icons.sentiment_very_satisfied,
         color: active ? Colors.orange : null,
       ),
       activeChanged: (bool active) {
         _keyboardPanelType = KeyboardPanelType.emoji;
         if (active) {
           controller.showCustomKeyboard();
           if (!_focusNode.hasFocus) {
             SchedulerBinding.instance
                 .addPostFrameCallback((Duration timeStamp) {
               _focusNode.requestFocus();
             });
           }
         } else {
           controller.showSystemKeyboard();
         }
       },
       active: controller.isCustom &&
           _keyboardPanelType == KeyboardPanelType.emoji,
     ),
   ),

CustomKeyboardController

A controller for managing the keyboard type and notifying listeners.

  • KeyboardType : The current keyboard type
  • isCustom : whether current keyboard is custom
  • showCustomKeyboard : show the custom keyboard
  • hideCustomKeyboard : hide the custom keyboard
  • showSystemKeyboard : show the system keyboard (set readOnly to false, it works if the input is on hasFocus)
  • unfocus : make the input lost focus and hide the system keyboard or custom keyboard

KeyboardBuilder

if Scaffold is used, make sure set Scaffold.resizeToAvoidBottomInset to false.

Using the KeyboardBuilder widget to encapsulate the area containing the input field allows for the creation of a custom keyboard layout within its builder callback. The builder function receives a parameter named systemKeyboardHeight, which represents the height of the last system keyboard displayed. This parameter can be utilized to set an appropriate height for your custom keyboard, ensuring a seamless and intuitive user experience.

parameter description default
builder A builder function that returns a widget based on the system keyboard height. required
bodyBuilder The main body widget builder with a parameter readOnly required
resizeToAvoidBottomInset The same as Scaffold.resizeToAvoidBottomInset. true
controller The controller for the custom keyboard. null
  return Scaffold(
    resizeToAvoidBottomInset: false,
    appBar: AppBar(title: const Text('ChatDemo(KeyboardBuilder)')),
    body: SafeArea(
      bottom: true,
      child: KeyboardBuilder(
        resizeToAvoidBottomInset: true,
        builder: (BuildContext context, double? systemKeyboardHeight) {
          return Container();
        },
        bodyBuilder: (bool readOnly) => Column(children: <Widget>[
          Row(
            children: <Widget>[
              Expanded(
                child: TextField(
                  readOnly: readOnly, 
                  showCursor: true,
                  onTap: () {
                    _customKeyboardController.showSystemKeyboard();
                  },
                ),
              ),
              KeyboardTypeBuilder(
                builder: (
                  BuildContext context,
                  CustomKeyboardController controller,
                ) =>
                    ToggleButton(
                  builder: (bool active) => Icon(
                    Icons.sentiment_very_satisfied,
                    color: active ? Colors.orange : null,
                  ),
                  activeChanged: (bool active) {
                    _keyboardPanelType = KeyboardPanelType.emoji;
                    if (active) {
                      controller.showCustomKeyboard();
                      if (!_focusNode.hasFocus) {
                        SchedulerBinding.instance
                            .addPostFrameCallback((Duration timeStamp) {
                          _focusNode.requestFocus();
                        });
                      }
                    } else {
                      controller.showSystemKeyboard();
                    }
                  },
                  active: controller.isCustom &&
                      _keyboardPanelType == KeyboardPanelType.emoji,
                ),
              ),
            ],
          ),
        ]),
      ),
    ),
  );

img

Full Demo

TextInputScope

KeyboardBinding / KeyboardBindingMixin

You can directly use KeyboardBinding or mix the KeyboardBindingMixin into your WidgetsFlutterBinding.

Future<void> main() async {
  KeyboardBinding();
  await SystemKeyboard().init();
  runApp(const MyApp());
}

KeyboardConfiguration

This configuration includes how the keyboard should be built, its animation durations, and how it should behave with respect to resizing.

parameter description default
getKeyboardHeight Function that calculates the height of the custom keyboard. required
builder The main body widget. required
keyboardName The name of the keyboard required
showDuration Duration for the keyboard's show animation. const Duration(milliseconds: 200)
hideDuration Duration for the keyboard's hide animation. const Duration(milliseconds: 200)
resizeToAvoidBottomInset The same as Scaffold.resizeToAvoidBottomInset. if it's null, it's equal to TextInputScope.resizeToAvoidBottomInset null
  KeyboardConfiguration(
    getKeyboardHeight: (double? systemKeyboardHeight) =>
        systemKeyboardHeight ?? 346,
    builder: () {
      return Container();
    },
    keyboardName: 'custom_number1',
    resizeToAvoidBottomInset: true,
  ),

TextInputScope

if Scaffold is used, make sure set Scaffold.resizeToAvoidBottomInset to false.

parameter description default
body The main body widget. required
configurations A list of KeyboardConfiguration required
keyboardHeight The default height of the keyboard. 346
resizeToAvoidBottomInset The same as Scaffold.resizeToAvoidBottomInset. true
  late List<KeyboardConfiguration> _configurations;
  @override
  void initState() {
    super.initState();
    _configurations = <KeyboardConfiguration>[
      KeyboardConfiguration(
        getKeyboardHeight: (double? systemKeyboardHeight) =>
            systemKeyboardHeight ?? 346,
        builder: () {
          return Container();
        },
        keyboardName: 'custom_number',
      ),
    ];
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('TextInputDemo'),
      ),
      resizeToAvoidBottomInset: false,
      body: SafeArea(
        bottom: true,
        child: TextInputScope(
          body: Padding(
            padding: const EdgeInsets.symmetric(horizontal: 5),
            child: Column(
              children: <Widget>[
                TextField(
                  keyboardType: _configurations[0].keyboardType,
                  controller: _controller,
                  decoration: InputDecoration(
                    hintText:
                        'The keyboardType is ${_configurations[0].keyboardType.name}',
                  ),
                ),
              ],
            ),
          ),
          configurations: _configurations,
        ),
      ),
    );
  }

img

Full Demo

extension

The extension for TextEditingController

  • void insertText(String text) Insert text at the current selection or replace the current selection with
  • void delete() Delete the character before the current selection or delete the current selection
  • TextEditingValue deleteText() Delete the character before the current selection or delete the current selection and handle the TextEditingValue base on your case
  • void performAction(TextInputAction action) The same as TextInputClient.performAction

About

Flutter plugin for create custom keyboards quickly.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages