Flutter复用逻辑块插件reusable_bloc_base的使用

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

Flutter复用逻辑块插件reusable_bloc_base的使用

reusable_bloc_base

轻量级扩展库,用于简化 flutter_bloc 的使用。

特性

覆盖了大多数常见的 Flutter BLoC 工作流程,避免了样板代码。

开始使用

安装该包:

flutter pub add reusable_bloc_base

使用方法

示例状态类

首先定义一个状态类 HelloWorldState,继承自 BaseState

// Your state class
final class HelloWorldState extends BaseState<HelloWorldLoading> {
  const HelloWorldState({
    super.failure,
    super.isLoading,
    super.pendingActions,
    super.success,
  });

  [@override](/user/override)
  List<Object> get props => [
        ...super.props,
      ];

  factory HelloWorldState.initial() {
    return const HelloWorldState();
  }

  [@override](/user/override)
  HelloWorldState copyWith({
    AnySuccess? success,
    AnyFailure? failure,
    bool? isLoading,
    Set<HelloWorldLoading>? pendingActions,
  }) {
    return HelloWorldState(
      failure: failure ?? this.failure,
      isLoading: isLoading ?? this.isLoading,
      pendingActions: pendingActions ?? this.pendingActions,
      success: success ?? this.success,
    );
  }

  [@override](/user/override)
  String toString() {
    return '''
      HelloWorldState {
        failure: $failure,
        isLoading: $isLoading,
        pendingActions: $pendingActions,
        success: $success,
      }
      ''';
  }
}

示例BLoC类

接下来定义一个 BLoC 类 HelloWorldBloc,继承自 BaseBloc

// Your bloc class
class HelloWorldBloc extends BaseBloc<HelloWorldLoading, HelloWorldEvent, HelloWorldState> {
  HelloWorldBloc() { 
    // Your initialization code
  }

  FutureOr<void> _onHelloWorldEvent(
    HelloWorldEvent event,
    Emitter<HelloWorldState> emit,
  ) async {
    emit(state.beforeLoading()); // 设置 isLoading 为 true
    try {
      // Your business logic here ... (synchronous or asynchronous)
      emit(state.successState<HelloWorldState>()); // 设置 isLoading 为 false 并设置成功状态
    } catch (e, stack) {
      addError(e, stack); // 设置失败状态,错误详情会反映在 state.failure 中
    }
  }
} 

示例代码

以下是一个完整的示例代码,展示了如何使用 reusable_bloc_base

import 'package:example/bloc/counter_bloc.dart';
import 'package:example/widgets/loading_indicator.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:loader_overlay/loader_overlay.dart';
import 'package:reusable_bloc_base/reusable_bloc_base.dart';
import 'package:toastification/toastification.dart';

