屏幕之间的颤动流构建器

问题描述

我是 Flutter 新手,我使用 streambuilder 实现了 bloc 架构。 我创建了 2 个页面,只有一个按钮可以改变我的背景颜色。所有这些页面都在监听流以更改背景颜色,但是当我在第一页上更改时,它不会在第二页上更改。 但是如果有 1 页决定更改它,我希望我的所有应用程序都更改

我是否需要初始化一个我的 2 个屏幕使用它的单例块?因为目前每个屏幕都初始化了自己的块 这是1页的例子(第二页是一样的)

class Test extends StatelessWidget {
  final ColorBloc _bloc = ColorBloc();

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<Response<ColorResponse>>(
      stream: _bloc.stream,builder: (context,snapshot) {
        if (snapshot.hasData) {
          return Scaffold(
              appBar: AppBar(
                title: Text('First Route clicked'),),backgroundColor: snapshot.data.data.color,body: new Center(
                  child: new InkWell(
                onTap: () {
                  Navigator.push(
                    context,MaterialPageRoute(builder: (context) => Act2()),);
                },// Handle your callback
                child: Ink(height: 100,width: 100,color: Colors.blue),)),floatingActionButton: FloatingActionButton(
                onpressed: () {
                  _bloc.changeColor(Colors.yellow);
                },child: Icon(Icons.navigation),backgroundColor: Colors.green,));
        }
        return Scaffold(
            appBar: AppBar(
              title: Text('First Route'),body: Center(
                child: new InkWell(
                    onTap: () {
                      Navigator.push(
                        context,);
                    },// Handle your callback
                    child: Ink(height: 200,width: 200,color: Colors.red))),floatingActionButton: FloatingActionButton(
              onpressed: () {
                _bloc.changeColor(Colors.yellow);
              },));
      },);
  }
}

解决方法

要在 bloc 触发事件时更改所有屏幕的状态,您可以使用多个 StreamBuilder,但它们都需要监听触发事件的 bloc。您可以尝试以下两种方式:

  • 将 bloc 作为参数传递到第二个屏幕
class Test extends StatelessWidget {
  final ColorBloc _bloc = ColorBloc();

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<Response<ColorResponse>>(

           // ... other lines

              body: new Center(
                  child: new InkWell(
                onTap: () {

                  // Pass your bloc to the 2nd screen
                  Navigator.push(
                    context,MaterialPageRoute(builder: (context) => Act2(bloc: _bloc)),);
                },// ... other lines
  • 使用诸如 provider 包之类的包将块传递到树中。在您的第一个屏幕中,您可以执行以下操作:
class Test extends StatelessWidget {
  final ColorBloc _bloc = ColorBloc();

  @override
  Widget build(BuildContext context) {

    // Use Provider to provide the bloc down the widget tree
    return Provider(
      create: (_) => _bloc,child: StreamBuilder<Response<ColorResponse>>(
        
        // ... other lines

然后在第二个屏幕(我假设是 Act2())中,您从提供者那里获得 ColorBloc:


class Act2 extends StatefulWidget {
  @override
  _Act2State createState() => _Act2State();
}

class _Act2State extends State<Act2> {
  ColorBloc _colorBloc;

  @override
  void didChangeDependencies() {
    // Get the bloc in the 1st page
    _colorBloc = Provider.of<ColorBloc>(context);
    super.didChangeDependencies();
  }

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<Response<ColorResponse>>(

      // Use the bloc like in the 1st page
      stream: _colorBloc.stream,builder: (context,snapshot) {
        if (snapshot.hasData) {
          // ... other lines

小注意:使用 StreamBuilder 时,您可以启动值而无需重复代码。由于我不知道您的 Response 对象的结构,我以 Response(ColorResponse(color: Colors.green)) 为例:

// ... other lines

@override
  Widget build(BuildContext context) {
    return Provider(
      create: (_) => _bloc,child: StreamBuilder<Response<ColorResponse>>(

        // Initiate your data here
        initialData: Response(ColorResponse(color: Colors.green)),stream: _bloc.stream,snapshot) {
          if (snapshot.hasData) {
            return Scaffold(
                appBar: AppBar(
                  title: Text('First Route clicked'),),backgroundColor: snapshot.data.data.color,// ... other lines

          }

          // Don't need to copy the above code block for the case when the data is not streamed yet
          return Container(child: Center(child: CircularProgressIndicator()));
        },);
  }