第二百二十一回

我们在上一章回中介绍了"如何绘制阴影效果"相关的内容,本章回中将介绍如何自定义一个可以滑动的刻度尺.闲话休提,让我们一起Talk Flutter吧。

1. 概念介绍

任何优美的文字在图形面前都显得苍白无力,因此我们先先上效果图。图中演示了一个可以滑动的刻度尺,图形中左侧的文字表示刻度值,右侧蓝色的线条表示刻度线,
刻度线上的圆脸图标表示滑动条,它可以在刻度线上滑动,滑动时左侧的刻度值会发生变化。我们将在本章回中介绍如何去实现图片中的刻度尺效果。

2. 思路与方法

2.1 实现思路

实现图中的效果需要使用自定义组件相关的知识,详细内容可以查看我们前面的博客。我们先把上面图片的内容做一个拆分:左侧显示刻度值的文本使用Text来实现,滑
块是一个图片,使用Iamge或者Icon来实现。刻度尺可以通过Container来实现,或者通过CustomPainter来绘制。滑动滑块是一个手势动作,通过手势组件来实现。
通过拆分后就会发现原来看着很复杂的效果一下子变成了常用的组件。拆分后的内容还需要进行组装,这样才能组成一个完整的组件,组装这些内容可以通过stack组件来
实现。上面描述的这些内容就是我们实现滑动刻度尺的思路,看似复杂的滑动刻度尺效果就在这一拆一合之间实现了,是不是感觉很优美?

2.2 实现方法

有了实现的思路就有了大体的目标和方向,接下来我们就一步一个脚印地朝着目标方向前进。这一个个的脚印就是具体的实现方法:

  1. 创建一个Stack组件,用来组合各个子组件;
  2. 创建显示刻度值的Text组件,它的位置通过Positioned组件控制;
  3. 创建显示滑块的Icon组件,它的位置是通过Positioned组件控制;
  4. 创建显示刻度线的Container组件,它用来显示最右侧的垂直线条;
  5. 在Container添加ListView组件,它用来显示小的刻度线;
  6. 在Stack组件外层嵌套GestureDetector组件,通过该组件的onPanUpdate属性来控制滑块移动;
    上面的介绍的实现方法中,我们重点介绍一下第5个方法:最开始我们想通过CustomPainter来绘制线条,感觉太麻烦,于是想到了ListView,它里面的每一个子项目就
    是刻度线之间的间隔,在子项目之间添加分隔线用来充当刻度线,分隔线使用Divider组件实现。这样设计有两个优点:
  • 可以通过子项目的大小灵活控制刻度线之间的间隔;
  • 可以通过Divider灵活控制刻度线的长度和宽度以及颜色;

3. 示例代码

GestureDetector(
  child: Container(
    color: Colors.black12,
    width: widget.width,
    height: widget.height,

    child: Stack(
      alignment: Alignment.center,
      children: [
        Positioned(
          left: textLeft,
          top: textTop,
          child: Text("${_currentValue.toInt().toString().padLeft(2, "0")} : 00"),
        ),
        Positioned(
          left: rulerLeft,
          top: rulerTop,

          ///整个刻度尺
          child: Container(
            ///控制刻度尺右侧的线
            decoration: const BoxDecoration(
              color: Colors.transparent,
              border:Border(
                right: BorderSide(color: Colors.black,width: 2,),
              ),

            ),
            ///整个刻度尺的长度和宽度
            width: ruleWidth,
            height: ruleHeight,

            ///使用ListView的divider来充当刻度线
            child: ListView(
              controller: scrollController,
              ///通过List中item的高度控制刻度线之间的间隔
              itemExtent: space,
              children: List.generate(lineCount, (index) {
                if(index %2 != 0 ) {
                  return Container(
                    ///这个颜色需要和整个组件的背景颜色一样,或者做成透明色
                    color: Colors.transparent,
                    child: const SizedBox.shrink(),
                  );
                }else {
                  return const Divider(
                    ///线的宽度
                    thickness: lineHeight,
                    ///总宽度减去此值为线的长度
                    indent: lineWidth,
                    color: Colors.blue,
                  );
                }
              }),
            ),
          ),
        ),
        ///滑块
        Positioned(
          top: value,
          left: thumbLeft,
            child: Container(
              color: Colors.transparent,
              child: const Icon(Icons.face,color: Colors.redAccent,),
            ), ),
      ],
    ),
  ),

  onPanUpdate: (event) {
    setState(() {
      value += event.delta.dy;
      _currentValue = value;
      ///转换滑动值为刻度值,
    });
  },
);

上面的示例代码中完整地演示了整个实现方法中的内容,不过还有一些细节需要说明:每个子组件的位置都是通完Ponsitioned组件控制的,具体的位置值也就是代码中
的top和left的数值可以自行指定,只要不超过外层组件大小就可以;ListView中每个项目的内容不重要,代码中设置了一个空组件,重要的是它的颜色,需要和组件
的背景颜色一致,或者指定成透明色。滑动的内容我们指定成了Icon,也可以指定成Image,或者设置成Widget,通过参数来设置Widget的内容;

4. 内容总结

最后,我们对本章回的内容做一个全面的总结,同时给大家分享一些经验:

  • 滑动的刻度尺寸可以拆分成各个子组件逐个实现,实现完成后再进行组合;
  • 自定义组件时优先考虑通过组合组件的方式来实现相关功能,实在无法实现时再考虑使用CustomPainter组件;
  • 自定义组件时可以把一些可变的内容做参数,这样灵活方便,比如示例代码中组件的长度和宽度,以及滑块的内容;
    看官们,与"自定义可以滑动的刻度尺"相关的内容就介绍到这里,欢迎大家在评论区交流与讨论!

你可能感兴趣的:(一起Talk,Flutter吧,前端,移动开发Flutter)