【Flutter】Bloc管理模式(入门)

状态管理:bloc、状态管理
在这里插入图片描述
bloc是一种mvvm基于事件状态驱动的

1、代码

入门Bloc,案例代码

2、视频资料

视频资料
视频尽量选择新一些的,bloc版本迭代到8.0.1了,里面的一些方法也有些改变,早版本的教学视频不合适

bloc插件,管理项目

3、安装插件bloc

用于快速创建bloc
在这里插入图片描述

4、导入依赖

dependencies:
  flutter:
    sdk: flutter


  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.2
  bloc: ^8.0.3
  flutter_bloc: ^8.0.1
  equatable: ^2.0.3

5、创建bloc

在这里插入图片描述

6、搭建项目案例(Pizza)

实现的功能及界面
在这里插入图片描述
这里有四个按钮,当点击第一个,生成一个pizza(种类A),第二个按钮,删除一个pizza(种类A);后面两个功能类似,但是生成的pizza种类不同。

在这里插入图片描述

6.1、Pizza对象

import 'package:equatable/equatable.dart';
import 'package:flutter/cupertino.dart';

class Pizza extends Equatable {
  final String id;
  final String name;
  final Image image;

  const Pizza(this.id, this.name, this.image);

  @override
  List<Object?> get props => [id, name, image];

  static List<Pizza> pizzas = [
    Pizza('0', 'Pizza0', Image.asset("images/pizza0.jpg")),
    Pizza('1', 'Pizza1', Image.asset("images/pizza1.jpg")),
  ];
}

这里的Equatable是用于比较对象的,Equatable可以为你覆写==和hashCode

只需要写这一句

  // Equatable
  @override
  List<Object?> get props => [id, name, image];

6.2、新建bloc

在这里插入图片描述
创建之后,先配置pizza_state,这个表示在初始化、添加、删除这几个操作中,会有几个状态。

在一开始会有初始化一个抽象类,继承Equatable

part of 'pizza_bloc.dart';

abstract class PizzaState extends Equatable {
  const PizzaState();

  @override
  List<Object> get props => [];
}

抽象类不能实例化(当然有factory可以),在这种场景下,有初始化状态,有加载pizza状态,初始化状态不需要添加什么内容,而加载状态需要构造器,用List保存现有的Pizza。

接着配置pizza_event,同样分析得出有三个事件,分别是初始化Pizza,添加Pizza,删除Pizza

part of 'pizza_bloc.dart';

abstract class PizzaEvent extends Equatable {
  const PizzaEvent();

  @override
  List<Object> get props => [];
}

class LoadPizzaCounter extends PizzaEvent {}

class AddPizza extends PizzaEvent {
  final Pizza pizza;

  AddPizza({required this.pizza});

  @override
  List<Object> get props => [pizza];
}

class RemovePizza extends PizzaEvent {
  final Pizza pizza;

  RemovePizza({required this.pizza});

  @override
  List<Object> get props => [pizza];
}

最后是bloc的配置

import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';

import '../models/pizza_model.dart';

part 'pizza_event.dart';

part 'pizza_state.dart';

class PizzaBloc extends Bloc<PizzaEvent, PizzaState> {
  /**
   * super(PizzaInitial())是将PizzaInitial()返回的结果传递给父类Bloc的构造器
   */
  PizzaBloc() : super(PizzaInitial()) {
    /**
     * void on<E extends Event>(
        EventHandler<E, State> handler, {
        EventTransformer<E>? transformer,
        })
     */
    on<LoadPizzaCounter>(
      (event, emit) async {
        //等待一秒
        await Future<void>.delayed(Duration(seconds: 1));
        //生成加载Pizza的状态
        emit(PizzaLoaded(pizzas: <Pizza>[]));
      },
    );
    on<AddPizza>(
      (event, emit) {
        if (state is PizzaLoaded) {
          final state = this.state as PizzaLoaded;
          emit(PizzaLoaded(
            pizzas: List.from(state.pizzas)..add(event.pizza),
          ));
        }
      },
    );

    /**
     * 如果当前状态是PizzaLoaded的状态,
     * 那么将emit引发一个新的状态PizzaLoaded,
     * 里面的内容将发生变化,即移除一个pizza
     */
    on<RemovePizza>(
      (event, emit) {
        if (state is PizzaLoaded) {
          final state = this.state as PizzaLoaded;
          emit(PizzaLoaded(
            pizzas: List.from(state.pizzas)..remove(event.pizza),
          ));
        }
      },
    );
  }
}

