如何直接将 bloc 添加到视图小部件

How to directly add bloc to the view widget

我有一个创建小部件的屏幕。

如何将 bloc 添加到我的小部件?

class UserView extends StatelessWidget {
   final AnimationController aController;
   final Animation animation;

   @override
   Widget build(BuildContext context) {
     // Add Scafold here?
      return AnimationBuilder(
         animation: aController;
         builder: (BuildContext context, Widget child) {
            ...
         },
      );
   }
}

集团

class UserBloc extends Bloc<UserEvent, UserState> {
    final UserRepo userRepo;
    UserBloc({@required this.userRepo}) : assert(userRepo != null);
}

如果我添加一个 Scaffold() 然后我得到一个错误说 "object was given an infinite size during layout".

我正在为 bloc 使用这个 https://bloclibrary.dev/#/

如有必要,我可以显示更多代码,我尽量保持简洁以便于阅读。请询问,我可以添加更多。


应用程序

void main() async {
  final UserRepo userRepo = UserRepo();
  BlocSupervisor.delegate = SimpleBlocDelegate();

  WidgetsFlutterBinding.ensureInitialized();
  await SystemChrome.setPreferredOrientations(<DeviceOrientation>[
    DeviceOrientation.portraitUp,
    DeviceOrientation.portraitDown
  ]).then((_) => runApp(MultiBlocProvider(
        providers: [
          BlocProvider<UserBloc>(
            create: (context) => UserBloc(userRepo: userRepo),
          )
        ],
        child: MyApp(),
      )));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    return MaterialApp(
      title: 'Test App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        textTheme: AppTheme.textTheme,
        platform: TargetPlatform.iOS,
      ),
      home: HomeScreen(),
    );
  }
}

主屏幕

class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen>
    with TickerProviderStateMixin {
  AnimationController animationController;

  Widget tabBody = Container(
    color: AppTheme.background,
  );

  @override
  void initState() {
    animationController = AnimationController(
        duration: const Duration(milliseconds: 800), vsync: this);
    tabBody = DashboardScreen(animationController: animationController);
    super.initState();
  }

  @override
  void dispose() {
    animationController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      color: AppTheme.background,
      child: Scaffold(
        backgroundColor: Colors.transparent,
        body: FutureBuilder<bool>(
          future: getData(),
          builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
            if (!snapshot.hasData) {
              return const SizedBox();
            } else {
              return Stack(
                children: <Widget>[
                  tabBody
                ],
              );
            }
          },
        ),
      ),
    );
  }
}

仪表板

class DashboardScreen extends StatefulWidget {
  const DashboardScreen({Key key, this.animationController}) : super(key: key);

  final AnimationController animationController;
  @override
  _DashboardScreenState createState() => _DashboardScreenState();
}

class _DashboardScreenState extends State<DashboardScreen>
    with TickerProviderStateMixin {
  Animation<double> topBarAnimation;

  List<Widget> listViews = <Widget>[];
  final ScrollController scrollController = ScrollController();
  double topBarOpacity = 0.0;

  @override
  void initState() {
    listViews.add(
      UserView(
        animation: Tween<double>(begin: 0.0, end: 1.0).animate(CurvedAnimation(
            parent: widget.animationController,
            curve:
                Interval((1 / count) * 1, 1.0, curve: Curves.fastOutSlowIn))),
        animationController: widget.animationController,
      ),
    );
    super.initState();
  }

}

我假设 UserBloc 必须对整个应用程序可用,如果不是,只需将下面的提供程序的级别更改为刚好在它应该涵盖的小部件之上:

在这里,您提供位于 MaterialApp 小部件之上的 bloc,以便稍后在该小部件的任何后代中使用它:(在 App 文件中)

 return BlocProvider(
    create: (_)=>UserBloc(userRepo:UserRep()),
    child: MaterialApp(
      title: 'Test App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        textTheme: AppTheme.textTheme,
        platform: TargetPlatform.iOS,
      ),
      home: HomeScreen(),
    ),
  );

现在,如果您想使用您的 bloc 发出事件并监听 MaterialApp 的任何后代小部件中的状态,您只需用 BlocListenerBlocConsumerBlocBuilder(看他们的区别here):

我假设您想在 HomeScreen 中这样做:

class _HomeScreenState extends State<HomeScreen>
    with TickerProviderStateMixin {
  AnimationController animationController;

  Widget tabBody = Container(
    color: AppTheme.background,
  );

  @override
  void initState() {
    animationController = AnimationController(
        duration: const Duration(milliseconds: 800), vsync: this);
    tabBody = DashboardScreen(animationController: animationController);
    super.initState();
  }

  @override
  void dispose() {
    animationController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      color: AppTheme.background,
      child: Scaffold(
        backgroundColor: Colors.transparent,
        body: FutureBuilder<bool>(
          future: getData(),
          builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
            if (!snapshot.hasData) {
              return const SizedBox();
            } else {
              return Stack(
                children: <Widget>[
                  //tabBody
                  //Don't save widgets as fields, just create them on the fly
                  BlocBuilder<UserBloc,UserState>(
                    builder: (ctx,state){
                      //return widget that depends on state and which should rebuild when state changes
                      return DashboardScreen(animationController: animationController);
                    },
                  )
                ],
              );
            }
          },
        ),
      ),
    );
  }
}

就是这样。

查看上面的 link 以获得更多文档。