Flutter状态管理与工具集插件flutter_bloc_toolbox的使用

发布于 1周前 作者 yibo5220 来自 Flutter

Flutter状态管理与工具集插件flutter_bloc_toolbox的使用

codecov

flutter_bloc_toolbox 是基于优秀的 flutter_bloc package 构建的,包含了一些有用的blocs/cubits。以下是其主要特性和示例代码。

Features

BoolCubit

这是一个简单的布尔cubit,用于管理布尔状态,适用于复选框或其他选项/退出选择。

/// 创建时带有初始值
final BoolCubit myBoolCubit = BoolCubit(initialValue: true);
/// 用于发出新的布尔状态
myBoolCubit.changeValue(false);
/// 发出 !value 状态
myBoolCubit.toggleValue();

FetchAndRefresh

这个cubit用于管理一个值的获取和刷新。可以与 FetchAndRefreshStateValidWrapper 一起使用以实现自动加载和错误显示。

typedef FetchAndRefreshStateTest = FetchAndRefreshState<String, PersonEntity>;
typedef FetchAndRefreshCubitTest = FetchAndRefreshCubit<FetchAndRefreshStateTest, String, PersonEntity>;

getObjectTest({required String idToGet}) => personRepository.getObject(idToGet);

FetchAndRefreshCubit fetchAndRefreshCubit = FetchAndRefreshCubitTest(
    fetchObject: getObjectTest,
);

/// 获取值
fetchAndRefreshCubit.fetch(idToFetch: 'ID');
/// 刷新值
fetchAndRefreshCubit.refresh();
/// 重置cubit
fetchAndRefreshCubit.reset();

...

FetchAndRefreshStateValidWrapper<
    FetchAndRefreshCubitTest,
    FetchAndRefreshStateTest,
    FetchAndRefreshWithValueState<String, PersonEntity>,
    String,
    PersonEntity>(
        cubit: fetchAndRefreshCubit,
        idToCheck: 'ID',
        validRender: (BuildContext context, FetchAndRefreshWithValueState<String, PersonEntity> localState) {
            return ...;
        },
    );

FetchAndRefreshPaginated

这个cubit用于管理分页值的获取和刷新,允许加载更多项。

typedef FetchAndRefreshPaginatedStateTest = FetchAndRefreshPaginatedState<String, PaginationEntity<PersonEntity>>;
typedef FetchAndRefreshPaginatedCubitTest = FetchAndRefreshPaginatedCubit<FetchAndRefreshPaginatedStateTest, String, PaginationEntity<PersonEntity>>;

getObjectTest({
    required String idToGet,
    bool loadMore = false,
    bool getAll = false,
    FetchAndRefreshPaginatedState? currentState,
  }) async {
    PaginationEntity<PersonEntity>? personsPaginationEntity;
    if (loadMore && currentState is FetchAndRefreshPaginatedWithValueState) {
      personsPaginationEntity = currentState.object;
    }
    PaginationEntity<PersonEntity>? persons = personsPaginationEntity != null
        ? await personRepository.getPaginationObject(
            idToGet,
            onlyOnePage: !getAll,
            currentPaginationEntity: personsPaginationEntity,
          )
        : await personRepository.getPaginationObject(
            idToGet,
            onlyOnePage: !getAll,
          );

    return persons;
  }

FetchAndRefreshPaginatedCubit fetchAndRefreshPaginatedCubit = FetchAndRefreshPaginatedCubitTest(
    fetchObject: getObjectTest,
);

/// 获取值
fetchAndRefreshPaginatedCubit.fetch(idToFetch: 'ID');
/// 加载更多
fetchAndRefreshPaginatedCubit.fetch(idToFetch: 'ID', loadMore: true);

FilterEnumCubit

这个cubit用于管理过滤器列表的选择情况。

typedef FilterEnumTest = FilterEnumEntity<MockEnum>;
typedef FilterState = FilterEnumState<MockEnum, FilterEnumTest>;
typedef FilterCubit = FilterEnumCubit<MockEnum, FilterEnumTest, FilterState>;