void main() {
  // 初始化加载器
  BlocStateReactor.showLoading = (context) => context.loaderOverlay.show();
  BlocStateReactor.hideLoading = (context) => context.loaderOverlay.hide();
  
  // 成功状态回调
  BlocStateReactor.onSuccessState = (context, success) {
    toastification.show(
      context: context,
      title: Text(success.translate()),
      autoCloseDuration: const Duration(seconds: 3),
      style: ToastificationStyle.minimal,
      type: ToastificationType.success,
    );
  };

  // 失败状态回调
  BlocStateReactor.onErrorState = (context, failure) {
    toastification.show(
      context: context,
      title: Text(failure.translate()),
      autoCloseDuration: const Duration(seconds: 3),
      style: ToastificationStyle.minimal,
      type: ToastificationType.error,
    );
  };

  runApp(const MyApp());
}

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return GlobalLoaderOverlay(
      overlayWidgetBuilder: (_) {
        return const LoadingIndicator();
      },
      overlayColor: Colors.black.withOpacity(0.4),
      overlayHeight: MediaQuery.of(context).size.height,
      overlayWidth: MediaQuery.of(context).size.width,
      child: ToastificationWrapper(
        child: MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
            useMaterial3: true,
          ),
          home: BlocProvider(
            create: (context) => CounterBloc(),
            child: const MyHomePage(title: 'Flutter Demo Home Page'),
          ),
        ),
      ),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return BaseStateListener<void, CounterBloc, CounterState>(
      child: Scaffold(
        appBar: AppBar(
          backgroundColor: Theme.of(context).colorScheme.inversePrimary,
          title: Text(title),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              const Text(
                'You have pushed the button this many times:',
              ),
              BlocBuilder<CounterBloc, CounterState>(
                builder: (context, state) {
                  return Text(
                    state.counter.toString(),
                    style: Theme.of(context).textTheme.headlineMedium,
                  );
                },
              ),
              ElevatedButton(
                onPressed: () {
                  context.read<CounterBloc>().add(const IncrementCounterEvent());
                },
                child: const Text('Increment'),
              ),
              const SizedBox(
                height: 20,
              ),
              ElevatedButton(
                onPressed: () {
                  context.read<CounterBloc>().add(const DecrementCounterEvent());
                },
                child: const Text('Decrement'),
              ),
              const SizedBox(
                height: 20,
              ),
              ElevatedButton(
                onPressed: () {
                  context.read<CounterBloc>().add(const ShowFailureEvent());
                },
                child: const Text('Trigger failure'),
              ),
              const SizedBox(
                height: 20,
              ),
              ElevatedButton(
                onPressed: () {
                  context.read<CounterBloc>().add(const PrintBlocHistoryEvent());
                },
                child: const Text('Print last 10 bloc state'),
              ),
              BlocBuilder<CounterBloc, CounterState>(
                builder: (context, state) {
                  return SizedBox(
                    height: 500,
                    child: ListView(
                      children: [
                        Text(
                          state.blocHistory,
                          style: Theme.of(context).textTheme.bodyMedium,
                        ),
                      ],
                    ),
                  );
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}

更多关于Flutter复用逻辑块插件reusable_bloc_base的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter复用逻辑块插件reusable_bloc_base的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,我可以为你提供一个关于如何在Flutter中使用reusable_bloc_base插件的代码案例。这个插件旨在帮助开发者在Flutter应用中复用逻辑块(Bloc),从而提高代码的可维护性和复用性。

首先,确保你已经在pubspec.yaml文件中添加了reusable_bloc_base依赖:

dependencies:
  flutter:
    sdk: flutter
  reusable_bloc_base: ^最新版本号  # 替换为实际可用的最新版本号

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

以下是一个简单的例子,展示了如何使用reusable_bloc_base来创建一个可复用的Bloc,并在Flutter应用中使用它。

1. 创建一个可复用的Bloc

首先,我们定义一个Bloc来处理计数器的逻辑。这个Bloc将包含增加和减少计数的功能。

// counter_bloc.dart
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:reusable_bloc_base/reusable_bloc_base.dart';

part 'counter_event.dart';
part 'counter_state.dart';

class CounterBloc extends ReusableBloc<CounterEvent, CounterState> {
  CounterBloc() : super(CounterState.initial()) {
    on<IncrementEvent>((event, emit) => emit(state!.copy(count: state!.count + 1)));
    on<DecrementEvent>((event, emit) => emit(state!.copy(count: state!.count - 1)));
  }

  @override
  Stream<CounterState> mapEventToState(CounterEvent event) async* {
    // 这个方法会被重写,但在这个例子中,我们已经在构造函数中处理了事件
    yield* super.mapEventToState(event);
  }
}

2. 定义事件和状态

接下来,我们定义事件和状态类。

// counter_event.dart
part of 'counter_bloc.dart';

abstract class CounterEvent {}

class IncrementEvent extends CounterEvent {}

class DecrementEvent extends CounterEvent {}
// counter_state.dart
part of 'counter_bloc.dart';

import 'package:equatable/equatable.dart';

class CounterState extends Equatable {
  final int count;

  const CounterState(this.count);

  static const initial = CounterState(0);

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

  CounterState copyWith(int? count) {
    return CounterState(count ?? this.count);
  }
}

3. 在UI中使用Bloc

最后,我们在Flutter的UI组件中使用这个Bloc。

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Counter App')),
        body: Center(
          child: BlocProvider(
            create: (context) => CounterBloc(),
            child: CounterWidget(),
          ),
        ),
        floatingActionButton: Column(
          mainAxisAlignment: MainAxisAlignment.end,
          children: [
            FloatingActionButton(
              onPressed: () => context.read<CounterBloc>().add(IncrementEvent()),
              tooltip: 'Increment',
              child: Icon(Icons.add),
            ),
            SizedBox(height: 10),
            FloatingActionButton(
              onPressed: () => context.read<CounterBloc>().add(DecrementEvent()),
              tooltip: 'Decrement',
              child: Icon(Icons.remove),
            ),
          ],
        ),
      ),
    );
  }
}

class CounterWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocBuilder<CounterBloc, CounterState>(
      builder: (context, state) {
        return Text('${state.count}');
      },
    );
  }
}

在这个例子中,我们创建了一个CounterBloc来处理计数器的状态管理,并在UI中使用BlocProviderBlocBuilder来监听和显示状态的变化。CounterWidget负责显示当前的计数,而两个FloatingActionButton则用于触发增加和减少计数的事件。

通过这种方式,你可以利用reusable_bloc_base插件来创建和管理可复用的Bloc逻辑,从而提高Flutter应用的代码质量和可维护性。

回到顶部