Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/flutter/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/dart/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Flutter 颤振:键盘';s选项卡按钮在TextFormFields中创建一个空格_Flutter_Dart - Fatal编程技术网

Flutter 颤振:键盘';s选项卡按钮在TextFormFields中创建一个空格

Flutter 颤振:键盘';s选项卡按钮在TextFormFields中创建一个空格,flutter,dart,Flutter,Dart,我已经接受了这一点,这就是颤振的工作原理,但我希望有人能解释为什么在导航到下一个表单字段时,物理键盘的tab按钮会在TextFormField中创建一个空格?我已经使用RawKeyboardInput来分配选项卡来移动焦点(它确实如此),但它仍然会在表单字段中创建一个空格 在存储数据时,使用这一个空格可能会导致许多问题,因此我更愿意在此时修复它,而不是稍后使用“string.strip()”。在Android emulator中测试表单,并使用TAB键移动到下一个TextFormField时,

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


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

在Android emulator中测试表单,并使用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();
  }

}
导入“包装:颤振/材料.省道”;
导入“包:flifter/services.dart”;
导入“package:flatter/widgets.dart”;
类LoginScreen扩展StatefulWidget{
@凌驾
_LoginsScreenState createState()=>\u LoginsScreenState();
}
类_LoginScreenState扩展状态{
TextEditingController_userNameController=TextEditingController();
TextEditingController_passwordController=TextEditingController();
FocusNode\u用户名FocusNode;
FocusNode_密码键盘FocusNode;
FocusNode_密码FocusNode;
物流商店(LoginStore);;
@凌驾
void initState(){
super.initState();
_passwordFocusNode=FocusNode();
_passwordKeyboardFocusNode=FocusNode();
_usernameFocusNode=FocusNode();
}
@凌驾
小部件构建(构建上下文){
返回脚手架(
小学:对,
主体:材料(
子:堆栈(
儿童:[
userNameTextField(),
尺寸箱(高度:12.0),
passwordTextField(),
尺寸箱(高度:12.0),
登录按钮()
]
)
)
);
}
小部件userNameTextField(){
//忽略mobx观察器
返回键盘侦听器(
focusNode:_usernameFocusNode,
子项:TextFormField(
装饰:输入装饰(
hintText:“用户名”,
errorText:_loginStore.formErrorStore.username
),
控制器:\ u userNameController,
onChanged:(动态值){
_loginStore.setUserName(_userNameController.text);
},
onFieldSubmitted:(动态值){
FocusScope.of(context.requestFocus)(\u passwordFocusNode);
}
),
onKey:(RawKeyEvent事件){
if(event.isKeyPressed(LogicalKeyboardKey.tab)){
var currentText=\u userNameController.text;
var textWithoutTab=currentText.replaceAll(“\t”和“);
//更新控制器和存储
_userNameController.text=textWithoutTab;
_loginStore.setUserName(_userNameController.text);
//将焦点移到密码窗体
FocusScope.of(context.requestFocus)(\u passwordFocusNode);
}
}
);
}
小部件密码文本字段(){
//忽略mobx观察器
返回键盘侦听器(
focusNode:_密码键盘focusNode,
子项:TextFormField(
装饰:输入装饰(
hintText:“密码”,
errorText:_loginStore.formErrorStore.password
),
控制器:_passwordController,
onChanged:(动态值){
_loginStore.setPassword(_passwordController.text);
}
),
onKey:(RawKeyEvent事件){
if(event.isKeyPressed(LogicalKeyboardKey.tab)){
var currentText=\u passwordController.text;
var textWithoutTab=currentText.replaceAll(“\t”和“);
//更新控制器和存储
_passwordController.text=text不带选项卡;
_loginStore.setPassword(_passwordController.text);
}
}
);
}
小部件登录按钮(){
//根据需要添加登录按钮。。。。
}
@凌驾
无效处置(){
//当小部件从小部件树中移除时,清理控制器
_userNameController.dispose();
_passwordController.dispose();
_passwordKeyboardFocusNode.dispose();
_passwordFocusNode.dispose();
_usernameFocusNode.dispose();
super.dispose();
}
}
请记住,使用如下自定义值设置文本控制器
\u passwordController.text=textWithoutTab
,在更改后不会触发
回调,如果执行表单验证,则需要保持状态与更新的文本同步,这就是为什么我必须执行另一个调用
\u loginStore.setPassword(\u passwordController.text)

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

final _controllerEmail = TextEditingController();

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

有关更多参考资料,请参阅函数trim()

非常感谢所有建议。我认为这是我的解决方案。[var textWithoutTab=currentText.replaceAll(“\t”,““””);]但这是我试图避免的工作。我也有一个键盘监听器。我只是没有做字符串操作,因为我认为可能有解决办法。你目前无法避免它,这是一个颤振错误,应该在TextField小部件中修复(我没有深入研究颤振代码来检查导致错误的原因)遗憾。哦,好吧,那就给解决方案打个绿色的勾吧。谢谢你,希望这个答案对其他人有帮助