Flutter数据可视化与UI组件插件dash_kit_core的使用

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

Flutter数据可视化与UI组件插件dash_kit_core的使用

Dash Kit Core 是一个提供基本架构组件的库,它基于Async Redux包构建,并提供了额外的API,例如用于监视应用程序中操作当前状态的操作状态API和高效的存储和更新数据的StoreList。

什么是AsyncRedux?

async_redux 的工作流如下图所示:

Flow Diagram

其主要概念区别在于引入了异步Reducer(Async Reducer),允许声明返回Future的异步操作。更多关于async_redux的信息,可以参考这篇文章或直接访问官方文档

示例代码

class QueryAndIncrementAction extends ReduxAction<AppState> {
  @override
  Future<AppState> reduce() async {
    int value = await getAmount();
    return state.copy(counter: state.counter + value);
  }
}

操作 Operations

在开发过程中,我们经常需要执行许多异步操作并在它们完成后做某些事情。因此,Dash Kit Core添加了获取异步操作状态的功能。通过为ReduxAction添加一个包装器来实现这一点,该包装器称为Action。为了确保类型安全,我们可以编写另一个包装器,定义特定的操作类型。

枚举操作类型

enum Operation {
  login,
  loginViaFacebook,
  loginViaGoogle,
  loginViaApple,
}

创建应用状态

import 'package:built_value/built_value.dart';

part 'app_state.g.dart';

abstract class AppState implements Built<AppState, AppStateBuilder>, GlobalState {
  factory AppState([void Function(AppStateBuilder) updates]) = _$AppState;

  AppState._();

  ProfileState get profile;

  @override
  BuiltMap<Object, OperationState> get operationsState;

  @override
  T updateOperation<T extends GlobalState>(
     Object? operationKey,
     OperationState operationState,
  ) {
    if (operationKey == null) {
      return this as T;
    }

    final GlobalState newState = rebuild(
      (s) => s.operationsState[operationKey] = operationState,
    );
    return newState as T;
  }

  @override
  OperationState getOperationState(Object operationKey) {
    return operationsState[operationKey] ?? OperationState.idle;
  }

  static AppState initial() {
    return AppState(
      (b) => b.profile = ProfileState.initial().toBuilder(),
    );
  }
}

登录操作示例

class LoginAction extends Action<AppState> {
  LoginAction({
    required this.email,
    required this.password,
  });

  final String email;
  final String password;

  @override
  Operation get operationKey => Operation.login;

  @override
  Future<AppState> reduce() async {
    final currentUserName = await Future.delayed(Duration(seconds: 5), () {
      if (email.isNotEmpty && password.isNotEmpty) {
        return 'UserName';
      }
    });

    return state.rebuild((s) {
      s.profileState.name = currentUserName;
    });
  }
}

在UI中使用操作状态

class _MyHomePageState extends State<MyHomePage> {
  final _formKey = GlobalKey<FormState>();
  final _emailController = TextEditingController();
  final _passwordController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: StoreConnector<AppState, OperationState>(
        converter: (store) => store.state.getOperationState(Operation.login),
        builder: (context, operationState) => LoadableView(
          isLoading: operationState.isInProgress,
          child: Padding(
            padding: const EdgeInsets.all(8),
            child: Form(
              key: _formKey,
              child: Column(
                children: [
                  TextFormField(
                    controller: _emailController,
                    decoration: const InputDecoration(hintText: 'Email'),
                  ),
                  TextFormField(
                    controller: _passwordController,
                    decoration: const InputDecoration(hintText: 'Password'),
                    obscureText: true,
                  ),
                  TextButton(
                    onPressed: _onLoginPressed,
                    child: const Text('LOG IN'),
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }

  Future<void> _onLoginPressed() async {
    return context
        .dispatchAndWait(
          LoginAction(
            email: _emailController.text,
            password: _passwordController.text,
          ),
        )
        .then((_) => _openSuccessDialog())
        .catchError(_onError);
  }

  void _onError(dynamic error) {
    showDialog(
        context: context,
        builder: (context) {
          return Dialog(
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(6),
            ),
            backgroundColor: Colors.white,
            child: const SizedBox(
              height: 100,
              width: 100,
              child: Center(
                child: Text('ERROR: something went wrong'),
              ),
            ),
          );
        });
  }

  void _openSuccessDialog() {
    final state = StoreProvider.state<AppState>(context);
    final userName = state.profileState.name;

    showDialog(
        context: context,
        builder: (context) {
          return Dialog(
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(6),
            ),
            backgroundColor: Colors.white,
            child: SizedBox(
              height: 100,
              width: 100,
              child: Center(
                child: Text('Hi, $userName!'),
              ),
            ),
          );
        });
  }
}

StoreList

StoreList是对BuiltList的一个封装,提供了更方便的方式来更新存储中的数据。它适用于存储列表或字典类型的数据。

示例代码

// 定义用户资料类
class UserProfile implements StoreListItem {
  UserProfile({Object id}) : super(id);
}

// 在全局状态中使用StoreList
StoreList<UserProfile> get userProfiles;

// 获取所有项
state.userProfiles.itemsMap;

// 获取所有ID
state.userProfiles.itemsIds;

// 获取单个项
state.userProfiles.getItem('Some ID according to type which you use');

// 删除项
@override
Future<AppState> reduce() async {
  return state.dataStructure.someOldList.deleteItem(conditionItemId);
}

PaginatedList

PaginatedList用于分页加载数据,通常包含以下元信息:

  • items: 数据项
  • meta: 分页信息(如前一页、当前页、下一页、总条数)

初始化和更新

// 初始化
static AppState initial() {
  return AppState(
    (b) => b.paginatedList = PaginatedList<YourType>.empty(),
  );
}

// 更新
@Override
Future<AppState> reduce() async {
  return state.paginatedList.update(
    items: newItems,
    totalCount: response.totalCount,
  );
}

通过以上内容,您应该能够理解如何使用dash_kit_core进行数据可视化和UI组件的集成。希望这些信息对您有所帮助!


更多关于Flutter数据可视化与UI组件插件dash_kit_core的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter数据可视化与UI组件插件dash_kit_core的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter中使用dash_kit_core插件进行数据可视化与UI组件集成的代码示例。dash_kit_core是一个用于构建数据驱动的UI组件的Flutter库,尽管它不是官方库,但假设它提供了一系列用于数据可视化和UI构建的组件。以下示例代码展示了如何使用假设的dash_kit_core库来创建一个简单的数据可视化界面。

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

dependencies:
  flutter:
    sdk: flutter
  dash_kit_core: ^latest_version  # 替换为实际的最新版本号

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

接下来,在你的Flutter项目中,创建一个简单的页面来展示数据可视化组件。以下是一个示例代码:

import 'package:flutter/material.dart';
import 'package:dash_kit_core/dash_kit_core.dart'; // 假设的包导入路径

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Dash Kit Core Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: DataVisualizationScreen(),
    );
  }
}

class DataVisualizationScreen extends StatefulWidget {
  @override
  _DataVisualizationScreenState createState() => _DataVisualizationScreenState();
}

class _DataVisualizationScreenState extends State<DataVisualizationScreen> {
  // 示例数据
  final List<Map<String, dynamic>> data = [
    {'label': 'A', 'value': 30},
    {'label': 'B', 'value': 45},
    {'label': 'C', 'value': 20},
    {'label': 'D', 'value': 80},
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Data Visualization with Dash Kit Core'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              'Pie Chart Example',
              style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
            SizedBox(height: 16),
            // 使用假设的PieChart组件
            DashKitPieChart(
              data: data.map((item) => PieChartData(label: item['label'], value: item['value'])).toList(),
            ),
            SizedBox(height: 32),
            Text(
              'Bar Chart Example',
              style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
            SizedBox(height: 16),
            // 使用假设的BarChart组件
            DashKitBarChart(
              data: data.map((item) => BarChartData(label: item['label'], value: item['value'])).toList(),
            ),
          ],
        ),
      ),
    );
  }
}