FilterCubit filterCubit = FilterCubit(
    FilterEnumInitialState<MockEnum, FilterEnumTest>(
      MockEnum.values,
      (MockEnum s, bool b) => FilterEnumTest(s, b),
    ),
    enumValues: MockEnum.values,
    enumBuilder: (MockEnum s, bool b) => FilterEnumEntity(s, b),
    selectedByDefault: selectedByDefault,
);

/// 更改过滤器选择
filterCubit.toggleEnum(MockEnum.mock1);
filterCubit.toggleEnum(MockEnum.mock2);
filterCubit.toggleEnum(MockEnum.mock1);
/// 重置为默认值
filterCubit.setDefaultFilters();
/// 从列表设置
filterCubit.setFiltersFromList(const [FilterEnumEntity(MockEnum.mock3, true)]);
filterCubit.setFilterFromPicked(const [MockEnum.mock3, MockEnum.mock1, MockEnum.mock2]);

SearchTextCubit

这个cubit用于管理文本搜索。

SearchTextCubit searchTextCubit = SearchTextCubit();
/// 更改文本
searchTextCubit.setText(textToSearch);
/// 清空文本
searchTextCubit.eraseText();

SortEnumCubit

这个cubit用于管理排序。

List<SortEnumTest> availableSorts = const [
  SortEnumTest(
    ascendant: true,
    sortEnum: MockEnum.mock1,
  ),
  SortEnumTest(
    ascendant: false,
    sortEnum: MockEnum.mock1,
  ),
  SortEnumTest(
    ascendant: true,
    sortEnum: MockEnum.mock2,
  ),
  SortEnumTest(
    ascendant: false,
    sortEnum: MockEnum.mock3,
  ),
  SortEnumTest(
    ascendant: true,
    sortEnum: MockEnum.mock4,
  ),
  SortEnumTest(
    ascendant: false,
    sortEnum: MockEnum.mock4,
  ),
];
int defaultIndex = 2;

SortCubit sortCubit = SortCubit(
    SortEnumInitialState(
      sortEntity: availableSorts.elementAt(defaultIndex),
    ),
    availableSorts: availableSorts,
    defaultIndex: defaultIndex,
);
/// 更改排序
sortCubit.changeSort(availableSorts.first);

示例Demo

下面是一个完整的Flutter应用示例,展示了如何使用PersonsFetchAndRefreshPaginatedCubit来获取和显示分页数据,并提供加载更多按钮。

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:example/data/person_repository.dart';
import 'package:example/logic/fetch_and_refresh_paginated/persons_fetch_and_refresh_paginated_cubit.dart';
import 'package:example/presentation/persons_fetch_and_refresh_state_valid_wrapper.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final String idToFetch = 'idToFetch';
  final PersonsFetchAndRefreshPaginatedCubit paginatedCubit = PersonsFetchAndRefreshPaginatedCubit(
    PersonRepository(),
  );

  @override
  void initState() {
    super.initState();
    paginatedCubit.fetch(idToFetch: idToFetch);
  }

  @override
  void dispose() {
    paginatedCubit.close();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text('Example'),
      ),
      body: Center(
        child: CustomScrollView(
          slivers: [
            BlocBuilder<PersonsFetchAndRefreshPaginatedCubit, FetchAndRefreshPaginatedState<String, PaginationEntity<PersonEntity>>>(
              bloc: paginatedCubit,
              builder: (context, state) {
                if (state is FetchAndRefreshPaginatedWithValueState) {
                  return SliverList.builder(
                    itemCount: state.persons.data.length,
                    itemBuilder: (BuildContext context, int i) => Container(
                      margin: const EdgeInsets.all(20),
                      child: Text(
                          '${state.persons.data.elementAt(i).firstName} ${state.persons.data.elementAt(i).lastName}'),
                    ),
                  );
                } else {
                  return const SliverToBoxAdapter(child: Center(child: CircularProgressIndicator()));
                }
              },
            ),
            BlocBuilder<PersonsFetchAndRefreshPaginatedCubit, FetchAndRefreshPaginatedState<String, PaginationEntity<PersonEntity>>>(
              bloc: paginatedCubit,
              builder: (context, state) {
                return SliverToBoxAdapter(
                  child: TextButton(
                    onPressed: () => paginatedCubit.fetch(
                      idToFetch: idToFetch,
                      loadMore: true,
                    ),
                    child: const Text('More'),
                  ),
                );
              },
            ),
          ],
        ),
      ),
    );
  }
}

