Flutter UI组件集成插件bloc_widgets的使用

Flutter UI组件集成插件bloc_widgets的使用

bloc_widgets 是一个用于简化 Flutter 中 flutter_bloc 包使用的插件。它通过扩展 StatelessWidget 并覆盖 build 方法来提供一个名为 buildWithBloc 的方法,该方法用于根据给定的状态构建小部件。

BlocConsumerWidget 还提供了 listenWhen、buildWhen 和 listen 方法,这些方法与 BlocConsumer 相同。BlocBuilderWidget 提供了 buildWhen 方法,与 BlocBuilder 相同。BlocListenerWidget 提供了 listenWhen 方法,与 BlocListener 相同。SelectorWidget 提供了 selector 方法,与 BlocSelector 相同。

这些小部件支持 Bloc 和 Cubit。

特性

  • 将 BlocConsumer 功能封装到 BlocConsumerWidget 中。
  • 将 BlocBuilder 功能封装到 BlocBuilderWidget 中。
  • 将 BlocListener 功能封装到 BlocListenerWidget 中。
  • 将 BlocSelector 功能封装到 BlocSelectorWidget 中。

安装

在你的 pubspec.yaml 文件中添加 bloc_widgets 作为依赖:

dependencies:
  bloc_widgets: ^1.1.2

示例代码

以下是一个完整的示例,展示了如何使用 bloc_widgets 插件中的不同小部件。

import 'package:bloc_widgets/bloc_widgets.dart';
import 'package:flutter/material.dart';

import 'calculator_bloc.dart';
import 'calculator_cubit.dart';

void main() => runApp(const MyApp());

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(primarySwatch: Colors.blue),
      // home: const MyHomePage(title: 'BlocWidget Demo'),
      home: const MySelectorHomePage(title: 'BlocSelectorWidget Demo'),
    );
  }
}

class MyConsumerHomePage extends BlocConsumerWidget<CalculatorBloc, BlocState> {
  const MyConsumerHomePage({super.key, required this.title});

  final String title;

  [@override](/user/override)
  CalculatorBloc bloc(BuildContext context) => CalculatorBloc();

  [@override](/user/override)
  void onMount(CalculatorBloc bloc) => bloc.add(CalculatorEvent.onMount);

  [@override](/user/override)
  void listener(context, bloc, state) {
    ScaffoldMessenger.of(context).clearSnackBars();

    if (state.counter == 0) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Counter cleared')),
      );
      return;
    }

    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('Counter changed')),
    );
  }

  [@override](/user/override)
  Widget build(context, bloc, state) {
    final textTheme = Theme.of(context).textTheme;
    return Scaffold(
      appBar: AppBar(title: Text(title)),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text('Counter value:'),
            Text('${state.counter}', style: textTheme.headlineMedium),
          ],
        ),
      ),
      bottomNavigationBar: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            FloatingActionButton(
              onPressed: () => bloc.add(CalculatorEvent.remove),
              tooltip: 'Decrement',
              child: const Icon(Icons.exposure_minus_1),
            ),
            TextButton(
              onPressed: () => bloc.add(CalculatorEvent.clear),
              child: const Text('Clear counter'),
            ),
            FloatingActionButton(
              onPressed: () => bloc.add(CalculatorEvent.add),
              tooltip: 'Increment',
              child: const Icon(Icons.exposure_plus_1),
            ),
          ],
        ),
      ),
    );
  }
}

class MyBuilderHomePage extends BlocBuilderWidget<CalculatorBloc, BlocState> {
  const MyBuilderHomePage({super.key, required this.title});

  final String title;

  [@override](/user/override)
  CalculatorBloc bloc(BuildContext context) => CalculatorBloc();

  [@override](/user/override)
  void onMount(CalculatorBloc bloc) => bloc.add(CalculatorEvent.onMount);

  [@override](/user/override)
  Widget build(context, bloc, state) {
    final textTheme = Theme.of(context).textTheme;
    return Scaffold(
      appBar: AppBar(title: Text(title)),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text('Counter value:'),
            Text('${state.counter}', style: textTheme.headlineMedium),
          ],
        ),
      ),
      bottomNavigationBar: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            FloatingActionButton(
              onPressed: () => bloc.add(CalculatorEvent.remove),
              tooltip: 'Decrement',
              child: const Icon(Icons.exposure_minus_1),
            ),
            TextButton(
              onPressed: () => bloc.add(CalculatorEvent.clear),
              child: const Text('Clear counter'),
            ),
            FloatingActionButton(
              onPressed: () => bloc.add(CalculatorEvent.add),
              tooltip: 'Increment',
              child: const Icon(Icons.exposure_plus_1),
            ),
          ],
        ),
      ),
    );
  }
}

