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

4,286 阅读5分钟

前言

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

image.png

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

easy_stepper 简介

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

stepper-horizontal.gif

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

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:当前已经达到节点(但未完成,比如节点负责人已读消息)下标集合,当节点下标在这个集合里面时,边框和标题会变颜色为完成状态颜色,但是节点自身不会。例如下面的蓝色外边框,内部是灰色圆的就是这种节点。

image.png

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

使用图标作为节点

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

图标步骤条.gif

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

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 时,就会使用动画展示活跃的节点。如下图所示。

loading.gif

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

zidingyi.gif

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

child: EasyStepper(
  //...
  showLoadingAnimation: true,
  loadingAnimation: 'images/animation.json',
  //...
)

结语

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

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

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

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

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