美文网首页
Flutter 状态管理 Bloc 使用

Flutter 状态管理 Bloc 使用

作者: _凌浩雨 | 来源:发表于2019-12-10 18:55 被阅读0次

    Bloc官网

    Bloc Github

    vs code Bloc插件

    Flutter Bloc Pub地址
    • 依赖
    dependencies:
      bloc: ^2.0.0
      flutter_bloc: ^2.1.1
    
    • 下载包
    flutter packages get
    
    • 导入
    import 'package:bloc/bloc.dart';
    import 'package:flutter_bloc/flutter_bloc.dart';
    

    Bloc 组件

    BlocBuilder

    BlocBuilder是Flutter窗口小部件,需要Bloc和builder函数。BlocBuilder处理构建小部件以响应新状态。如果省略了bloc参数,BlocBuilder将使用BlocProvider和当前函数自动执行查找BuildContext。如果你想再构造器函数被调用时,自己控制页面的刷新,那么你可以提供一个更细粒度的condition来空中BlocBuilder。在condition中有之前的状态和当前的状态两个参数,方法返回一个布尔值。如果返回true, builder将被调用,且widget会重新绘制; 返回false, builder则不会重新绘制。

    BlocBuilder<BlocA, BlocAState>(
        bloc: blocA, // 提供一个本地Bloc实例
        condition: (previousState, state) {
        // 返回true/false决定是否重建组件状态
        },
        builder: (context, state) {
          // 返回组件
        }
      )
    
    BlocProvider

    BlocProvider 是 通过BlocProvider.of<T>(context)为其子元素提供Bloc 的Flutter widget。它使用依赖注入便于单例Bloc提供给子树的多个小部件。在大多数情况下,BlocProvider应使用它来创建新的属性bloc,并将其提供给其余的子树。在这种情况下,由于BlocProvider负责创建Bloc,它将自动处理关闭块。

    BlocProvider(
      create: (BuildContext context) => BlocA(),
      child: ChildA(),
    );
    

    在一些情况下,BlocProvider可用于向子元素提供现有的Bloc。在这种情况下,BlocProvider由于不会创建新的Bloc,因此不会自动关闭Bloc。

    BlocProvider.value(
      value: BlocProvider.of<BlocA>(context),
      child: ScreenA(),
    );
    

    在ChildA或ScreenA中使用BlocProvider.of<BlocA>(context)获取BlocA对象

    MultiBlocProvider

    MultiBlocProvider是可将多个BlocProvider小部件合并为一个BlocProvider的Flutter widget。 MultiBlocProvider提高了可读性,消除了嵌套多个元素的需求BlocProvider。

    MultiBlocProvider(
      providers: [
        BlocProvider<BlocA>(
          create: (BuildContext context) => BlocA(),
        ),
        BlocProvider<BlocB>(
          create: (BuildContext context) => BlocB(),
        ),
        BlocProvider<BlocC>(
          create: (BuildContext context) => BlocC(),
        ),
      ],
      child: ChildA(),
    )
    
    BlocListener

    BlocListener 包含一个 BlocWidgetListener 和可选的Bloc, 并且listener每在状态改变时被调用。

      BlocListener<BlocA, BlocAState>(
        bloc: blocA,
        listener: (context, state) {
          // 基于BlocA的状态做一些处理
        },
        child: Container()
      )
    

    如果希望更加细粒度的控制listener被调用, 那么可以实现condition来控制, 它将会返回一个布尔值, 如果返回true, listener将会被调用; 如果返回false, listener将不会被调用.

    BlocListener<BlocA, BlocAState>(
      condition: (previousState, state) {
        // 返回 true/false 决定是否调用监听
      },
      listener: (context, state) {
        // 基于BlocA的状态做一些处理
      }
      child: Container(),
    )
    
    MultiBlocListener

    MultiBlocListener 可将多个BlocListener小部件合并为一个BlocListener。 MultiBlocListener提高了可读性,消除了嵌套多个元素的需求BlocListeners。

    MultiBlocListener(
      listeners: [
        BlocListener<BlocA, BlocAState>(
          listener: (context, state) {},
        ),
        BlocListener<BlocB, BlocBState>(
          listener: (context, state) {},
        ),
        BlocListener<BlocC, BlocCState>(
          listener: (context, state) {},
        ),
      ],
      child: ChildA(),
    )
    
    RepositoryProvider

    RepositoryProvider 通过RepositoryProvider.of<T>(context)为其子项提供存储库。它使用依赖注入将存储库的单个实例提供给子树中的多个小部件。BlocProvider应该用于提供Bloc,而RepositoryProvider只能用于存储库。

    RepositoryProvider(
      builder: (context) => RepositoryA(),
      child: ChildA(),
    );
    

    在ChildA中使用RepositoryProvider.of<RepositoryA>(context) 获取RepositoryA.

    MultiRepositoryProvider

    MultiRepositoryProvider 将多个RepositoryProvider小部件合并为一个RepositoryProvider。 MultiRepositoryProvider提高了可读性,消除了嵌套多个元素的需求RepositoryProvider。

    MultiRepositoryProvider(
      providers: [
        RepositoryProvider<RepositoryA>(
          builder: (context) => RepositoryA(),
        ),
        RepositoryProvider<RepositoryB>(
          builder: (context) => RepositoryB(),
        ),
        RepositoryProvider<RepositoryC>(
          builder: (context) => RepositoryC(),
        ),
      ],
      child: ChildA(),
    )
    

    使用

    • 事件枚举
    /// 计数事件
    enum CounterEvent { 
      increment, 
      decrement 
    }
    
    • 计数Bloc
    import 'package:bloc/bloc.dart';
    import 'event.dart';
    
    /// Bloc 计数
    class CounterBloc extends Bloc<CounterEvent, int> {
      @override
      int get initialState => 0;
    
      @override
      Stream<int> mapEventToState(event) async* {
        switch (event) {
          case CounterEvent.increment:
            yield state + 1;
            break;
          case CounterEvent.decrement:
            yield state - 1;
            break;
          default:
            throw Exception("未知Event");
        }
      }
    }
    
    • 测试页面
    import 'package:flutter/material.dart';
    import 'package:flutter_bloc/flutter_bloc.dart';
    import 'package:state_manage/counter/counter_bloc.dart';
    import 'package:state_manage/counter/event.dart';
    
    /// 测试页面
    class CounterTest extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
            title: 'Counter',
            theme: ThemeData(
              primarySwatch: Colors.blue,
            ),
            home: BlocProvider(
              // 使用 BlocProvider
              create: (context) => CounterBloc(),
              child: MyHomePage(title: 'Counter'),
            ));
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key, this.title}) : super(key: key);
    
      final String title;
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      @override
      Widget build(BuildContext context) {
        // 获取Bloc
        final CounterBloc bloc = BlocProvider.of<CounterBloc>(context);
    
        return Scaffold(
            appBar: AppBar(
              title: Text(widget.title),
            ),
            body: BlocBuilder<CounterBloc, int>(
              builder: (context, count) {
                return Center(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      Text(
                        'You have pushed the button this many times:',
                      ),
                      Text(
                        '$count',
                        style: Theme.of(context).textTheme.display1,
                      ),
                    ],
                  ),
                );
              },
            ),
            floatingActionButton: Column(
              crossAxisAlignment: CrossAxisAlignment.end,
              mainAxisAlignment: MainAxisAlignment.end,
              children: <Widget>[
                // 加
                Padding(
                  padding: EdgeInsets.symmetric(vertical: 5.0),
                  child: FloatingActionButton(
                    onPressed: () {
                      bloc.add(CounterEvent.increment);
                    },
                    tooltip: 'Increment',
                    child: Icon(Icons.add),
                  ),
                ),
                // 减
                Padding(padding: EdgeInsets.symmetric(vertical: 5.0),
                  child: FloatingActionButton(
                    onPressed: () {
                      bloc.add(CounterEvent.decrement);
                    },
                    tooltip: 'Decrement',
                    child: Icon(Icons.add),
                  ),)
              ],
            ));
      }
    }
    
    • 主函数
    // 状态管理之计数器
    void main() => runApp(CounterTest());
    
    效果图.gif

    相关文章

      网友评论

          本文标题:Flutter 状态管理 Bloc 使用

          本文链接:https://www.haomeiwen.com/subject/ychhgctx.html