class MySelectorHomePage extends BlocSelectorWidget<CalculatorCubit, CubitState, int> {
  const MySelectorHomePage({super.key, required this.title});

  final String title;

  [@override](/user/override)
  CalculatorCubit bloc(BuildContext context) => CalculatorCubit();

  [@override](/user/override)
  void onMount(CalculatorCubit bloc) => bloc.changeCounter(-1);

  [@override](/user/override)
  int selector(CubitState state) => state.counter;

  [@override](/user/override)
  Widget build(context, bloc, selector) {
    final textTheme = Theme.of(context).textTheme;
    return Scaffold(
      appBar: AppBar(title: Text(title)),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            const Text('Counter value:'),
            Text('$selector', style: textTheme.headlineMedium),
          ],
        ),
      ),
      bottomNavigationBar: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            FloatingActionButton(
              onPressed: () => bloc.changeCounter(selector - 1),
              tooltip: 'Decrement',
              child: const Icon(Icons.exposure_minus_1),
            ),
            TextButton(
              onPressed: () => bloc.changeCounter(0),
              child: const Text('Clear counter'),
            ),
            FloatingActionButton(
              onPressed: () => bloc.changeCounter(selector + 1),
              tooltip: 'Increment',
              child: const Icon(Icons.exposure_plus_1),
            ),
          ],
        ),
      ),
    );
  }
}

class MyListenerHomePage extends BlocListenerWidget<CalculatorCubit, CubitState> {
  const MyListenerHomePage({super.key, required this.title});

  final String title;

  [@override](/user/override)
  CalculatorCubit bloc(BuildContext context) => CalculatorCubit();

  [@override](/user/override)
  void onMount(CalculatorCubit bloc) => bloc.changeCounter(-1);

  [@override](/user/override)
  void listener(BuildContext context, CalculatorCubit bloc, CubitState state) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('Counter value: ${state.counter}')),
    );
  }

  [@override](/user/override)
  Widget build(BuildContext context, CalculatorCubit bloc) {
    return Scaffold(
      appBar: AppBar(title: Text(title)),
      body: const Center(child: Text('Click to show SnackBar with value')),
    );
  }
}

更多关于Flutter UI组件集成插件bloc_widgets的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter UI组件集成插件bloc_widgets的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter项目中集成并使用bloc_widgets插件的示例代码。bloc_widgets插件主要用于简化Bloc状态管理与UI组件之间的集成。

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

dependencies:
  flutter:
    sdk: flutter
  flutter_bloc: ^8.0.0  # 确保版本是最新的
  bloc: ^8.0.0         # 确保版本是最新的

然后,运行flutter pub get来获取这些依赖。

创建Bloc和State

接下来,我们创建一个简单的计数器Bloc和它的状态。

counter_bloc.dart

import 'package:bloc/bloc.dart';

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

class CounterBloc extends Bloc<CounterEvent, CounterState> {
  CounterBloc() : super(CounterInitial());

  @override
  Stream<CounterState> mapEventToState(CounterEvent event) async* {
    if (event is CounterIncremented) {
      yield* _mapCounterIncrementedToState();
    }
  }

  Stream<CounterState> _mapCounterIncrementedToState() async* {
    yield CounterState(count: state.count + 1);
  }
}

counter_event.dart

part of 'counter_bloc.dart';

abstract class CounterEvent {}

class CounterIncremented extends CounterEvent {}

counter_state.dart

part of 'counter_bloc.dart';

class CounterState {
  final int count;

  CounterState({required this.count});

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

class CounterInitial extends CounterState {
  CounterInitial() : super(count: 0);
}

使用BlocProvider和BlocBuilder

现在,我们在UI组件中使用BlocProvider来提供Bloc实例,并使用BlocBuilder来根据Bloc状态更新UI。

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(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: BlocProvider(
        create: (context) => CounterBloc(),
        child: CounterPage(),
      ),
    );
  }
}

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

解释

  1. Bloc和State: 我们定义了一个CounterBloc,它处理CounterEvent并转换到CounterState。
  2. 事件和状态: CounterEvent包含一个简单的事件CounterIncremented,CounterState包含一个整数count。
  3. UI组件: 在main.dart中,我们使用BlocProvider来提供CounterBloc实例,并在CounterPage中使用BlocBuilder来监听状态变化并更新UI。
  4. 事件触发: 点击FloatingActionButton时,触发CounterIncremented事件,从而更新Bloc状态。

这样,我们就完成了Flutter项目中bloc_widgets(实际上是flutter_bloc库中的功能)的基本集成和使用。希望这个示例对你有所帮助!

回到顶部