推荐 Flutter 简单易用可以个性化定制的步骤条组件

前言

我们在应用里,会经常遇到一项业务有多个步骤,比如订单状态,任务进展等等,这个时候就需要用到步骤指示器,也叫步骤条。步骤条可以让用户清晰地知道整个业务会经历哪些环节,以及当前所处的状态,如下图所示。

这种步骤条自己实现还挺麻烦的,不过已经有人给我们造好"轮子"了,这就是我们本篇要介绍的easy_stepper

easy_stepper 简介

easy_stepper 专门用于指示步骤,其优点是简单易用,而且可以高度自定义。因此,我们可以基于它实现各种花里胡哨(不实用)的步骤条,比如下面这种效果。

我们先来看最基础的使用,也就是我们在前言中贴的截图:

dart 复制代码
SingleChildScrollView(
  child: EasyStepper(
    direction: Axis.horizontal,
    disableScroll: false,
    alignment: Alignment.center,
    activeStep: activeStep,
    lineLength: 50,
    lineSpace: 0,
    lineType: LineType.normal,
    defaultLineColor: toBeFinishedColor,
    finishedLineColor: finishedColor,
    activeStepTextColor: activeColor,
    finishedStepTextColor: finishedColor,
    internalPadding: 0,
    padding: const EdgeInsetsDirectional.symmetric(
        horizontal: 10, vertical: 40),
    showLoadingAnimation: false,
    stepRadius: 8.0,
    showStepBorder: false,
    lineThickness: 1.0,
    steps: [
      EasyStep(
        customStep: CircleAvatar(
          backgroundColor: _getStepColor(0),
        ),
        title: '待付款',
      ),
      EasyStep(
        customStep: CircleAvatar(
          backgroundColor: _getStepColor(1),
        ),
        title: '已付款',
        topTitle: true,
      ),
      EasyStep(
        customStep: CircleAvatar(
          backgroundColor: _getStepColor(2),
        ),
        title: '运输中',
      ),
      EasyStep(
        customStep: CircleAvatar(
          backgroundColor: _getStepColor(3),
        ),
        title: '已收货',
        topTitle: true,
      ),
      EasyStep(
        customStep: CircleAvatar(
          backgroundColor: _getStepColor(4),
        ),
        title: '交易完成',
      ),
      EasyStep(
        customStep: CircleAvatar(
          backgroundColor: _getStepColor(5),
        ),
        title: '已评价',
        topTitle: true,
      ),
    ],
    onStepReached: (index) => setState(() => activeStep = index),
  ),
)

按照示例写一个 EasyStepper,注意需要包裹在 SingleChildScrollView 里(如果不包裹样式会有问题)。其中前面那部分参数都是配置步骤条的展示方式,具体参数说明如下:

  • direction:横向还是纵向,默认横向,如果节点比较多,推荐使用纵向,比如任务节点或者 OA 审批流转节点。
  • disableScroll:是否禁止滚动,当步骤条的内容超出宽度或高度时,默认是支持滚动的,也可以禁止滚动。
  • alignment:步骤条各个节点的对齐方式。
  • activeStep:当前活跃的步骤节点。
  • lineLength:线段长度。
  • xxColor:线条或步骤条节点文字的颜色,可以配置不同状态节点的边框、文本和线条的颜色。
  • showLoadingAnimation:是否显示 Loading 动效等等。
  • stepRadius:步骤节点的半径大小,也可以不指定,通过自定义组件实现自定义大小。
  • lineThickness:步骤线段粗细。
  • steppingEnabled:是否启用步骤节点(不启用则点击无效果),也可以在 EasyStep 里禁用单个节点。
  • enableStepTapping:步骤节点是否允许Tap,如果允许会有按压效果指示。
  • steps:一个 EasyStep 数组,可以在里面定义各个节点的组件及属性,比如标题是不是放上面(topTitle),节点使用什么组件只是。这里就可以自定义自己的节点样式。
  • onStepReached:步骤交互相应,当步骤发生变更时会调用该方法,告诉我们当前进行到了哪个步骤了。我们可以利用这个回调来更改界面或完成相应的业务逻辑。
  • lineType:正常(normal)是实线,可以绘制虚线,此时参数值为LineType.dotted
  • lineSpace:当使用虚线时(lineTypeLineType.dotted),可以指定虚线点之间的间距,如果是0那么还是会是实线。
  • padding:节点与父组件之间的内边距,可以通过这个来调节步骤条与父组件的距离。
  • internalPadding:节点之间的间距。
  • reachedSteps:当前已经达到节点(但未完成,比如节点负责人已读消息)下标集合,当节点下标在这个集合里面时,边框和标题会变颜色为完成状态颜色,但是节点自身不会。例如下面的蓝色外边框,内部是灰色圆的就是这种节点。

实际还有不少参数,大家可以看源码了解具体参数的用途。下面我们来看几个典型的示例。

使用图标作为节点

这个在电商领域比较常见,用图标代替圆点会更加简洁形象。

实现的源码是通过一个 Row组件,然后使用 Flex 布局,将上一步、下一步的按钮和步骤条放在一起。这里需要注意,如果是 Row 组件,那么步骤条需要使用Expanded包裹住。源码如下:

