如何在Flutter中创建带大型刻度标记的Slider?求完整实现代码
带大型刻度标记的Slider实现方案
如果直接通过ThemeData配置没生效,大概率是因为默认Slider的轨道样式不支持自定义刻度,需要通过自定义SliderTrackShape来实现,同时结合SliderTheme来统一样式。以下是完整的可运行代码:
import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData( primarySwatch: Colors.blue, ), home: const SliderWithMarkersPage(), ); } } class SliderWithMarkersPage extends StatefulWidget { const SliderWithMarkersPage({super.key}); @override State<SliderWithMarkersPage> createState() => _SliderWithMarkersPageState(); } class _SliderWithMarkersPageState extends State<SliderWithMarkersPage> { double _currentValue = 50; final int _minValue = 0; final int _maxValue = 100; final int _markerInterval = 10; // 刻度间隔 @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("带大型刻度的Slider")), body: Padding( padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 64), child: Column( children: [ SliderTheme( data: SliderTheme.of(context).copyWith( trackHeight: 8, // 轨道高度,放大刻度显示 activeTrackColor: Colors.blueAccent, inactiveTrackColor: Colors.grey.shade300, thumbColor: Colors.blue, thumbShape: const RoundSliderThumbShape(enabledThumbRadius: 12), // 放大滑块 // 使用自定义轨道形状绘制刻度 trackShape: CustomSliderTrackShape( markerInterval: _markerInterval, minValue: _minValue, maxValue: _maxValue, ), ), child: Slider( min: _minValue.toDouble(), max: _maxValue.toDouble(), divisions: (_maxValue - _minValue) ~/ _markerInterval, value: _currentValue, onChanged: (value) { setState(() { _currentValue = value; }); }, ), ), const SizedBox(height: 16), Text("当前值: ${_currentValue.toInt()}"), ], ), ), ); } } // 自定义Slider轨道形状,添加大型刻度标记 class CustomSliderTrackShape extends RoundedRectSliderTrackShape { final int markerInterval; final int minValue; final int maxValue; CustomSliderTrackShape({ required this.markerInterval, required this.minValue, required this.maxValue, }); @override void paint(PaintingContext context, Offset offset, {required RenderBox parentBox, required SliderThemeData sliderTheme, required Animation<double> enableAnimation, required TextDirection textDirection, required Offset thumbCenter, bool isDiscrete = false, bool isEnabled = false, double additionalActiveTrackHeight = 2}) { // 先绘制默认轨道 super.paint( context, offset, parentBox: parentBox, sliderTheme: sliderTheme, enableAnimation: enableAnimation, textDirection: textDirection, thumbCenter: thumbCenter, isDiscrete: isDiscrete, isEnabled: isEnabled, additionalActiveTrackHeight: additionalActiveTrackHeight, ); final Canvas canvas = context.canvas; final trackRect = getPreferredRect( parentBox: parentBox, offset: offset, sliderTheme: sliderTheme, isEnabled: isEnabled, isDiscrete: isDiscrete, ); // 计算刻度数量和位置 int markerCount = ((maxValue - minValue) / markerInterval) + 1; double trackWidth = trackRect.width; double markerStep = trackWidth / (markerCount - 1); // 绘制刻度标记 Paint markerPaint = Paint() ..color = Colors.blueAccent ..strokeWidth = 3; for (int i = 0; i < markerCount; i++) { double xPos = trackRect.left + markerStep * i; // 大型刻度:超出轨道上下方 canvas.drawLine( Offset(xPos, trackRect.top - 8), Offset(xPos, trackRect.bottom + 8), markerPaint, ); // 可选:绘制刻度数值 TextPainter textPainter = TextPainter( text: TextSpan( text: "${minValue + i * markerInterval}", style: const TextStyle(color: Colors.black, fontSize: 12), ), textDirection: textDirection, textAlign: TextAlign.center, )..layout(); textPainter.paint( canvas, Offset(xPos - textPainter.width / 2, trackRect.bottom + 12), ); } } }
代码说明:
- CustomSliderTrackShape:继承自默认的轨道形状,在绘制完默认轨道后,额外绘制大型刻度标记,刻度超出轨道上下范围,视觉上更突出。
- SliderTheme配置:放大了轨道高度、滑块大小,确保整体样式和刻度匹配;通过
divisions参数让滑块自动吸附到刻度位置。 - 刻度数值:可选添加了刻度下方的数值标签,不需要可以删除相关代码。
如果之前用ThemeData没生效,是因为默认的SliderTheme并没有提供直接配置刻度的参数,必须通过自定义轨道形状来实现。
内容的提问来源于stack exchange,提问作者seyyed javad
相关产品推荐
相关产品推荐

