Flutter步骤指示器插件acyclic_steps的使用

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

Flutter步骤指示器插件acyclic_steps的使用

描述

acyclic_steps 是一个用于定义具有非循环依赖关系的步骤并评估这些步骤的Dart包。每个步骤可以是一个函数(可选异步),产生结果或副作用。一个步骤可以依赖于其他步骤,但循环依赖会导致编译时错误。

当评估一个步骤时,其依赖项会首先被评估,并且在依赖约束允许的情况下,这些依赖项将并发运行。步骤也可以被覆盖以注入初始值或在测试期间使用模拟/伪造对象。Step的结果会被缓存在执行该StepRunner对象中,确保步骤不会重复执行。

此包旨在促进具有许多组件的复杂项目的初始化,其中某些组件依赖于其他组件。例如,在服务器环境中,可能有一个步骤是设置数据库连接,而其他步骤则依赖于这个数据库连接。在测试期间,能够覆盖数据库连接步骤也是非常有用的,以便使用不同的数据库或甚至不同的数据库驱动程序。

此外,该包还适用于评估复杂的任务图,其中任务可能依赖于前面任务的结果。

示例代码

下面是一个完整的示例demo,演示了如何使用 acyclic_steps 包:

import 'dart:async' show Future;
import 'package:acyclic_steps/acyclic_steps.dart';

/// 定义一个提供消息的步骤,这是一个虚拟步骤,因为它没有实现而是抛出一个错误。
/// 因此,要评估依赖于 [messageStep] 的步骤,必须通过注入一个值来覆盖它。
final Step<String> messageStep = Step.define('message').build(
  () => throw UnimplementedError('message must be overriden with input'),
);

/// 定义一个提供日期和时间的步骤
final dateTimeStep = Step.define('date-time').build(
  () => DateTime.now().toString(),
);

/// 定义一个具有副作用的步骤
final Step<void> printStep = Step.define(
  'print',
) // 依赖项:
    .dep(messageStep)
    .dep(dateTimeStep)
    // 构建步骤的方法
    .build((
  msg, // 从评估 [messageStep] 得到的结果
  time, // 从评估 [dateTimeStep] 得到的结果
) async {
  await Future.delayed(Duration(milliseconds: 100));
  print('$msg at $time');
});

Future<void> main() async {
  final r = Runner();
  // 覆盖 [messageStep] 以提供输入值。
  r.override(messageStep, 'hello world');
  // 评估 [printStep],这将依次评估 [dateTimeStep],并重用为 [messageStep] 覆盖的值。
  await r.run(printStep);

  // 在测试时,可能希望覆盖 [dateTimeStep] 以生成独立于时间的相同输出。
  // 为此,我们必须创建一个新的 runner:
  final testRunner = Runner();
  testRunner.override(messageStep, 'hello world');
  testRunner.override(dateTimeStep, '2019-11-04 09:47:37.461795');
  // 现在我们可以确保 [dateTimeStep] 评估为某个可预测的值
  assert(await testRunner.run(dateTimeStep) == '2019-11-04 09:47:37.461795');
  // 这将打印固定的时间,对于测试非常有用。
  await testRunner.run(printStep);
}

使用说明

  1. 引入包:在 pubspec.yaml 文件中添加 acyclic_steps 包的依赖。

    dependencies:
      acyclic_steps: ^最新版本号
    
  2. 定义步骤:使用 Step.define() 方法定义步骤,并使用 .dep() 方法指定依赖项。使用 .build() 方法构建步骤逻辑。

  3. 创建Runner实例:使用 Runner() 创建一个实例,用于管理和执行步骤。

  4. 覆盖步骤:使用 runner.override() 方法覆盖步骤,以便在运行时提供特定的输入值或模拟数据。

  5. 执行步骤:使用 runner.run() 方法执行步骤,自动处理依赖关系并并发执行依赖项。

通过这种方式,您可以方便地管理复杂的初始化流程和任务依赖关系,同时确保代码的可测试性和灵活性。


更多关于Flutter步骤指示器插件acyclic_steps的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter步骤指示器插件acyclic_steps的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter中使用acyclic_steps步骤指示器插件的一个示例代码。这个插件可以帮助你创建步骤指示器,通常用于引导用户完成一系列步骤,例如注册流程或表单填写。

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

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

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

接下来,是一个简单的示例代码,展示如何使用acyclic_steps

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Acyclic Steps Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: StepIndicatorScreen(),
    );
  }
}

class StepIndicatorScreen extends StatefulWidget {
  @override
  _StepIndicatorScreenState createState() => _StepIndicatorScreenState();
}

class _StepIndicatorScreenState extends State<StepIndicatorScreen> {
  final List<Step> steps = [
    Step(
      title: Text('Step 1: Introduction'),
      content: Text('This is the introduction step.'),
      isActive: true,
    ),
    Step(
      title: Text('Step 2: Personal Info'),
      content: Text('Enter your personal information.'),
      isActive: false,
    ),
    Step(
      title: Text('Step 3: Payment Info'),
      content: Text('Enter your payment information.'),
      isActive: false,
    ),
    Step(
      title: Text('Step 4: Confirmation'),
      content: Text('Confirm your order.'),
      isActive: false,
    ),
  ];

  int currentStep = 0;

  void _nextStep() {
    setState(() {
      if (currentStep < steps.length - 1) {
        currentStep++;
        steps[currentStep].isActive = true;
        if (currentStep > 0) {
          steps[currentStep - 1].isActive = false;
        }
      }
    });
  }

  void _prevStep() {
    setState(() {
      if (currentStep > 0) {
        currentStep--;
        steps[currentStep].isActive = true;
        if (currentStep < steps.length - 1) {
          steps[currentStep + 1].isActive = false;
        }
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Step Indicator Example'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            AcyclicSteps(
              steps: steps,
              currentIndex: currentStep,
              stepDoneIcon: Icons.done,
              stepActiveIcon: Icons.circle,
              stepInactiveIcon: Icons.circle_outlined,
              stepDoneColor: Colors.green,
              stepActiveColor: Colors.blue,
              stepInactiveColor: Colors.grey,
            ),
            SizedBox(height: 24),
            Expanded(
              child: SingleChildScrollView(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    steps[currentStep].content,
                    SizedBox(height: 24),
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        currentStep > 0
                            ? TextButton(
                                onPressed: _prevStep,
                                child: Text('Previous'),
                              )
                            : SizedBox(),
                        TextButton(
                          onPressed: _nextStep,
                          child: Text('Next'),
                        ),
                      ],
                    ),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

在这个示例中,我们创建了一个包含四个步骤的步骤指示器。每个步骤都有一个标题和内容。我们使用AcyclicSteps小部件来显示步骤指示器,并手动管理当前活动步骤(通过currentStep变量)。

  • _nextStep_prevStep函数用于在步骤之间导航。
  • AcyclicSteps小部件的steps属性接收步骤列表,currentIndex属性表示当前活动步骤的索引。
  • 步骤指示器的图标和颜色可以通过stepDoneIconstepActiveIconstepInactiveIconstepDoneColorstepActiveColorstepInactiveColor等属性进行自定义。

希望这个示例代码能帮助你更好地理解和使用acyclic_steps插件。

回到顶部