这里的bloc配置是将事件和状态关联起来,处理不同事件的逻辑操作
最后在main.dart写界面,并使用bloc

6.3、 MultiBlocProvider

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MultiBlocProvider(
        providers: [
          BlocProvider(
            create: (context) => PizzaBloc()..add(LoadPizzaCounter()),
          ),
        ],
        child: MaterialApp(
          debugShowCheckedModeBanner: false,
          title: 'The Pizza Bloc',
          home: HomeScreen(),
        ));
  }
}

这里的MultiBlocProvider的写法很像MultiProvider的注册方式,比如下面代码

main() {
  runApp(MultiProvider(
    providers: [
      ChangeNotifierProvider(create: (ctx) => HYBaseDataViewModel()),
      ChangeNotifierProxyProvider<HYBaseDataViewModel, HYVideoViewModel>(
          create: (cts) => HYVideoViewModel(),
          update: (ctx, baseDataVM, videoVM) {
            videoVM?.updateBaseData(baseDataVM);
            return videoVM as HYVideoViewModel;
          })
    ],
    child: MyApp(),
  ));
}

那么可以理解为初始化bloc,注册BlocProvider,接着创建BlocBuilder,

body: Center(
        //2、创建BlocBuilder
        child: BlocBuilder<PizzaBloc, PizzaState>(
          builder: (context, state) {
            //如果状态是初始化状态,就返回圆形加载的进度条
            if (state is PizzaInitial) {
              return CircularProgressIndicator(
                color: Colors.orange,
              );
            }
            //如果状态是加载完成的
            if (state is PizzaLoaded) {
              return Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Text(
                    '${state.pizzas.length}',  //pizza的数量
                    style: TextStyle(fontSize: 60, fontWeight: FontWeight.bold),
                  ),
                  SizedBox(
                    height: 20,
                  ),
                  SizedBox(
                    height: MediaQuery.of(context).size.height / 1.5,
                    width: MediaQuery.of(context).size.width,
                    child: Stack(
                      alignment: Alignment.center,
                      clipBehavior: Clip.none, //不裁剪
                      children: buildContent(state),
                    ),
                  )
                ],
              );
            } else {
              return const Text('Something went wrong!');
            }
          },
        ),
      ),

然后在FloatActionButton中编写点击事件

floatingActionButton: Column(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [
          FloatingActionButton(
            onPressed: () {
              /**
               *   T read<T>() {
                  return Provider.of<T>(this, listen: false);
                  }
                  查询Bloc,,并调用添加Pizza事件来添加一个Pizza
               */
              context.read<PizzaBloc>().add(AddPizza(pizza: Pizza.pizzas[0]));
            },
            child: Icon(Icons.local_pizza_outlined),
            backgroundColor: Colors.orange[800],
          ),
          SizedBox(
            height: 10,
          ),
          FloatingActionButton(
            onPressed: () {
              context.read<PizzaBloc>().add(RemovePizza(pizza: Pizza.pizzas[0]));
            },
            child: Icon(Icons.remove),
            backgroundColor: Colors.orange[800],
          ),
          SizedBox(
            height: 10,
          ),
          FloatingActionButton(
            onPressed: () {
              context.read<PizzaBloc>().add(AddPizza(pizza: Pizza.pizzas[1]));
            },
            child: Icon(Icons.local_pizza_rounded),
            backgroundColor: Colors.orange[800],
          ),
          SizedBox(
            height: 10,
          ),
          FloatingActionButton(
            onPressed: () {
              context.read<PizzaBloc>().add(RemovePizza(pizza: Pizza.pizzas[1]));
            },
            child: Icon(Icons.remove),
            backgroundColor: Colors.orange[800],
          ),
          SizedBox(
            height: 10,
          ),
        ],
      ),
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sheng_er_sheng

打赏是什么?好吃么

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值