Flutter Slider 组件隐藏刻度

Flutter 里的 Slider 组件类似 Android 里的 SeekBar 组件,中间有一个滑块,可以滑动选择进度。最近在使用 Slider 组件时确碰到一个问题,具体如下图所示:


Slider带有刻度

图中可以看到,组件上面有一个个等分的点,刚开始还以为是什么属性配置错误了,后来通过研究官方文档以及源码发现,这叫tickMark,俗称刻度。但是我只想要一个单纯的滑动条,并不想要在上面显示刻度,找了一圈发现 Slider 并没有属性可以控制这个。

后来经过一番查找,发现可以通过 SliderTheme 来改变 Slider 组件的一些默认属性,里面恰好有 activeTickMarkColorinactiveTickMarkColortickMarkShape是与tickMark相关的。于是想到 将 tickMarkColor 配置成透明色不就不显示刻度了么,试验了一下如下代码:

  SliderTheme(
    data: SliderTheme.of(context).copyWith(
        activeTickMarkColor: Colors.transparent,
        inactiveTickMarkColor: Colors.transparent
      ),
    child: Slider(
        min: 1, max: 100, value: _value, divisions: 10, 
        activeColor: Colors.red,
        inactiveColor: Colors.grey,
        onChanged: (value) {
          setState(() {
            _value = value;
          });
        }));

结果很遗憾,一点效果都没有(有知道原因的可以共享下),无论设置成啥颜色都不起作用。

于是,目光只能投向tickMarkShape,看描述是来绘制tickMark形状的,其类型为SliderTickMarkShape,默认的实现有RoundSliderTickMarkShape,看其源码其核心就有一个paint 方法,里面就是用来绘制tickMark的:

@override
  void paint(
    PaintingContext context,
    Offset center, {
    required RenderBox parentBox,
    required SliderThemeData sliderTheme,
    required Animation<double> enableAnimation,
    required TextDirection textDirection,
    required Offset thumbCenter,
    required bool isEnabled,
  }) {
    assert(context != null);
    assert(center != null);
    assert(parentBox != null);
    assert(sliderTheme != null);
    assert(sliderTheme.disabledActiveTickMarkColor != null);
    assert(sliderTheme.disabledInactiveTickMarkColor != null);
    assert(sliderTheme.activeTickMarkColor != null);
    assert(sliderTheme.inactiveTickMarkColor != null);
    assert(enableAnimation != null);
    assert(textDirection != null);
    assert(thumbCenter != null);
    assert(isEnabled != null);
    // The paint color of the tick mark depends on its position relative
    // to the thumb and the text direction.
    Color? begin;
    Color? end;
    switch (textDirection) {
      case TextDirection.ltr:
        final bool isTickMarkRightOfThumb = center.dx > thumbCenter.dx;
        begin = isTickMarkRightOfThumb ? sliderTheme.disabledInactiveTickMarkColor : sliderTheme.disabledActiveTickMarkColor;
        end = isTickMarkRightOfThumb ? sliderTheme.inactiveTickMarkColor : sliderTheme.activeTickMarkColor;
        break;
      case TextDirection.rtl:
        final bool isTickMarkLeftOfThumb = center.dx < thumbCenter.dx;
        begin = isTickMarkLeftOfThumb ? sliderTheme.disabledInactiveTickMarkColor : sliderTheme.disabledActiveTickMarkColor;
        end = isTickMarkLeftOfThumb ? sliderTheme.inactiveTickMarkColor : sliderTheme.activeTickMarkColor;
        break;
    }
    final Paint paint = Paint()..color = ColorTween(begin: begin, end: end).evaluate(enableAnimation)!;

    // The tick marks are tiny circles that are the same height as the track.
    final double tickMarkRadius = getPreferredSize(
       isEnabled: isEnabled,
       sliderTheme: sliderTheme,
     ).width / 2;
    if (tickMarkRadius > 0) {
      context.canvas.drawCircle(center, tickMarkRadius, paint);
    }
  }

上面可以看到只有当 tickMarkRadius > 0 时,才会绘制一个圆圈,为了不让显示tickMark我们只需将tickMarkRadius设置成 <=0 就可以了,最终设置如下:

SliderTheme(
    data: SliderTheme.of(context).copyWith(
        //这里 tickMarkRadius 设置成 0 即可
        tickMarkShape: const RoundSliderTickMarkShape(tickMarkRadius: 0)
      ),
    child: Slider(
        min: 1, max: 100, value: _value, divisions: 10, 
        activeColor: Colors.red,
        inactiveColor: Colors.grey,
        onChanged: (value) {
          setState(() {
            _value = value;
          });
        }));

最终效果如下:


tick2.png

除此外,我们还可以自定义一个类来继承SliderTickMarkShape,在paint方法里什么都不做,同样可以达到一样的效果,代码如下:

class TransparentSliderTickMarkShape extends SliderTickMarkShape {
  @override
  Size getPreferredSize({required SliderThemeData sliderTheme, required bool isEnabled}) {
    return const Size(0, 0);
  }

  @override
  void paint(PaintingContext context, Offset center, {required RenderBox parentBox, required SliderThemeData sliderTheme, required Animation<double> enableAnimation, required Offset thumbCenter, required bool isEnabled, required TextDirection textDirection}) {
    
  }

}

SliderTheme(
      data: SliderTheme.of(context).copyWith(
          activeTickMarkColor: Colors.transparent,
          inactiveTickMarkColor: Colors.transparent,
          tickMarkShape: TransparentSliderTickMarkShape()
        ),
      child: Slider(
          min: 1, max: 100, value: _value, divisions: 10, 
          activeColor: Colors.red,
          inactiveColor: Colors.grey,
          onChanged: (value) {
            setState(() {
              _value = value;
            });
          }))
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容