如何在 Widget 之外调度 Bloc 事件?

mar*_*337 11 flutter flutter-bloc

我是 Bloc 架构的新手,最近看了一些教程。我有一个 StatelessWidget 页面,在里面我使用 BlocProvider 来初始化 UI 中的 Bloc。它将根据状态变化返回不同的小部件。

\n

但即使在教程中,他们也仅从其他小部件调度事件(例如通过按按钮)。但在我的情况下,我需要在 Bloc Event 中的 Widget 之外调用 init API 调用。

\n

如果我在其他 Widget 中,我可以调用它BlocProvider.of<FirstTabBloc>(context).dispatch(GetUserProfile());,但无法在 main() 中调用它,因为上下文不是来自 Widget。

\n

代码:

\n
class FirstPage extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      body: SingleChildScrollView(\n        child: firstTabElement(context),\n      ),\n      appBar: EmptyAppBar(mainAppColor),\n    );\n  }\n\n  BlocProvider<FirstTabBloc> firstTabElement(BuildContext context) {\n    return BlocProvider(\n        builder: (_) => sl<FirstTabBloc>(),\n        child: Expanded(\n            child: Container(\n          height: MediaQuery.of(context).size.height,\n          width: MediaQuery.of(context).size.width,\n          child: Column(\n            children: <Widget>[\n              Stack(\n                children: [\n                  //Main Background\n                  Column(children: <Widget>[\n                    //Top part\n                    Container(\n                      constraints: BoxConstraints(\n                        minHeight: 120,\n                      ),\n                      width: MediaQuery.of(context).size.width,\n                      height: 300,\n                      decoration: new BoxDecoration(\n                        gradient: LinearGradient(\n                          begin: Alignment.topCenter,\n                          end: Alignment.bottomCenter,\n                          colors: ticketGradient,\n                        ),\n                      ),\n                    ),\n                    // Bottom part - white\n                    Container(\n                      color: basicWhite,\n                    ),\n                  ]),\n                  //content above background\n                  BlocBuilder<FirstTabBloc, FirstTabState>(\n                    builder: (context, state) {\n                      if (state is Uninitialized) {\n                        return WalletWidget(\n                          credit: formatPrice(0),\n                          currency: '\xe2\x82\xac',\n                        );\n                      } else if (state is Loading) {\n                        return LoadingWidget();\n                      } else if (state is Loaded) {\n                        Wallet currWallet = state.profile.getWalletByClient(clientId);\n                        return WalletWidget(\n                          credit: formatPrice(currWallet.value),\n                          currency: formatCurrency(currWallet.currency),\n                        );\n                      } else if (state is Error) {\n                        return MessageDisplay(\n                          message: state.message,\n                        );\n                      }\n                    },\n                  ),\n                ],\n              ),\n            ],\n          ),\n        )));\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

Khe*_*rel 8

您需要使用另一种方式来获得该集团。

BlocProvider.of(context)Provider在引擎盖下使用。Provider是一个 flutter 包,它包装了InheritedWidget. InheritedWidget是一个 flutter widget,它通过上下文在 widget 树中传递数据。

所以你需要另一种方式。例如,您可以使用get_it库。这是 的 Dart 实现Service Locator

小部件外部的块的简单示例

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

final bloc = CounterBloc();

void main() {
  bloc.add(CounterEvent.increment);
  bloc.add(CounterEvent.increment);
  bloc.add(CounterEvent.increment);
  bloc.add(CounterEvent.increment);

  runApp(
    MyApp(),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        body: SafeArea(
          child: MyHomePage(),
        ),
      ),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (_) => bloc,
      child: CounterPage(),
    );
  }
}

class CounterPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Counter')),
      body: BlocBuilder<CounterBloc, int>(
        builder: (_, count) {
          return Center(
            child: Text('$count', style: Theme.of(context).textTheme.headline1),
          );
        },
      ),
      floatingActionButton: Column(
        crossAxisAlignment: CrossAxisAlignment.end,
        mainAxisAlignment: MainAxisAlignment.end,
        children: <Widget>[
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 5.0),
            child: FloatingActionButton(
              child: const Icon(Icons.add),
              onPressed: () =>
                  context.bloc<CounterBloc>().add(CounterEvent.increment),
            ),
          ),
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 5.0),
            child: FloatingActionButton(
              child: const Icon(Icons.remove),
              onPressed: () =>
                  context.bloc<CounterBloc>().add(CounterEvent.decrement),
            ),
          ),
        ],
      ),
    );
  }
}

enum CounterEvent { increment, decrement }

class CounterBloc extends Bloc<CounterEvent, int> {
  CounterBloc() : super(0);

  @override
  Stream<int> mapEventToState(CounterEvent event) async* {
    switch (event) {
      case CounterEvent.decrement:
        yield state - 1;
        break;
      case CounterEvent.increment:
        yield state + 1;
        break;
      default:
        addError(Exception('unsupported event'));
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

在 get_it 中注册您的块。之后您就可以在没有上下文的情况下获取并使用它。