Flutter textfield光标无法正常工作
当我从数据库检索数据并将其显示在文本字段中,然后尝试编辑时,文本字段光标无法正常工作 我希望每次返回change方法的validate结果时都能考虑光标的位置 完整代码如下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
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,
);
}
只需更改文本,您不必担心其他属性。非常感谢!