【问题标题】:Flutter: Keyboard's tab button creates a space in TextFormFieldsFlutter:键盘选项卡按钮在 TextFormField 中创建空间
【发布时间】:2020-06-25 13:03:00
【问题描述】:

我已经接受这就是 Flutter 的工作原理,但希望有人能解释为什么物理键盘的选项卡按钮在导航到下一个表单字段时会在 TextFormField 中创建一个空间?我已经使用 RawKeyboardInput 分配选项卡以转移焦点(它确实如此),但它仍然在表单字段中创建单个空间。

在存储数据时,拥有这个单一空间可能会导致许多问题,因此我更愿意在此时修复它,而不是稍后再执行“string.strip()”。

【问题讨论】:

  • 非常感谢任何和所有建议。

标签: flutter dart


【解决方案1】:

我在 TextEditingController() 的实例中使用了函数 trim() 来删除所有空格。

final _controllerEmail = TextEditingController();

user.email = _controllerEmail.text.trim();

更多参考函数 trim() https://api.dart.dev/stable/2.10.4/dart-core/String/trim.html

【讨论】:

    【解决方案2】:

    我在 Android 模拟器中测试表单并使用 TAB 移动到下一个 TextFormField 时遇到了同样的问题。

    我的解决方法是将TextFormField 包装在RawKeyboardListener 中。

    下面的代码有你需要的一切,你可以忽略“LoginStore”相关的东西,因为我使用的是 MobX 状态管理器。

    示例:

    import 'package:flutter/material.dart';
    import 'package:flutter/services.dart';
    import 'package:flutter/widgets.dart';
    
    class LoginScreen extends StatefulWidget {
      @override
      _LoginScreenState createState() => _LoginScreenState();
    }
    
    class _LoginScreenState extends State<LoginScreen> {
    
      TextEditingController _userNameController = TextEditingController();
      TextEditingController _passwordController = TextEditingController();
    
      FocusNode _usernameFocusNode;
      FocusNode _passwordKeyboardFocusNode;
      FocusNode _passwordFocusNode;
    
      LoginStore _loginStore;
    
      @override
      void initState() {
        super.initState();
        _passwordFocusNode = FocusNode();
        _passwordKeyboardFocusNode = FocusNode();
        _usernameFocusNode = FocusNode();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          primary: true,
          body: Material(
            child: Stack(
              children: <Widget>[
                userNameTextField(),
                SizedBox(height: 12.0),
                passwordTextField(),
                SizedBox(height: 12.0),
                loginButton()
              ]
            )
          )
        );
      }
    
      Widget userNameTextField() {
        //mobx observer omitted
        return RawKeyboardListener(
          focusNode: _usernameFocusNode,
          child: TextFormField(
            decoration: InputDecoration(
              hintText: "username",
              errorText: _loginStore.formErrorStore.username
            ),
            controller: _userNameController,
            onChanged: (dynamic value) {
              _loginStore.setUserName(_userNameController.text);
            },
            onFieldSubmitted: (dynamic value) {
              FocusScope.of(context).requestFocus(_passwordFocusNode);
            }
          ),
          onKey: (RawKeyEvent event) {
            if (event.isKeyPressed(LogicalKeyboardKey.tab)) {
              var currentText = _userNameController.text;
              var textWithoutTab = currentText.replaceAll("\t", "");
              //update the controller and the store
              _userNameController.text = textWithoutTab;
              _loginStore.setUserName(_userNameController.text);
              //move the focus to the password form
              FocusScope.of(context).requestFocus(_passwordFocusNode);
            }
          }
        );
      }
    
      Widget passwordTextField() {
        //mobx observer omitted
        return RawKeyboardListener(
          focusNode: _passwordKeyboardFocusNode,
          child: TextFormField(
            decoration: InputDecoration(
              hintText: "password",
              errorText: _loginStore.formErrorStore.password
            ),
            controller: _passwordController,
            onChanged: (dynamic value) {
              _loginStore.setPassword(_passwordController.text);
            }
          ),
          onKey: (RawKeyEvent event) {
            if (event.isKeyPressed(LogicalKeyboardKey.tab)) {
              var currentText = _passwordController.text;
              var textWithoutTab = currentText.replaceAll("\t", "");
              //update the controller and the store
              _passwordController.text = textWithoutTab;
              _loginStore.setPassword(_passwordController.text);
            }
          }
        );
      }
    
      Widget loginButton() {
        //add a login button as you want ....
      }
    
      @override
      void dispose() {
        // Clean up the controller when the Widget is removed from the Widget tree
        _userNameController.dispose();
        _passwordController.dispose();
        _passwordKeyboardFocusNode.dispose();
        _passwordFocusNode.dispose();
        _usernameFocusNode.dispose();
        super.dispose();
      }
    
    }
    

    请记住,使用像 _passwordController.text = textWithoutTab; 这样的自定义值设置文本控制器不会触发 onChanged 回调,如果您执行表单验证,您需要保持状态与更新的文本同步,这就是我必须这样做的原因再次调用_loginStore.setPassword(_passwordController.text);

    【讨论】:

    • 我认为这就是我的解决方案。 [var textWithoutTab = currentText.replaceAll("\t", "");] 但这是我试图避免的工作。我在 RawKeyboardListener 中也有我的。我只是没有进行字符串操作,因为我认为可能有解决办法。
    • 目前无法避免,这是一个 Flutter 错误,应该在 TextField 小部件中修复(我没有深入研究 Flutter 代码来检查导致错误的原因)跨度>
    • 可惜。哦,好吧,那就为解决方案打一个绿色的勾。
    • 谢谢,希望这个答案对其他人有所帮助
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-31
    • 2019-08-12
    • 2019-05-04
    • 2020-04-28
    • 1970-01-01
    • 2022-01-26
    • 2018-10-24
    相关资源
    最近更新 更多