Stream 如何使用流转换和bloc重置表单中的字段

Stream 如何使用流转换和bloc重置表单中的字段,stream,flutter,rxdart,bloc,Stream,Flutter,Rxdart,Bloc,我有一个屏幕,我想用流转换验证字段。验证数据时,必须启用“提交”按钮。当我提交表单时,我希望保持在同一屏幕上并重置数据。必须停用发送按钮 验证过程正在运行,但当我单击提交时,表单重置过程不起作用 下面是完整的代码 import 'dart:async'; import 'package:flutter/material.dart'; import 'package:rxdart/rxdart.dart'; void main() => runApp(MyApp()); class

我有一个屏幕,我想用流转换验证字段。验证数据时,必须启用“提交”按钮。当我提交表单时,我希望保持在同一屏幕上并重置数据。必须停用发送按钮

验证过程正在运行,但当我单击提交时,表单重置过程不起作用

下面是完整的代码

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
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  ApplicationBloc _bloc;

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

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

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

  Widget _buildEmail(ApplicationBloc _bloc) {
    return StreamBuilder(
      stream: _bloc.email,
      builder: (context, snapshot) {
        return TextField(
          onChanged: _bloc.changeEmail,
          keyboardType: TextInputType.emailAddress,
          decoration: InputDecoration(
            labelText: "Email",
            errorText: snapshot.error,
          ),
        );
      },
    );
  }

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

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

  BehaviorSubject<String> _emailController = BehaviorSubject<String>();
  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) => true);

  submitForm() {
    //Send to api and wait
    //Reset values
    _nameController.add(null);
    _emailController.add(null);
  }

  final validateName =
      StreamTransformer<String, String>.fromHandlers(handleData: (name, sink) {
    if (name != null && name.length > 4) {
      sink.add(name);
    } else {
      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 != null && 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{
@凌驾
_HomePageState createState()=>\u HomePageState();
}
类_HomePageState扩展状态{
应用集团(ApplicationBloc);;
@凌驾
void initState(){
super.initState();
_bloc=新应用程序bloc();
}
@凌驾
小部件生成(BuildContext上下文){
返回脚手架(
appBar:appBar(
标题:文本(“现场文本测试”),
),
正文:ListView(
收缩膜:对,
儿童:[
_buildName(_bloc),
_buildEmail(_bloc),
_buildSubmit(集团)
],
),
);
}
Widget\u buildName(ApplicationBloc\u bloc){
返回流生成器(
流:_bloc.name,
生成器:(上下文,快照){
返回文本字段(
一旦更改:_bloc.changeName,
键盘类型:TextInputType.text,
装饰:输入装饰(
labelText:“名称”,
errorText:snapshot.error,
),
);
},
);
}
Widget\u buildEmail(ApplicationBloc\u bloc){
返回流生成器(
流:_bloc.email,
生成器:(上下文,快照){
返回文本字段(
一旦更改:_bloc.changemail,
键盘类型:TextInputType.emailAddress,
装饰:输入装饰(
labelText:“电子邮件”,
errorText:snapshot.error,
),
);
},
);
}
小部件构建提交(应用程序组){
返回流生成器(
流:_bloc.submit,
生成器:(上下文,快照){
返回上升按钮(
按下:(!snapshot.hasData | |!snapshot.data)
无效的
:()=>_bloc.submitForm(),
子项:文本('Submit!'),
);
},
);
}
}
类应用程序组{
行为主体_nameController=行为主体();
可观察的get name=>\u nameController.stream.transform(validateName);
函数(字符串)get changeName=>\u nameController.sink.add;
BehaviorSubject_emailController=BehaviorSubject();
可观察的获取电子邮件=>
_emailController.stream.transform(validateEmail);
函数(字符串)get-changeEmail=>\u-emailController.sink.add;
可观察的获取提交=>
可观察。组合相关度2(姓名、电子邮件,(e、e1)=>true);
submitForm(){
//发送到api并等待
//重置值
_nameController.add(空);
_emailController.add(空);
}
最终验证名称=
StreamTransformer.fromHandlers(handleData:(名称,接收器){
如果(name!=null&&name.length>4){
添加(名称);
}否则{
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!=null&&email.length>4&®Exp.hasMatch(email)){
添加(电子邮件);
}否则{
sink.addError('无效电子邮件!');
}
});
//调用dispose()方法时,dispose/关闭所有流
无效处置(){
_nameController.close();
_emailController.close();
}
}

(不在此代码中)我尝试使用控制器重置textfield,但submit按钮仍处于启用状态。

这是因为您的textfield没有侦听StreamBuilder中的文本值流。
例如,您的_bloc.changeName是一个控制器,只能将操作发布到流中,不能侦听任何值。

这是因为您的文本字段不侦听StreamBuilder中的文本值流。 例如,您的_bloc.changeName是一个控制器,只能将操作发布到流中,不能侦听任何值