Flutter图表与状态管理插件graph_bloc的使用

Flutter图表与状态管理插件graph_bloc的使用

Graph Bloc

一个实现FSM(有限状态机)的包。这是一个灵活且轻量的状态图,可以帮助保证事件和状态之间的关系保持声明性。

开始使用

你将需要在pubspec.yaml文件中包含此包。

dependencies:
  graph_bloc: 0.1.0

使用方法

查看/example文件夹中的典型计数器示例。

其他信息

有关FSM的更多信息,请参阅维基百科

示例代码

以下是完整的示例代码:

import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:graph_bloc/graph_bloc.dart';

// 定义事件
abstract class ExampleEvent extends Equatable {
  const ExampleEvent();

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

class ExampleEventLoad extends ExampleEvent {
  const ExampleEventLoad();
}

class ExampleEventIncrement extends ExampleEvent {
  const ExampleEventIncrement();
}

class ExampleEventDecrement extends ExampleEvent {
  const ExampleEventDecrement();
}

class ExampleEventReset extends ExampleEvent {
  const ExampleEventReset();
}

class ExampleEventError extends ExampleEvent {
  const ExampleEventError({this.error});

  final Object? error;

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

// 定义状态
abstract class ExampleState extends Equatable {
  const ExampleState();

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

class ExampleStateLoading extends ExampleState {
  const ExampleStateLoading();
}

class ExampleStateLoaded extends ExampleState {
  const ExampleStateLoaded([this.counter = 0]);

  final int counter;

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

class ExampleStateError extends ExampleState {
  const ExampleStateError([this.error]);

  final Object? error;

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

// 我们的状态图实现
class ExampleGraphBloc extends GraphBloc<ExampleEvent, ExampleState> {
  ExampleGraphBloc({
    required ExampleState initialState,
  }) : super(initialState: initialState);

  @override
  BlocStateGraph<ExampleEvent, ExampleState> get graph => BlocStateGraph(
        graph: {
          ExampleStateLoading: {
            ExampleEventLoad: transition((
              ExampleEventLoad event,
              ExampleStateLoading state,
            ) {
              return const ExampleStateLoaded(0);
            }),
          },
          ExampleStateLoaded: {
            ExampleEventIncrement: transition((ExampleEventIncrement event, ExampleStateLoaded state) {
              return ExampleStateLoaded(state.counter + 1);
            }),
            ExampleEventDecrement: transition((ExampleEventDecrement event, ExampleStateLoaded state) {
              return ExampleStateLoaded(state.counter - 1);
            }),
          },
        },
        unrestrictedGraph: {
          ExampleEventError: transition((event, state) {
            return const ExampleStateError('Failed loading');
          }),
          ExampleEventReset: transition(((event, state) => const ExampleStateLoaded(0))),
        },
      );
}

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  ExampleGraphBloc bloc = ExampleGraphBloc(initialState: const ExampleStateLoaded());

