You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 10:57:22