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

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

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

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

这些小部件支持 BlocCubit

特性

  • 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包含一个简单的事件CounterIncrementedCounterState包含一个整数count
  3. UI组件: 在main.dart中,我们使用BlocProvider来提供CounterBloc实例,并在CounterPage中使用BlocBuilder来监听状态变化并更新UI。
  4. 事件触发: 点击FloatingActionButton时,触发CounterIncremented事件,从而更新Bloc状态。

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

回到顶部