// 假设的PieChartData类,根据dash_kit_core的实际API可能需要调整
class PieChartData {
  final String label;
  final double value;

  PieChartData({required this.label, required this.value});
}

// 假设的BarChartData类,根据dash_kit_core的实际API可能需要调整
class BarChartData {
  final String label;
  final double value;

  BarChartData({required this.label, required this.value});
}

// 假设的DashKitPieChart组件,实际使用时需要根据dash_kit_core的文档进行调整
class DashKitPieChart extends StatelessWidget {
  final List<PieChartData> data;

  DashKitPieChart({required this.data});

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 300,
      child: CustomPaint(
        // 这里应该使用dash_kit_core提供的绘制逻辑
        painter: _PieChartPainter(data: data),
      ),
    );
  }
}

// 假设的_PieChartPainter类,用于绘制饼图
class _PieChartPainter extends CustomPainter {
  final List<PieChartData> data;

  _PieChartPainter({required this.data});

  @override
  void paint(Canvas canvas, Size size) {
    final Paint paint = Paint()
      ..style = PaintingStyle.fill;

    double startAngle = 0.0;
    double sum = data.fold(0, (value, element) => value + element.value);

    for (final PieChartData item in data) {
      final double sweepAngle = (item.value / sum) * 2 * 3.141592653589793;
      final Rect rect = Rect.fromCircle(center: Offset(size.width / 2, size.height / 2), radius: size.width / 2);

      paint.color = Colors.primaries[data.indexOf(item) % Colors.primaries.length];
      canvas.drawArc(rect, startAngle, sweepAngle, false, paint);

      startAngle += sweepAngle;
    }
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return oldDelegate != this;
  }
}

// 假设的DashKitBarChart组件,实际使用时需要根据dash_kit_core的文档进行调整
class DashKitBarChart extends StatelessWidget {
  final List<BarChartData> data;

  DashKitBarChart({required this.data});

  @override
  Widget build(BuildContext context) {
    return ListView.separated(
      shrinkWrap: true,
      itemCount: data.length,
      itemBuilder: (context, index) {
        return Container(
          height: 50,
          color: Colors.primaries[index % Colors.primaries.length],
          child: Center(
            child: Text(
              '${data[index].value}',
              style: TextStyle(color: Colors.white, fontSize: 18),
            ),
          ),
        );
      },
      separatorBuilder: (context, index) => Divider(height: 8),
    );
  }
}

注意:上述代码中的DashKitPieChartDashKitBarChart组件以及相关的数据类PieChartDataBarChartData是基于假设的dash_kit_core库的功能构建的。在实际使用中,你需要根据dash_kit_core的文档和API来调整这些组件和数据类的实现。特别是,dash_kit_core可能提供了现成的饼图和条形图组件,你可以直接使用而无需自己实现绘制逻辑。

此外,如果dash_kit_core库提供了主题和样式定制功能,你还可以进一步美化你的UI组件。务必查阅dash_kit_core的官方文档以获取最新的使用指南和API参考。

回到顶部