Flutter 里的 Slider 组件类似 Android 里的 SeekBar 组件,中间有一个滑块,可以滑动选择进度。最近在使用 Slider 组件时确碰到一个问题,具体如下图所示:
图中可以看到,组件上面有一个个等分的点,刚开始还以为是什么属性配置错误了,后来通过研究官方文档以及源码发现,这叫tickMark
,俗称刻度
。但是我只想要一个单纯的滑动条,并不想要在上面显示刻度,找了一圈发现 Slider 并没有属性可以控制这个。
后来经过一番查找,发现可以通过 SliderTheme
来改变 Slider
组件的一些默认属性,里面恰好有 activeTickMarkColor
、inactiveTickMarkColor
、tickMarkShape
是与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;
});
}));
最终效果如下:
除此外,我们还可以自定义一个类来继承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;
});
}))