dart 复制代码
child: SingleChildScrollView(
  child: Row(
    mainAxisAlignment: MainAxisAlignment.spaceBetween,
    children: [
      Expanded(flex: 1, child: _previousStep(StepEnabling.individual)),
      Expanded(
        flex: 15,
        child: EasyStepper(
          activeStep: activeStep2,
          reachedSteps: reachedSteps,
          lineLength: 100,
          lineSpace: 4,
          lineType: LineType.dotted,
          activeStepBorderColor: Colors.blue,
          activeStepIconColor: Colors.blue,
          activeStepTextColor: Colors.blue,
          activeLineColor: Colors.blueGrey.withOpacity(0.5),
          activeStepBackgroundColor: Colors.white,
          unreachedStepBackgroundColor:
              Colors.blueGrey.withOpacity(0.5),
          unreachedStepBorderColor: Colors.blueGrey.withOpacity(0.5),
          unreachedStepIconColor: Colors.blueGrey,
          unreachedStepTextColor: Colors.blueGrey.withOpacity(0.5),
          unreachedLineColor: Colors.blueGrey.withOpacity(0.5),
          finishedStepBackgroundColor: Colors.pink.withOpacity(0.5),
          finishedStepBorderColor: Colors.blueGrey.withOpacity(0.5),
          finishedStepIconColor: Colors.blueGrey,
          finishedStepTextColor: Colors.pink.withOpacity(0.5),
          finishedLineColor: Colors.pink.withOpacity(0.5),
          borderThickness: 2,
          internalPadding: 15,
          showStepBorder: true,
          showLoadingAnimation: false,
          stepRadius: 20,
          // stepShape: baseStep.StepShape.rRectangle,
          showTitle: true,
          steps: [
            EasyStep(
              icon: const Icon(CupertinoIcons.cart),
              title: '购物车',
              lineText: '添加收货地址',
              enabled: _allowTabStepping(0, StepEnabling.individual),
            ),
            EasyStep(
              icon: const Icon(CupertinoIcons.info),
              title: '填写地址',
              lineText: '付款结算',
              enabled: _allowTabStepping(1, StepEnabling.individual),
            ),
            EasyStep(
              icon: const Icon(CupertinoIcons.cart_fill_badge_plus),
              title: '结算',
              lineText: '选择付款方式',
              enabled: _allowTabStepping(2, StepEnabling.individual),
            ),
            EasyStep(
              icon: const Icon(CupertinoIcons.money_dollar),
              title: '付款',
              lineText: '核对订单',
              enabled: _allowTabStepping(3, StepEnabling.individual),
            ),
            EasyStep(
              icon: const Icon(Icons.file_present_rounded),
              title: '确认订单',
              lineText: '提交订单',
              enabled: _allowTabStepping(4, StepEnabling.individual),
            ),
            EasyStep(
              icon: const Icon(Icons.check_circle_outline),
              title: '完成',
              enabled: _allowTabStepping(5, StepEnabling.individual),
            ),
          ],
          onStepReached: (index) => setState(() {
            activeStep2 = index;
          }),
        ),
      ),
      Expanded(flex: 1, child: _nextStep(StepEnabling.individual)),
    ],
  ),
  ),

这里我们也可以看到,步骤节点(EasyStep)之间的线条也是可以加文字说明的,包括标题可以放置在下方,也可以设置放置在节点上方(topTitle属性为 true)。

自定义动画

我们有时候会使用动画来标识活跃的节点,在 EasySteper 里,默认是内置了一个 loading动画,当showLoadingAnimationtrue 时,就会使用动画展示活跃的节点。如下图所示。

而实际上,是可以使用 Lottiejson 动画文件来自定义动画的,比如我自己随便下了一个 Lottie 动画替换了默认的动画。

这个时候,我们只需要配置 EasyStepper 的两个参数就行了,除了showLoadingAnimation设置为 true 之外,再把下载的 Lottie动画文件路径给loadingAnimation即可。

dart 复制代码
child: EasyStepper(
  //...
  showLoadingAnimation: true,
  loadingAnimation: 'images/animation.json',
  //...
)

结语

easy_stepper 官方还给了不少其他示例,有兴趣的可以自行去看一下。个人感受来说,这个组件是可以拿来就用的,相比自己开发的话,会更加高效。本篇的源码已经提交至Flutter 实用组件相关源码

我是岛上码农,微信公众号同名。如有问题可以加本人微信交流,微信号:island-coder

👍🏻:觉得有收获请点个赞鼓励一下!

🌟:收藏文章,方便回看哦!

💬:评论交流,互相进步!

相关推荐
崔庆才丨静觅20 分钟前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60611 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了1 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅1 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅2 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
未来侦察班2 小时前
一晃13年过去了,苹果的Airdrop依然很坚挺。
macos·ios·苹果vision pro
renke33642 小时前
Flutter for OpenHarmony:色彩捕手——基于HSL色轮与感知色差的交互式色觉训练系统
flutter
崔庆才丨静觅2 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment2 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅2 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端