Flutter textfield光标无法正常工作

Flutter textfield光标无法正常工作,flutter,Flutter,当我从数据库检索数据并将其显示在文本字段中,然后尝试编辑时,文本字段光标无法正常工作 我希望每次返回change方法的validate结果时都能考虑光标的位置 完整代码如下 import 'dart:async'; import 'package:flutter/material.dart'; import 'package:rxdart/rxdart.dart'; void main() => runApp(MyApp()); class MyApp extends Statel

当我从数据库检索数据并将其显示在文本字段中,然后尝试编辑时,文本字段光标无法正常工作

我希望每次返回change方法的validate结果时都能考虑光标的位置

完整代码如下

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:rxdart/rxdart.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'TextField Test',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  TextEditingController _nameController = TextEditingController();
  TextEditingController _emailController = TextEditingController();
  ApplicationBloc _bloc;

  @override
  void initState() {
    super.initState();
    _bloc = new ApplicationBloc();
    _bloc.initData();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('TextField Test'),
      ),
      body: ListView(
        shrinkWrap: true,
        children: <Widget>[_buildName(), _buildEmail(), _buildSubmit()],
      ),
    );
  }

  Widget _buildName() {
    return StreamBuilder(
      stream: _bloc.name,
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          _nameController.text = snapshot.data;
        }
        return TextField(
          controller: _nameController,
          onChanged: _bloc.changeName,
          keyboardType: TextInputType.text,
          decoration: InputDecoration(
            labelText: "Name",
            errorText: snapshot.error,
          ),
        );
      },
    );
  }

  Widget _buildEmail() {
    return StreamBuilder(
      stream: _bloc.email,
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          _emailController.text = snapshot.data;
        }
        return TextField(
          controller: _emailController,
          onChanged: _bloc.changeEmail,
          keyboardType: TextInputType.emailAddress,
          decoration: InputDecoration(
            labelText: "Email",
            errorText: snapshot.error,
          ),
        );
      },
    );
  }

  Widget _buildSubmit() {
    return StreamBuilder(
      stream: _bloc.submit,
      builder: (context, snapshot) {
        return RaisedButton(
          onPressed: (!snapshot.hasData || !snapshot.data)
              ? null
              : () {
                  _bloc.submitForm();
                  _nameController.text = '';
                  _emailController.text = '';
                },
          child: Text('Submit!'),
        );
      },
    );
  }
}

class ApplicationBloc {
  BehaviorSubject<String> _nameController =
      BehaviorSubject<String>(seedValue: '');
  Observable<String> get name => _nameController.stream.transform(validateName);
  Function(String) get changeName => _nameController.sink.add;

  BehaviorSubject<String> _emailController =
      BehaviorSubject<String>(seedValue: '');
  Observable<String> get email =>
      _emailController.stream.transform(validateEmail);
  Function(String) get changeEmail => _emailController.sink.add;

  Observable<bool> get submit => Observable.combineLatest2(
      name, email, (e, e1) => e.isNotEmpty && e1.isNotEmpty);

  initData() {
    // This data from database
    _nameController.sink.add('Test123');
    _emailController.sink.add('test@email.com');
  }    

  submitForm() {
    //Send to api and wait
    //Reset values
    Future.delayed(const Duration(seconds: 1));
  }

  final validateName =
      StreamTransformer<String, String>.fromHandlers(handleData: (name, sink) {
    if (name.isEmpty || name.length > 4) {
      sink.add(name);
    } else if (name.isNotEmpty) {
      sink.addError('Invalid Name!');
    }
  });

  final validateEmail =
      StreamTransformer<String, String>.fromHandlers(handleData: (email, sink) {
    String p =
        r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$';

    RegExp regExp = new RegExp(p);
    if (email.isEmpty || (email.length > 4 && regExp.hasMatch(email))) {
      sink.add(email);
    } else {
      sink.addError('Invalid email!');
    }
  });