  void _incrementCounter() {
    bloc.add(const ExampleEventIncrement());
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text(
              'You have pushed the button this many times:',
            ),
            StreamBuilder<ExampleState>(
              stream: bloc.stream,
              builder: (context, snapshot) {
                if (snapshot.hasData && snapshot.data is ExampleStateLoaded) {
                  return Text(
                    '${(snapshot.data as ExampleStateLoaded).counter}',
                    style: Theme.of(context).textTheme.titleMedium,
                  );
                }

                return const SizedBox.shrink();
              },
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

代码解释

  1. 定义事件

    abstract class ExampleEvent extends Equatable {
      const ExampleEvent();
      @override
      List<Object?> get props => [];
    }
    
    class ExampleEventLoad extends ExampleEvent {
      const ExampleEventLoad();
    }
    
    class ExampleEventIncrement extends ExampleEvent {
      const ExampleEventIncrement();
    }
    
    class ExampleEventDecrement extends ExampleEvent {
      const ExampleEventDecrement();
    }
    
    class ExampleEventReset extends ExampleEvent {
      const ExampleEventReset();
    }
    
    class ExampleEventError extends ExampleEvent {
      const ExampleEventError({this.error});
      final Object? error;
      @override
      List<Object?> get props => [error];
    }
    

    这些类定义了不同的事件类型,例如加载、增加、减少、重置和错误。

  2. 定义状态

    abstract class ExampleState extends Equatable {
      const ExampleState();
      @override
      List<Object?> get props => [];
    }
    
    class ExampleStateLoading extends ExampleState {
      const ExampleStateLoading();
    }
    
    class ExampleStateLoaded extends ExampleState {
      const ExampleStateLoaded([this.counter = 0]);
      final int counter;
      @override
      List<Object?> get props => [counter];
    }
    
    class ExampleStateError extends ExampleState {
      const ExampleStateError([this.error]);
      final Object? error;
      @override
      List<Object?> get props => [error];
    }
    

    这些类定义了不同的状态类型,例如加载、已加载和错误。

  3. 定义状态图

    class ExampleGraphBloc extends GraphBloc<ExampleEvent, ExampleState> {
      ExampleGraphBloc({
        required ExampleState initialState,
      }) : super(initialState: initialState);
    
      @override
      BlocStateGraph<ExampleEvent, ExampleState> get graph => BlocStateGraph(
            graph: {
              ExampleStateLoading: {
                ExampleEventLoad: transition((
                  ExampleEventLoad event,
                  ExampleStateLoading state,
                ) {
                  return const ExampleStateLoaded(0);
                }),
              },
              ExampleStateLoaded: {
                ExampleEventIncrement: transition((ExampleEventIncrement event, ExampleStateLoaded state) {
                  return ExampleStateLoaded(state.counter + 1);
                }),
                ExampleEventDecrement: transition((ExampleEventDecrement event, ExampleStateLoaded state) {
                  return ExampleStateLoaded(state.counter - 1);
                }),
              },
            },
            unrestrictedGraph: {
              ExampleEventError: transition((event, state) {
                return const ExampleStateError('Failed loading');
              }),
              ExampleEventReset: transition(((event, state) => const ExampleStateLoaded(0))),
            },
          );
    }
    

    ExampleGraphBloc类实现了状态图,定义了状态和事件之间的转换关系。

  4. 主应用逻辑

    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: const MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      const MyHomePage({Key? key, required this.title}) : super(key: key);
    
      final String title;
    
      @override
      State<MyHomePage> createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      ExampleGraphBloc bloc = ExampleGraphBloc(initialState: const ExampleStateLoaded());
    
      void _incrementCounter() {
        bloc.add(const ExampleEventIncrement());
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                const Text(
                  'You have pushed the button this many times:',
                ),
                StreamBuilder<ExampleState>(
                  stream: bloc.stream,
                  builder: (context, snapshot) {
                    if (snapshot.hasData && snapshot.data is ExampleStateLoaded) {
                      return Text(
                        '${(snapshot.data as ExampleStateLoaded).counter}',
                        style: Theme.of(context).textTheme.titleMedium,
                      );
                    }
    
                    return const SizedBox.shrink();
                  },
                ),
              ],
            ),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: _incrementCounter,
            tooltip: 'Increment',
            child: const Icon(Icons.add),
          ),
        );
      }
    }
    

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

1 回复

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


在Flutter中,graph_bloc 是一个用于管理图表状态的状态管理插件。它基于 Bloc(Business Logic Component)模式,可以帮助开发者更轻松地管理图表的状态和数据流。以下是如何在Flutter项目中使用 graph_bloc 的基本步骤:

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 graph_bloc 和其他相关依赖:

dependencies:
  flutter:
    sdk: flutter
  graph_bloc: ^0.1.0  # 请根据实际情况选择最新版本
  flutter_bloc: ^8.0.0  # Bloc库
  equatable: ^2.0.0  # 用于简化状态比较

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

2. 创建图表状态

接下来,你需要定义图表的状态。通常,图表的状态会包括数据、加载状态等信息。

import 'package:equatable/equatable.dart';

abstract class GraphState extends Equatable {
  const GraphState();

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

class GraphInitial extends GraphState {}

class GraphLoading extends GraphState {}

class GraphLoaded extends GraphState {
  final List<double> data;

  const GraphLoaded(this.data);

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

class GraphError extends GraphState {
  final String message;

  const GraphError(this.message);

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

3. 创建图表事件

事件是用户交互或其他外部因素触发的动作,例如加载数据、刷新图表等。

import 'package:equatable/equatable.dart';

abstract class GraphEvent extends Equatable {
  const GraphEvent();

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

class LoadGraphData extends GraphEvent {}

4. 创建图表 Bloc

Bloc 是业务逻辑的核心,它接收事件并根据事件更新状态。

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

class GraphBloc extends Bloc<GraphEvent, GraphState> {
  GraphBloc() : super(GraphInitial());

  @override
  Stream<GraphState> mapEventToState(GraphEvent event) async* {
    if (event is LoadGraphData) {
      yield GraphLoading();
      try {
        // 模拟加载数据
        await Future.delayed(Duration(seconds: 2));
        final data = [1.0, 2.0, 3.0, 4.0, 5.0];
        yield GraphLoaded(data);
      } catch (e) {
        yield GraphError('Failed to load graph data');
      }
    }
  }
}

5. 在UI中使用 Bloc

在UI中,你可以使用 BlocBuilderBlocProvider 来监听状态变化并更新UI。

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'graph_bloc.dart';

class GraphScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (context) => GraphBloc()..add(LoadGraphData()),
      child: Scaffold(
        appBar: AppBar(
          title: Text('Graph Example'),
        ),
        body: BlocBuilder<GraphBloc, GraphState>(
          builder: (context, state) {
            if (state is GraphInitial || state is GraphLoading) {
              return Center(child: CircularProgressIndicator());
            } else if (state is GraphLoaded) {
              return Center(
                child: Text('Graph Data: ${state.data}'),
              );
            } else if (state is GraphError) {
              return Center(child: Text(state.message));
            }
            return Container();
          },
        ),
      ),
    );
  }
}

6. 运行应用

现在你可以运行应用并查看图表的状态管理是如何工作的。当应用启动时,LoadGraphData 事件会被触发,GraphBloc 会加载数据并更新UI。

7. 使用 graph_bloc 插件

graph_bloc 插件可能提供了特定的图表组件或工具,你可以根据插件的文档来使用这些功能。例如,如果插件提供了 GraphWidget,你可以将其集成到UI中:

if (state is GraphLoaded) {
  return GraphWidget(data: state.data);
}
回到顶部