在这个示例中,我们创建了一个简单的Flutter应用程序,它使用 PersonsFetchAndRefreshPaginatedCubit 来获取和显示分页数据,并提供了一个“更多”按钮来加载更多数据。通过这种方式,您可以更好地理解和使用 flutter_bloc_toolbox 插件中的功能。


更多关于Flutter状态管理与工具集插件flutter_bloc_toolbox的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter状态管理与工具集插件flutter_bloc_toolbox的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,关于Flutter中的状态管理与工具集插件flutter_bloc_toolbox的使用,以下是一个具体的代码案例来展示如何结合Flutter的Bloc状态管理与flutter_bloc_toolbox插件进行开发。

环境设置

首先,确保你的Flutter项目已经配置好flutter_blocflutter_bloc_toolbox。在你的pubspec.yaml文件中添加以下依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_bloc: ^8.0.0 # 请检查最新版本
  flutter_bloc_toolbox: ^0.3.0 # 请检查最新版本

然后运行flutter pub get来安装依赖。

创建一个简单的计数器应用

1. 定义事件、状态和Bloc

首先,我们定义一个简单的事件(IncrementEvent)和状态(CounterState),然后创建一个Bloc来处理这些事件并更新状态。

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

abstract class CounterEvent extends Equatable {
  const CounterEvent();
}

class IncrementEvent extends CounterEvent {
  @override
  List<Object> get props => [];
}
// counter_state.dart
import 'package:equatable/equatable.dart';

class CounterState extends Equatable {
  final int count;

  const CounterState({required this.count});

  @override
  List<Object> get props => [count];
}
// counter_bloc.dart
import 'package:bloc/bloc.dart';
import 'package:flutter_bloc_toolbox/flutter_bloc_toolbox.dart';
import 'counter_event.dart';
import 'counter_state.dart';

class CounterBloc extends Bloc<CounterEvent, CounterState> with BlocLogger {
  CounterBloc() : super(CounterState(count: 0)) {
    on<IncrementEvent>((event, emit) {
      emit(state.copyWith(count: state.count + 1));
    });
  }
}

2. 使用flutter_bloc_toolbox中的BlocProvider

main.dart文件中,使用flutter_bloc_toolbox提供的BlocProvider来提供我们的CounterBloc

// main.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_bloc_toolbox/flutter_bloc_toolbox.dart';
import 'counter_bloc.dart';
import 'counter_page.dart';

void main() {
  runApp(
    BlocProvider<CounterBloc>(
      create: (_) => CounterBloc(),
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: CounterPage(),
    );
  }
}

3. 创建UI组件

counter_page.dart文件中,创建一个简单的界面来显示计数器的值,并提供一个按钮来增加计数。

// counter_page.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'counter_bloc.dart';
import 'counter_event.dart';

class CounterPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Counter App')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '${context.bloc<CounterBloc>().state.count}',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          context.read<CounterBloc>().add(IncrementEvent());
        },
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

运行应用

现在,你可以运行你的Flutter应用,应该能看到一个简单的计数器应用,点击浮动按钮会增加计数器的值。

这个示例展示了如何使用flutter_bloc进行状态管理,并结合flutter_bloc_toolbox提供的BlocProvider来提供Bloc实例。flutter_bloc_toolbox还包括其他有用的功能,比如日志记录(在这里我们通过with BlocLogger使用了它),你可以根据需要进一步探索和使用这些功能。

回到顶部