  //dispose/close all the streams when we call dispose() method
  void dispose() {
    _nameController.close();
    _emailController.close();
  }
}
导入'dart:async';
进口“包装:颤振/材料.省道”;
导入“包:rxdart/rxdart.dart”;
void main()=>runApp(MyApp());
类MyApp扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回材料PP(
标题:“文本字段测试”,
主题:主题数据(
主样本:颜色。蓝色,
),
主页:主页(),
);
}
}
类主页扩展了StatefulWidget{
@凌驾
createState()=>_HomePageState();
}
类_HomePageState扩展状态{
TextEditingController _nameController=TextEditingController();
TextEditingController_emailController=TextEditingController();
应用集团(ApplicationBloc);;
@凌驾
void initState(){
super.initState();
_bloc=新应用程序bloc();
_bloc.initData();
}
@凌驾
小部件构建(构建上下文){
返回脚手架(
appBar:appBar(
标题:文本(“文本字段测试”),
),
正文:ListView(
收缩膜:对,
子项:[[u buildName(),[u buildEmail(),[u buildSubmit()],
),
);
}
小部件_buildName(){
返回流生成器(
流:_bloc.name,
生成器:(上下文,快照){
if(snapshot.hasData){
_nameController.text=snapshot.data;
}
返回文本字段(
控制器:_name控制器,
一旦更改:_bloc.changeName,
键盘类型:TextInputType.text,
装饰:输入装饰(
labelText:“名称”,
errorText:snapshot.error,
),
);
},
);
}
Widget_buildEmail(){
返回流生成器(
流:_bloc.email,
生成器:(上下文,快照){
if(snapshot.hasData){
_emailController.text=snapshot.data;
}
返回文本字段(
控制器:\u电子邮件控制器,
一旦更改:_bloc.changemail,
键盘类型:TextInputType.emailAddress,
装饰:输入装饰(
labelText:“电子邮件”,
errorText:snapshot.error,
),
);
},
);
}
小部件_buildSubmit(){
返回流生成器(
流:_bloc.submit,
生成器:(上下文,快照){
返回上升按钮(
按下:(!snapshot.hasData | |!snapshot.data)
无效的
: () {
_bloc.submitForm();
_nameController.text='';
_emailController.text='';
},
子项:文本('Submit!'),
);
},
);
}
}
类应用程序组{
行为主体_name控制器=
BehaviorSubject(种子值:“”);
可观察的get name=>\u nameController.stream.transform(validateName);
函数(字符串)get changeName=>\u nameController.sink.add;
行为主体\u电子邮件控制器=
BehaviorSubject(种子值:“”);
可观察的获取电子邮件=>
_emailController.stream.transform(validateEmail);
函数(字符串)get-changeEmail=>\u-emailController.sink.add;
Observable get submit=>Observable.CombineRelatest2(
名称,电子邮件,(e,e1)=>e.isNotEmpty&&e1.isNotEmpty);
initData(){
//此数据来自数据库
_nameController.sink.add('Test123');
_emailController.sink.add('test@email.com');
}    
submitForm(){
//发送到api并等待
//重置值
延迟(常数持续时间(秒:1));
}
最终验证名称=
StreamTransformer.fromHandlers(handleData:(名称,接收器){
if(name.isEmpty | | name.length>4){
添加(名称);
}else if(name.isNotEmpty){
sink.addError('无效名称!');
}
});
最终确认邮件=
StreamTransformer.fromHandlers(handleData:(电子邮件、接收器){
字符串p=
r'^([^()[\]\\,;:\s@']+(\.[^()[\]\,;:\s@']+*))(\[[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[1,3}.[0-9]{1,3}.]124;([a-zA Z-0-9]{a-zA Z]++$){2};
RegExp RegExp=新的RegExp(p);
if(email.isEmpty | |(email.length>4&®Exp.hasMatch(email))){
添加(电子邮件);
}否则{
sink.addError('无效电子邮件!');
}
});
//调用dispose()方法时,dispose/关闭所有流
无效处置(){
_nameController.close();
_emailController.close();
}
}

我尝试了一个将光标位置更改为final的代码,但当我尝试编辑文本字段的中间内容时,该代码无法正常工作。

如果您查看
文本编辑控制器的
文本设置器,您将看到:

设置文本(字符串newText){
value=value.copyWith(
文本:新文本,
选择:常量文本选择。折叠(偏移量:-1),
组合:TextRange.empty,
);
}
请注意,
选择
已重置,因此无法使用此设置器。相反,在构建器中,执行以下操作:

if(snapshot.hasData){
_nameController.value=\u nameController.value.copyWith(
text:snapshot.data,
);
}

只需更改文本,您不必担心其他属性。

非常感谢!