【问题标题】:Is it possible to build a system-wide custom keyboard for IOS and ANDROID in Flutter?是否可以在 Flutter 中为 IOS 和 ANDROID 构建系统范围的自定义键盘?
【发布时间】:2020-12-22 08:29:06
【问题描述】:

我希望构建一个适用于所有应用的自定义键盘。自定义键盘现在很常见。我想知道你是否能够在 Flutter 中构建一个可以工作并被 Apple 接受以在其他应用程序中工作的键盘。

【问题讨论】:

  • 你能做到吗??
  • 下面的答案很可能在 CustomInputViews 上,但仅限于您的应用程序,而不是系统范围内!你能做到吗?
  • 是的,它们并没有真正回答问题。

标签: flutter keyboard


【解决方案1】:

抱歉,在 Flutter 中无法做到这一点。 Flutter 是一个 UI 框架,不会像系统键盘那样扩展到操作系统级别的更改。但是您可以使用 Kotlin 或 Java 在 Android 上进行本地操作(不包括 iOS - 系统不支持 OS 模型的更改)。

【讨论】:

    【解决方案2】:

    我认为你不能在 Flutter 中构建系统范围的键盘,因为它是一个 UI 框架。我相信您可以使用受人尊敬的操作系统开发语言(Android 的 Java、Koltin 以及 iOS 设备的 Swift)构建一个,因为它需要某些权限才能实际用作系统范围的键盘。

    您可以使用 Flutter 构建 UI 本身,但不能构建整个键盘。键盘的其余部分需要是 Java 或 Android 的 Koltin 或 iOS 的 Swift。

    最后,如果您只想在应用程序中使用键盘,您可以使用 Flutter 构建它并使用应用程序的语言来控制输入。

    如果你想做一个全局键盘,我推荐这个指南:https://www.androidauthority.com/lets-build-custom-keyboard-android-832362/

    如果你想在 UI 上使用 Flutter,我会替换本指南中使用它的 UI 的部分,并将其替换为 Flutter。

    祝你在冒险中好运,如果你确实制作了一个好的键盘,请给我一个下载链接,因为 GBoard 快把我逼疯了。

    【讨论】:

    • iOS 允许自定义系统范围的键盘,developer.apple.com/documentation/uikit/keyboards_and_input/…。即使自定义键盘需要是原生项目,但这并不一定意味着它不能托管 Flutter 模块来处理 UI 和业务逻辑。
    • 在这种情况下,是的,您可以使用 iOS 构建一个。我遇到了 Flutter 无法单独使用键盘的地方——它可以处理 UI,但不能处理实际的键盘输入等。我会更新我的答案。
    【解决方案3】:

    最好使用系统键盘!

    您可以使用键盘设置,例如数字、小数、文本、电子邮件等 输入/

    【讨论】:

      【解决方案4】:

      您可以参考https://pub.dev/packages/keyboard_actions 通过 Flutter 以简单的方式创建自定义键盘/向 Android/iOS 添加功能。

      项目Github链接:https://github.com/diegoveloper/flutter_keyboard_actions/tree/master/example

      注意:
      1.然后您应该在 IntelliJ/Android Studio 中运行 flutter packages upgrade 或更新您的包。
      2. 你需要 Flutter 的依赖,如下所示:

      dependencies:
        keyboard_actions: "^3.1.2"
      

      Flutter 中自定义键盘的一些特性:

      1. 键盘的完成按钮(您可以自定义按钮)。
      2. 在您的文本字段之间向上/向下移动(您可以隐藏设置 nextFocus: false)。
      3. 键盘栏自定义。
      4. 键盘栏下方的自定义页脚小部件
      4. 轻松创建自己的键盘
      4. 您可以将它用于 Android、iOS 或两种平台。
      4. 与Dialog兼容。

      用法:

      import  'package:flutter/material.dart';
      import  'package:keyboard_actions/keyboard_actions.dart';
      
      
      class Content extends StatefulWidget {
        const Content({
          Key key,
        }) : super(key: key);
      
        @override
        _ContentState createState() => _ContentState();
      }
      
      class _ContentState extends State<Content> {
        final FocusNode _nodeText1 = FocusNode();
        final FocusNode _nodeText2 = FocusNode();
        final FocusNode _nodeText3 = FocusNode();
        final FocusNode _nodeText4 = FocusNode();
        final FocusNode _nodeText5 = FocusNode();
        final FocusNode _nodeText6 = FocusNode();
        final FocusNode _nodeText7 = FocusNode();
      
        /// Creates the [KeyboardActionsConfig] to hook up the fields
        /// and their focus nodes to our [FormKeyboardActions].
        KeyboardActionsConfig _buildConfig(BuildContext context) {
          return KeyboardActionsConfig(
            keyboardActionsPlatform: KeyboardActionsPlatform.ALL,
            keyboardBarColor: Colors.grey[200],
            nextFocus: true,
            actions: [
              KeyboardAction(
                focusNode: _nodeText1,
              ),
              KeyboardAction(
                focusNode: _nodeText2,
                closeWidget: Padding(
                  padding: EdgeInsets.all(8.0),
                  child: Icon(Icons.close),
                ),
              ),
              KeyboardAction(
                focusNode: _nodeText3,
                onTapAction: () {
                  showDialog(
                      context: context,
                      builder: (context) {
                        return AlertDialog(
                          content: Text("Custom Action"),
                          actions: <Widget>[
                            FlatButton(
                              child: Text("OK"),
                              onPressed: () => Navigator.of(context).pop(),
                            )
                          ],
                        );
                      });
                },
              ),
              KeyboardAction(
                focusNode: _nodeText4,
                displayCloseWidget: false,
              ),
              KeyboardAction(
                focusNode: _nodeText5,
                closeWidget: Padding(
                  padding: EdgeInsets.all(5.0),
                  child: Text("CLOSE"),
                ),
              ),
              KeyboardAction(
                focusNode: _nodeText6,
                footerBuilder: (_) => PreferredSize(
                    child: SizedBox(
                        height: 40,
                        child: Center(
                          child: Text('Custom Footer'),
                        )),
                    preferredSize: Size.fromHeight(40)),
              ),
            ],
          );
        }
      
        @override
        Widget build(BuildContext context) {
          return KeyboardActions(
            config: _buildConfig(context),
            child: Center(
              child: Padding(
                padding: const EdgeInsets.all(15.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.stretch,
                  children: <Widget>[
                    TextField(
                      keyboardType: TextInputType.number,
                      focusNode: _nodeText1,
                      decoration: InputDecoration(
                        hintText: "Input Number",
                      ),
                    ),
                    TextField(
                      keyboardType: TextInputType.text,
                      focusNode: _nodeText2,
                      decoration: InputDecoration(
                        hintText: "Input Text with Custom Close Widget",
                      ),
                    ),
                    TextField(
                      keyboardType: TextInputType.number,
                      focusNode: _nodeText3,
                      decoration: InputDecoration(
                        hintText: "Input Number with Custom Action",
                      ),
                    ),
                    TextField(
                      keyboardType: TextInputType.text,
                      focusNode: _nodeText4,
                      decoration: InputDecoration(
                        hintText: "Input Text without Close Widget",
                      ),
                    ),
                    TextField(
                      keyboardType: TextInputType.number,
                      focusNode: _nodeText5,
                      decoration: InputDecoration(
                        hintText: "Input Number with Custom Close Widget",
                      ),
                    ),
                    TextField(
                      keyboardType: TextInputType.number,
                      focusNode: _nodeText6,
                      decoration: InputDecoration(
                        hintText: "Input Number with Custom Footer",
                      ),
                    ),
                  ],
                ),
              ),
            ),
          );
        }
      }
      

      使用自定义键盘:

      import  'package:flutter/material.dart';
      import  'package:keyboard_actions/keyboard_actions.dart';
      
      class Content extends StatelessWidget {
        final FocusNode _nodeText7 = FocusNode();
        final FocusNode _nodeText8 = FocusNode();
        //This is only for custom keyboards
        final custom1Notifier = ValueNotifier<String>("0");
        final custom2Notifier = ValueNotifier<Color>(Colors.blue);
      
        /// Creates the [KeyboardActionsConfig] to hook up the fields
        /// and their focus nodes to our [FormKeyboardActions].
        KeyboardActionsConfig _buildConfig(BuildContext context) {
          return KeyboardActionsConfig(
            keyboardActionsPlatform: KeyboardActionsPlatform.ALL,
            keyboardBarColor: Colors.grey[200],
            nextFocus: true,
            actions: [
              KeyboardAction(
                focusNode: _nodeText7,
                footerBuilder: (_) => CounterKeyboard(
                  notifier: custom1Notifier,
                ),
              ),
              KeyboardAction(
                focusNode: _nodeText8,
                footerBuilder: (_) => ColorPickerKeyboard(
                  notifier: custom2Notifier,
                ),
              ),
            ],
          );
        }
      
        @override
        Widget build(BuildContext context) {
          return KeyboardActions(
            config: _buildConfig(context),
            child: Center(
              child: Container(
                padding: const EdgeInsets.all(15.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.stretch,
                  children: <Widget>[
                    KeyboardCustomInput<String>(
                      focusNode: _nodeText7,
                      height: 65,
                      notifier: custom1Notifier,
                      builder: (context, val, hasFocus) {
                        return Container(
                          alignment: Alignment.center,
                          color: hasFocus ? Colors.grey[300] : Colors.white,
                          child: Text(
                            val,
                            style:
                                TextStyle(fontSize: 30, fontWeight: FontWeight.bold),
                          ),
                        );
                      },
                    ),
                    KeyboardCustomInput<Color>(
                      focusNode: _nodeText8,
                      height: 65,
                      notifier: custom2Notifier,
                      builder: (context, val, hasFocus) {
                        return Container(
                          width: double.maxFinite,
                          color: val ?? Colors.transparent,
                        );
                      },
                    ),
                  ],
                ),
              ),
            ),
          );
        }
      }
      
      
      /// A quick example "keyboard" widget for picking a color.
      class ColorPickerKeyboard extends StatelessWidget
          with KeyboardCustomPanelMixin<Color>
          implements PreferredSizeWidget {
        final ValueNotifier<Color> notifier;
        static const double _kKeyboardHeight = 200;
      
        ColorPickerKeyboard({Key key, this.notifier}) : super(key: key);
      
        @override
        Widget build(BuildContext context) {
          final double rows = 3;
          final double screenWidth = MediaQuery.of(context).size.width;
          final int colorsCount = Colors.primaries.length;
          final int colorsPerRow = (colorsCount / rows).ceil();
          final double itemWidth = screenWidth / colorsPerRow;
          final double itemHeight = _kKeyboardHeight / rows;
      
          return Container(
            height: _kKeyboardHeight,
            child: Wrap(
              children: <Widget>[
                for (final color in Colors.primaries)
                  GestureDetector(
                    onTap: () {
                      updateValue(color);
                    },
                    child: Container(
                      color: color,
                      width: itemWidth,
                      height: itemHeight,
                    ),
                  )
              ],
            ),
          );
        }
      

      预期输出:


      【讨论】:

      • OP 正在询问如何在 Flutter 中构建系统范围的键盘。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-18
      相关资源
      最近更新 更多