1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/// @docImport 'color_scheme.dart';
6/// @docImport 'range_slider.dart';
7/// @docImport 'text_theme.dart';
8library;
9
10import 'dart:ui' show lerpDouble;
11
12import 'package:flutter/foundation.dart';
13import 'package:flutter/rendering.dart';
14import 'package:flutter/widgets.dart';
15
16import 'colors.dart';
17import 'material_state.dart';
18import 'range_slider_parts.dart';
19import 'slider.dart';
20import 'slider_parts.dart';
21import 'slider_value_indicator_shape.dart';
22import 'theme.dart';
23
24/// Applies a slider theme to descendant [Slider] widgets.
25///
26/// A slider theme describes the colors and shape choices of the slider
27/// components.
28///
29/// Descendant widgets obtain the current theme's [SliderThemeData] object using
30/// [SliderTheme.of]. When a widget uses [SliderTheme.of], it is automatically
31/// rebuilt if the theme later changes.
32///
33/// The slider is as big as the largest of
34/// the [SliderComponentShape.getPreferredSize] of the thumb shape,
35/// the [SliderComponentShape.getPreferredSize] of the overlay shape,
36/// and the [SliderTickMarkShape.getPreferredSize] of the tick mark shape.
37///
38/// See also:
39///
40/// * [SliderThemeData], which describes the actual configuration of a slider
41/// theme.
42/// * [SliderComponentShape], which can be used to create custom shapes for
43/// the [Slider]'s thumb, overlay, and value indicator and the
44/// [RangeSlider]'s overlay.
45/// * [SliderTrackShape], which can be used to create custom shapes for the
46/// [Slider]'s track.
47/// * [SliderTickMarkShape], which can be used to create custom shapes for the
48/// [Slider]'s tick marks.
49/// * [RangeSliderThumbShape], which can be used to create custom shapes for
50/// the [RangeSlider]'s thumb.
51/// * [RangeSliderValueIndicatorShape], which can be used to create custom
52/// shapes for the [RangeSlider]'s value indicator.
53/// * [RangeSliderTrackShape], which can be used to create custom shapes for
54/// the [RangeSlider]'s track.
55/// * [RangeSliderTickMarkShape], which can be used to create custom shapes for
56/// the [RangeSlider]'s tick marks.
57class SliderTheme extends InheritedTheme {
58 /// Applies the given theme [data] to [child].
59 const SliderTheme({super.key, required this.data, required super.child});
60
61 /// Specifies the color and shape values for descendant slider widgets.
62 final SliderThemeData data;
63
64 /// Returns the data from the closest [SliderTheme] instance that encloses
65 /// the given context.
66 ///
67 /// Defaults to the ambient [ThemeData.sliderTheme] if there is no
68 /// [SliderTheme] in the given build context.
69 ///
70 /// {@tool snippet}
71 ///
72 /// ```dart
73 /// class Launch extends StatefulWidget {
74 /// const Launch({super.key});
75 ///
76 /// @override
77 /// State createState() => LaunchState();
78 /// }
79 ///
80 /// class LaunchState extends State<Launch> {
81 /// double _rocketThrust = 0;
82 ///
83 /// @override
84 /// Widget build(BuildContext context) {
85 /// return SliderTheme(
86 /// data: SliderTheme.of(context).copyWith(activeTrackColor: const Color(0xff804040)),
87 /// child: Slider(
88 /// onChanged: (double value) { setState(() { _rocketThrust = value; }); },
89 /// value: _rocketThrust,
90 /// ),
91 /// );
92 /// }
93 /// }
94 /// ```
95 /// {@end-tool}
96 ///
97 /// See also:
98 ///
99 /// * [SliderThemeData], which describes the actual configuration of a slider
100 /// theme.
101 static SliderThemeData of(BuildContext context) {
102 final SliderTheme? inheritedTheme = context.dependOnInheritedWidgetOfExactType<SliderTheme>();
103 return inheritedTheme != null ? inheritedTheme.data : Theme.of(context).sliderTheme;
104 }
105
106 @override
107 Widget wrap(BuildContext context, Widget child) {
108 return SliderTheme(data: data, child: child);
109 }
110
111 @override
112 bool updateShouldNotify(SliderTheme oldWidget) => data != oldWidget.data;
113}
114
115/// Describes the conditions under which the value indicator on a [Slider]
116/// will be shown. Used with [SliderThemeData.showValueIndicator].
117///
118/// See also:
119///
120/// * [Slider], a Material Design slider widget.
121/// * [SliderThemeData], which describes the actual configuration of a slider
122/// theme.
123enum ShowValueIndicator {
124 /// The value indicator will only be shown while dragging for discrete sliders (sliders
125 /// where [Slider.divisions] is non-null).
126 onlyForDiscrete,
127
128 /// The value indicator will only be shown while dragging for continuous sliders (sliders
129 /// where [Slider.divisions] is null).
130 onlyForContinuous,
131
132 /// The value indicator is shown while dragging.
133 @Deprecated(
134 'Use ShowValueIndicator.onDrag. '
135 'This feature was deprecated after v3.28.0-1.0.pre.',
136 )
137 always,
138
139 /// The value indicator is shown while dragging.
140 onDrag,
141
142 /// The value indicator is always displayed.
143 alwaysVisible,
144
145 /// The value indicator will never be shown.
146 never,
147}
148
149/// Identifier for a thumb.
150///
151/// There are 2 thumbs in a [RangeSlider], [start] and [end].
152///
153/// For [TextDirection.ltr], the [start] thumb is the left-most thumb and the
154/// [end] thumb is the right-most thumb. For [TextDirection.rtl] the [start]
155/// thumb is the right-most thumb, and the [end] thumb is the left-most thumb.
156enum Thumb {
157 /// Left-most thumb for [TextDirection.ltr], otherwise, right-most thumb.
158 start,
159
160 /// Right-most thumb for [TextDirection.ltr], otherwise, left-most thumb.
161 end,
162}
163
164/// Holds the color, shape, and typography values for a Material Design slider
165/// theme.
166///
167/// Use this class to configure a [SliderTheme] widget, or to set the
168/// [ThemeData.sliderTheme] for a [Theme] widget.
169///
170/// To obtain the current ambient slider theme, use [SliderTheme.of].
171///
172/// This theme is for both the [Slider] and the [RangeSlider]. The properties
173/// that are only for the [Slider] are: [tickMarkShape], [thumbShape],
174/// [trackShape], and [valueIndicatorShape]. The properties that are only for
175/// the [RangeSlider] are [rangeTickMarkShape], [rangeThumbShape],
176/// [rangeTrackShape], [rangeValueIndicatorShape],
177/// [overlappingShapeStrokeColor], [minThumbSeparation], and [thumbSelector].
178/// All other properties are used by both the [Slider] and the [RangeSlider].
179///
180/// The parts of a slider are:
181///
182/// * The "thumb", which is a shape that slides horizontally when the user
183/// drags it.
184/// * The "track", which is the line that the slider thumb slides along.
185/// * The "tick marks", which are regularly spaced marks that are drawn when
186/// using discrete divisions.
187/// * The "value indicator", which appears when the user is dragging the thumb
188/// to indicate the value being selected.
189/// * The "overlay", which appears around the thumb, and is shown when the
190/// thumb is pressed, focused, or hovered. It is painted underneath the
191/// thumb, so it must extend beyond the bounds of the thumb itself to
192/// actually be visible.
193/// * The "active" side of the slider is the side between the thumb and the
194/// minimum value.
195/// * The "inactive" side of the slider is the side between the thumb and the
196/// maximum value.
197/// * The [Slider] is disabled when it is not accepting user input. See
198/// [Slider] for details on when this happens.
199///
200/// The thumb, track, tick marks, value indicator, and overlay can be customized
201/// by creating subclasses of [SliderTrackShape],
202/// [SliderComponentShape], and/or [SliderTickMarkShape]. See
203/// [RoundSliderThumbShape], [RectangularSliderTrackShape],
204/// [RoundSliderTickMarkShape], [RectangularSliderValueIndicatorShape], and
205/// [RoundSliderOverlayShape] for examples.
206///
207/// The track painting can be skipped by specifying 0 for [trackHeight].
208/// The thumb painting can be skipped by specifying
209/// [SliderComponentShape.noThumb] for [SliderThemeData.thumbShape].
210/// The overlay painting can be skipped by specifying
211/// [SliderComponentShape.noOverlay] for [SliderThemeData.overlayShape].
212/// The tick mark painting can be skipped by specifying
213/// [SliderTickMarkShape.noTickMark] for [SliderThemeData.tickMarkShape].
214/// The value indicator painting can be skipped by specifying the
215/// appropriate [ShowValueIndicator] for [SliderThemeData.showValueIndicator].
216///
217/// See also:
218///
219/// * [SliderTheme] widget, which can override the slider theme of its
220/// children.
221/// * [Theme] widget, which performs a similar function to [SliderTheme],
222/// but for overall themes.
223/// * [ThemeData], which has a default [SliderThemeData].
224/// * [SliderComponentShape], which can be used to create custom shapes for
225/// the [Slider]'s thumb, overlay, and value indicator and the
226/// [RangeSlider]'s overlay.
227/// * [SliderTrackShape], which can be used to create custom shapes for the
228/// [Slider]'s track.
229/// * [SliderTickMarkShape], which can be used to create custom shapes for the
230/// [Slider]'s tick marks.
231/// * [RangeSliderThumbShape], which can be used to create custom shapes for
232/// the [RangeSlider]'s thumb.
233/// * [RangeSliderValueIndicatorShape], which can be used to create custom
234/// shapes for the [RangeSlider]'s value indicator.
235/// * [RangeSliderTrackShape], which can be used to create custom shapes for
236/// the [RangeSlider]'s track.
237/// * [RangeSliderTickMarkShape], which can be used to create custom shapes for
238/// the [RangeSlider]'s tick marks.
239@immutable
240class SliderThemeData with Diagnosticable {
241 /// Create a [SliderThemeData] given a set of exact values.
242 ///
243 /// This will rarely be used directly. It is used by [lerp] to
244 /// create intermediate themes based on two themes.
245 ///
246 /// The simplest way to create a SliderThemeData is to use
247 /// [copyWith] on the one you get from [SliderTheme.of], or create an
248 /// entirely new one with [SliderThemeData.fromPrimaryColors].
249 ///
250 /// {@tool snippet}
251 ///
252 /// ```dart
253 /// class Blissful extends StatefulWidget {
254 /// const Blissful({super.key});
255 ///
256 /// @override
257 /// State createState() => BlissfulState();
258 /// }
259 ///
260 /// class BlissfulState extends State<Blissful> {
261 /// double _bliss = 0;
262 ///
263 /// @override
264 /// Widget build(BuildContext context) {
265 /// return SliderTheme(
266 /// data: SliderTheme.of(context).copyWith(activeTrackColor: const Color(0xff404080)),
267 /// child: Slider(
268 /// onChanged: (double value) { setState(() { _bliss = value; }); },
269 /// value: _bliss,
270 /// ),
271 /// );
272 /// }
273 /// }
274 /// ```
275 /// {@end-tool}
276 const SliderThemeData({
277 this.trackHeight,
278 this.activeTrackColor,
279 this.inactiveTrackColor,
280 this.secondaryActiveTrackColor,
281 this.disabledActiveTrackColor,
282 this.disabledInactiveTrackColor,
283 this.disabledSecondaryActiveTrackColor,
284 this.activeTickMarkColor,
285 this.inactiveTickMarkColor,
286 this.disabledActiveTickMarkColor,
287 this.disabledInactiveTickMarkColor,
288 this.thumbColor,
289 this.overlappingShapeStrokeColor,
290 this.disabledThumbColor,
291 this.overlayColor,
292 this.valueIndicatorColor,
293 this.valueIndicatorStrokeColor,
294 this.overlayShape,
295 this.tickMarkShape,
296 this.thumbShape,
297 this.trackShape,
298 this.valueIndicatorShape,
299 this.rangeTickMarkShape,
300 this.rangeThumbShape,
301 this.rangeTrackShape,
302 this.rangeValueIndicatorShape,
303 this.showValueIndicator,
304 this.valueIndicatorTextStyle,
305 this.minThumbSeparation,
306 this.thumbSelector,
307 this.mouseCursor,
308 this.allowedInteraction,
309 this.padding,
310 this.thumbSize,
311 this.trackGap,
312 @Deprecated(
313 'Set this flag to false to opt into the 2024 slider appearance. Defaults to true. '
314 'In the future, this flag will default to false. Use SliderThemeData to customize individual properties. '
315 'This feature was deprecated after v3.27.0-0.2.pre.',
316 )
317 this.year2023,
318 });
319
320 /// Generates a SliderThemeData from three main colors.
321 ///
322 /// Usually these are the primary, dark and light colors from
323 /// a [ThemeData].
324 ///
325 /// The opacities of these colors will be overridden with the Material Design
326 /// defaults when assigning them to the slider theme component colors.
327 ///
328 /// This is used to generate the default slider theme for a [ThemeData].
329 factory SliderThemeData.fromPrimaryColors({
330 required Color primaryColor,
331 required Color primaryColorDark,
332 required Color primaryColorLight,
333 required TextStyle valueIndicatorTextStyle,
334 }) {
335 // These are Material Design defaults, and are used to derive
336 // component Colors (with opacity) from base colors.
337 const int activeTrackAlpha = 0xff;
338 const int inactiveTrackAlpha = 0x3d; // 24% opacity
339 const int secondaryActiveTrackAlpha = 0x8a; // 54% opacity
340 const int disabledActiveTrackAlpha = 0x52; // 32% opacity
341 const int disabledInactiveTrackAlpha = 0x1f; // 12% opacity
342 const int disabledSecondaryActiveTrackAlpha = 0x1f; // 12% opacity
343 const int activeTickMarkAlpha = 0x8a; // 54% opacity
344 const int inactiveTickMarkAlpha = 0x8a; // 54% opacity
345 const int disabledActiveTickMarkAlpha = 0x1f; // 12% opacity
346 const int disabledInactiveTickMarkAlpha = 0x1f; // 12% opacity
347 const int thumbAlpha = 0xff;
348 const int disabledThumbAlpha = 0x52; // 32% opacity
349 const int overlayAlpha = 0x1f; // 12% opacity
350 const int valueIndicatorAlpha = 0xff;
351
352 return SliderThemeData(
353 trackHeight: 2.0,
354 activeTrackColor: primaryColor.withAlpha(activeTrackAlpha),
355 inactiveTrackColor: primaryColor.withAlpha(inactiveTrackAlpha),
356 secondaryActiveTrackColor: primaryColor.withAlpha(secondaryActiveTrackAlpha),
357 disabledActiveTrackColor: primaryColorDark.withAlpha(disabledActiveTrackAlpha),
358 disabledInactiveTrackColor: primaryColorDark.withAlpha(disabledInactiveTrackAlpha),
359 disabledSecondaryActiveTrackColor: primaryColorDark.withAlpha(
360 disabledSecondaryActiveTrackAlpha,
361 ),
362 activeTickMarkColor: primaryColorLight.withAlpha(activeTickMarkAlpha),
363 inactiveTickMarkColor: primaryColor.withAlpha(inactiveTickMarkAlpha),
364 disabledActiveTickMarkColor: primaryColorLight.withAlpha(disabledActiveTickMarkAlpha),
365 disabledInactiveTickMarkColor: primaryColorDark.withAlpha(disabledInactiveTickMarkAlpha),
366 thumbColor: primaryColor.withAlpha(thumbAlpha),
367 overlappingShapeStrokeColor: Colors.white,
368 disabledThumbColor: primaryColorDark.withAlpha(disabledThumbAlpha),
369 overlayColor: primaryColor.withAlpha(overlayAlpha),
370 valueIndicatorColor: primaryColor.withAlpha(valueIndicatorAlpha),
371 valueIndicatorStrokeColor: primaryColor.withAlpha(valueIndicatorAlpha),
372 overlayShape: const RoundSliderOverlayShape(),
373 tickMarkShape: const RoundSliderTickMarkShape(),
374 thumbShape: const RoundSliderThumbShape(),
375 trackShape: const RoundedRectSliderTrackShape(),
376 valueIndicatorShape: const PaddleSliderValueIndicatorShape(),
377 rangeTickMarkShape: const RoundRangeSliderTickMarkShape(),
378 rangeThumbShape: const RoundRangeSliderThumbShape(),
379 rangeTrackShape: const RoundedRectRangeSliderTrackShape(),
380 rangeValueIndicatorShape: const PaddleRangeSliderValueIndicatorShape(),
381 valueIndicatorTextStyle: valueIndicatorTextStyle,
382 showValueIndicator: ShowValueIndicator.onlyForDiscrete,
383 );
384 }
385
386 /// The height of the [Slider] track.
387 final double? trackHeight;
388
389 /// The color of the [Slider] track between the [Slider.min] position and the
390 /// current thumb position.
391 final Color? activeTrackColor;
392
393 /// The color of the [Slider] track between the current thumb position and the
394 /// [Slider.max] position.
395 final Color? inactiveTrackColor;
396
397 /// The color of the [Slider] track between the current thumb position and the
398 /// [Slider.secondaryTrackValue] position.
399 final Color? secondaryActiveTrackColor;
400
401 /// The color of the [Slider] track between the [Slider.min] position and the
402 /// current thumb position when the [Slider] is disabled.
403 final Color? disabledActiveTrackColor;
404
405 /// The color of the [Slider] track between the current thumb position and the
406 /// [Slider.secondaryTrackValue] position when the [Slider] is disabled.
407 final Color? disabledSecondaryActiveTrackColor;
408
409 /// The color of the [Slider] track between the current thumb position and the
410 /// [Slider.max] position when the [Slider] is disabled.
411 final Color? disabledInactiveTrackColor;
412
413 /// The color of the track's tick marks that are drawn between the [Slider.min]
414 /// position and the current thumb position.
415 final Color? activeTickMarkColor;
416
417 /// The color of the track's tick marks that are drawn between the current
418 /// thumb position and the [Slider.max] position.
419 final Color? inactiveTickMarkColor;
420
421 /// The color of the track's tick marks that are drawn between the [Slider.min]
422 /// position and the current thumb position when the [Slider] is disabled.
423 final Color? disabledActiveTickMarkColor;
424
425 /// The color of the track's tick marks that are drawn between the current
426 /// thumb position and the [Slider.max] position when the [Slider] is
427 /// disabled.
428 final Color? disabledInactiveTickMarkColor;
429
430 /// The color given to the [thumbShape] to draw itself with.
431 final Color? thumbColor;
432
433 /// The color given to the perimeter of the top [rangeThumbShape] when the
434 /// thumbs are overlapping and the top [rangeValueIndicatorShape] when the
435 /// value indicators are overlapping.
436 final Color? overlappingShapeStrokeColor;
437
438 /// The color given to the [thumbShape] to draw itself with when the
439 /// [Slider] is disabled.
440 final Color? disabledThumbColor;
441
442 /// The color of the overlay drawn around the slider thumb when it is
443 /// pressed, focused, or hovered.
444 ///
445 /// This is typically a semi-transparent color.
446 final Color? overlayColor;
447
448 /// The color given to the [valueIndicatorShape] to draw itself with.
449 final Color? valueIndicatorColor;
450
451 /// The color given to the [valueIndicatorShape] stroke.
452 final Color? valueIndicatorStrokeColor;
453
454 /// The shape that will be used to draw the [Slider]'s overlay.
455 ///
456 /// Both the [overlayColor] and a non default [overlayShape] may be specified.
457 /// The default [overlayShape] refers to the [overlayColor].
458 ///
459 /// The default value is [RoundSliderOverlayShape].
460 final SliderComponentShape? overlayShape;
461
462 /// The shape that will be used to draw the [Slider]'s tick marks.
463 ///
464 /// The [SliderTickMarkShape.getPreferredSize] is used to help determine the
465 /// location of each tick mark on the track. The slider's minimum size will
466 /// be at least this big.
467 ///
468 /// The default value is [RoundSliderTickMarkShape].
469 ///
470 /// See also:
471 ///
472 /// * [RoundRangeSliderTickMarkShape], which is the default tick mark
473 /// shape for the range slider.
474 final SliderTickMarkShape? tickMarkShape;
475
476 /// The shape that will be used to draw the [Slider]'s thumb.
477 ///
478 /// The default value is [RoundSliderThumbShape].
479 ///
480 /// See also:
481 ///
482 /// * [RoundRangeSliderThumbShape], which is the default thumb shape for
483 /// the [RangeSlider].
484 final SliderComponentShape? thumbShape;
485
486 /// The shape that will be used to draw the [Slider]'s track.
487 ///
488 /// The [SliderTrackShape.getPreferredRect] method is used to map
489 /// slider-relative gesture coordinates to the correct thumb position on the
490 /// track. It is also used to horizontally position tick marks, when the
491 /// slider is discrete.
492 ///
493 /// The default value is [RoundedRectSliderTrackShape].
494 ///
495 /// See also:
496 ///
497 /// * [RoundedRectRangeSliderTrackShape], which is the default track
498 /// shape for the [RangeSlider].
499 final SliderTrackShape? trackShape;
500
501 /// The shape that will be used to draw the [Slider]'s value
502 /// indicator.
503 ///
504 /// The default value is [PaddleSliderValueIndicatorShape].
505 ///
506 /// See also:
507 ///
508 /// * [PaddleRangeSliderValueIndicatorShape], which is the default value
509 /// indicator shape for the [RangeSlider].
510 final SliderComponentShape? valueIndicatorShape;
511
512 /// The shape that will be used to draw the [RangeSlider]'s tick marks.
513 ///
514 /// The [RangeSliderTickMarkShape.getPreferredSize] is used to help determine
515 /// the location of each tick mark on the track. The slider's minimum size
516 /// will be at least this big.
517 ///
518 /// The default value is [RoundRangeSliderTickMarkShape].
519 ///
520 /// See also:
521 ///
522 /// * [RoundSliderTickMarkShape], which is the default tick mark shape
523 /// for the [Slider].
524 final RangeSliderTickMarkShape? rangeTickMarkShape;
525
526 /// The shape that will be used for the [RangeSlider]'s thumbs.
527 ///
528 /// By default the same shape is used for both thumbs, but strokes the top
529 /// thumb when it overlaps the bottom thumb. The top thumb is always the last
530 /// selected thumb.
531 ///
532 /// The default value is [RoundRangeSliderThumbShape].
533 ///
534 /// See also:
535 ///
536 /// * [RoundSliderThumbShape], which is the default thumb shape for the
537 /// [Slider].
538 final RangeSliderThumbShape? rangeThumbShape;
539
540 /// The shape that will be used to draw the [RangeSlider]'s track.
541 ///
542 /// The [SliderTrackShape.getPreferredRect] method is used to map
543 /// slider-relative gesture coordinates to the correct thumb position on the
544 /// track. It is also used to horizontally position the tick marks, when the
545 /// slider is discrete.
546 ///
547 /// The default value is [RoundedRectRangeSliderTrackShape].
548 ///
549 /// See also:
550 ///
551 /// * [RoundedRectSliderTrackShape], which is the default track
552 /// shape for the [Slider].
553 final RangeSliderTrackShape? rangeTrackShape;
554
555 /// The shape that will be used for the [RangeSlider]'s value indicators.
556 ///
557 /// The default shape uses the same value indicator for each thumb, but
558 /// strokes the top value indicator when it overlaps the bottom value
559 /// indicator. The top indicator corresponds to the top thumb, which is always
560 /// the most recently selected thumb.
561 ///
562 /// The default value is [PaddleRangeSliderValueIndicatorShape].
563 ///
564 /// See also:
565 ///
566 /// * [PaddleSliderValueIndicatorShape], which is the default value
567 /// indicator shape for the [Slider].
568 final RangeSliderValueIndicatorShape? rangeValueIndicatorShape;
569
570 /// Whether the value indicator should be shown for different types of
571 /// sliders.
572 ///
573 /// By default, [showValueIndicator] is set to
574 /// [ShowValueIndicator.onlyForDiscrete]. The value indicator is only shown
575 /// when the thumb is being touched.
576 final ShowValueIndicator? showValueIndicator;
577
578 /// The text style for the text on the value indicator.
579 final TextStyle? valueIndicatorTextStyle;
580
581 /// Limits the thumb's separation distance.
582 ///
583 /// Use this only if you want to control the visual appearance of the thumbs
584 /// in terms of a logical pixel value. This can be done when you want a
585 /// specific look for thumbs when they are close together. To limit with the
586 /// real values, rather than logical pixels, the values can be restricted by
587 /// the parent.
588 final double? minThumbSeparation;
589
590 /// Determines which thumb should be selected when the slider is interacted
591 /// with.
592 ///
593 /// If null, the default thumb selector finds the closest thumb, excluding
594 /// taps that are between the thumbs and not within any one touch target.
595 /// When the selection is within the touch target bounds of both thumbs, no
596 /// thumb is selected until the selection is moved.
597 ///
598 /// Override this for custom thumb selection.
599 final RangeThumbSelector? thumbSelector;
600
601 /// {@macro flutter.material.slider.mouseCursor}
602 ///
603 /// If specified, overrides the default value of [Slider.mouseCursor].
604 final MaterialStateProperty<MouseCursor?>? mouseCursor;
605
606 /// Allowed way for the user to interact with the [Slider].
607 ///
608 /// If specified, overrides the default value of [Slider.allowedInteraction].
609 final SliderInteraction? allowedInteraction;
610
611 /// Determines the padding around the [Slider].
612 ///
613 /// If specified, this padding overrides the default vertical padding of
614 /// the [Slider], defaults to the height of the overlay shape, and the
615 /// horizontal padding, defaults to the width of the thumb shape or
616 /// overlay shape, whichever is larger.
617 final EdgeInsetsGeometry? padding;
618
619 /// The size of the [HandleThumbShape] thumb.
620 ///
621 /// If [SliderThemeData.thumbShape] is [HandleThumbShape], this property is used to
622 /// set the size of the thumb. Otherwise, the default thumb size is 4 pixels for the
623 /// width and 44 pixels for the height.
624 final MaterialStateProperty<Size?>? thumbSize;
625
626 /// The size of the gap between the active and inactive tracks of the [GappedSliderTrackShape].
627 ///
628 /// If [SliderThemeData.trackShape] is [GappedSliderTrackShape], this property
629 /// is used to set the gap between the active and inactive tracks. Otherwise,
630 /// the default gap size is 6.0 pixels.
631 ///
632 /// The Slider defaults to [GappedSliderTrackShape] when the track shape is
633 /// not specified, and the [trackGap] can be used to adjust the gap size.
634 ///
635 /// If [Slider.year2023] is false or [ThemeData.useMaterial3] is false, then
636 /// the Slider track shape defaults to [RoundedRectSliderTrackShape] and the
637 /// [trackGap] is ignored. In this case, set the track shape to
638 /// [GappedSliderTrackShape] to use the [trackGap].
639 ///
640 /// Defaults to 6.0 pixels of gap between the active and inactive tracks.
641 final double? trackGap;
642
643 /// Overrides the default value of [Slider.year2023] and [RangeSlider.year2023].
644 ///
645 /// When true, the [Slider] and [RangeSlider] will use the 2023 Material Design 3 appearance.
646 /// Defaults to true.
647 ///
648 /// If this is set to false, the [Slider] and [RangeSlider] will use the latest Material Design 3
649 /// appearance, which was introduced in December 2023.
650 ///
651 /// If [ThemeData.useMaterial3] is false, then this property is ignored.
652 @Deprecated(
653 'Set this flag to false to opt into the 2024 slider appearance. Defaults to true. '
654 'In the future, this flag will default to false. Use SliderThemeData to customize individual properties. '
655 'This feature was deprecated after v3.27.0-0.2.pre.',
656 )
657 final bool? year2023;
658
659 /// Creates a copy of this object but with the given fields replaced with the
660 /// new values.
661 SliderThemeData copyWith({
662 double? trackHeight,
663 Color? activeTrackColor,
664 Color? inactiveTrackColor,
665 Color? secondaryActiveTrackColor,
666 Color? disabledActiveTrackColor,
667 Color? disabledInactiveTrackColor,
668 Color? disabledSecondaryActiveTrackColor,
669 Color? activeTickMarkColor,
670 Color? inactiveTickMarkColor,
671 Color? disabledActiveTickMarkColor,
672 Color? disabledInactiveTickMarkColor,
673 Color? thumbColor,
674 Color? overlappingShapeStrokeColor,
675 Color? disabledThumbColor,
676 Color? overlayColor,
677 Color? valueIndicatorColor,
678 Color? valueIndicatorStrokeColor,
679 SliderComponentShape? overlayShape,
680 SliderTickMarkShape? tickMarkShape,
681 SliderComponentShape? thumbShape,
682 SliderTrackShape? trackShape,
683 SliderComponentShape? valueIndicatorShape,
684 RangeSliderTickMarkShape? rangeTickMarkShape,
685 RangeSliderThumbShape? rangeThumbShape,
686 RangeSliderTrackShape? rangeTrackShape,
687 RangeSliderValueIndicatorShape? rangeValueIndicatorShape,
688 ShowValueIndicator? showValueIndicator,
689 TextStyle? valueIndicatorTextStyle,
690 double? minThumbSeparation,
691 RangeThumbSelector? thumbSelector,
692 MaterialStateProperty<MouseCursor?>? mouseCursor,
693 SliderInteraction? allowedInteraction,
694 EdgeInsetsGeometry? padding,
695 MaterialStateProperty<Size?>? thumbSize,
696 double? trackGap,
697 bool? year2023,
698 }) {
699 return SliderThemeData(
700 trackHeight: trackHeight ?? this.trackHeight,
701 activeTrackColor: activeTrackColor ?? this.activeTrackColor,
702 inactiveTrackColor: inactiveTrackColor ?? this.inactiveTrackColor,
703 secondaryActiveTrackColor: secondaryActiveTrackColor ?? this.secondaryActiveTrackColor,
704 disabledActiveTrackColor: disabledActiveTrackColor ?? this.disabledActiveTrackColor,
705 disabledInactiveTrackColor: disabledInactiveTrackColor ?? this.disabledInactiveTrackColor,
706 disabledSecondaryActiveTrackColor:
707 disabledSecondaryActiveTrackColor ?? this.disabledSecondaryActiveTrackColor,
708 activeTickMarkColor: activeTickMarkColor ?? this.activeTickMarkColor,
709 inactiveTickMarkColor: inactiveTickMarkColor ?? this.inactiveTickMarkColor,
710 disabledActiveTickMarkColor: disabledActiveTickMarkColor ?? this.disabledActiveTickMarkColor,
711 disabledInactiveTickMarkColor:
712 disabledInactiveTickMarkColor ?? this.disabledInactiveTickMarkColor,
713 thumbColor: thumbColor ?? this.thumbColor,
714 overlappingShapeStrokeColor: overlappingShapeStrokeColor ?? this.overlappingShapeStrokeColor,
715 disabledThumbColor: disabledThumbColor ?? this.disabledThumbColor,
716 overlayColor: overlayColor ?? this.overlayColor,
717 valueIndicatorColor: valueIndicatorColor ?? this.valueIndicatorColor,
718 valueIndicatorStrokeColor: valueIndicatorStrokeColor ?? this.valueIndicatorStrokeColor,
719 overlayShape: overlayShape ?? this.overlayShape,
720 tickMarkShape: tickMarkShape ?? this.tickMarkShape,
721 thumbShape: thumbShape ?? this.thumbShape,
722 trackShape: trackShape ?? this.trackShape,
723 valueIndicatorShape: valueIndicatorShape ?? this.valueIndicatorShape,
724 rangeTickMarkShape: rangeTickMarkShape ?? this.rangeTickMarkShape,
725 rangeThumbShape: rangeThumbShape ?? this.rangeThumbShape,
726 rangeTrackShape: rangeTrackShape ?? this.rangeTrackShape,
727 rangeValueIndicatorShape: rangeValueIndicatorShape ?? this.rangeValueIndicatorShape,
728 showValueIndicator: showValueIndicator ?? this.showValueIndicator,
729 valueIndicatorTextStyle: valueIndicatorTextStyle ?? this.valueIndicatorTextStyle,
730 minThumbSeparation: minThumbSeparation ?? this.minThumbSeparation,
731 thumbSelector: thumbSelector ?? this.thumbSelector,
732 mouseCursor: mouseCursor ?? this.mouseCursor,
733 allowedInteraction: allowedInteraction ?? this.allowedInteraction,
734 padding: padding ?? this.padding,
735 thumbSize: thumbSize ?? this.thumbSize,
736 trackGap: trackGap ?? this.trackGap,
737 year2023: year2023 ?? this.year2023,
738 );
739 }
740
741 /// Linearly interpolate between two slider themes.
742 ///
743 /// {@macro dart.ui.shadow.lerp}
744 static SliderThemeData lerp(SliderThemeData a, SliderThemeData b, double t) {
745 if (identical(a, b)) {
746 return a;
747 }
748 return SliderThemeData(
749 trackHeight: lerpDouble(a.trackHeight, b.trackHeight, t),
750 activeTrackColor: Color.lerp(a.activeTrackColor, b.activeTrackColor, t),
751 inactiveTrackColor: Color.lerp(a.inactiveTrackColor, b.inactiveTrackColor, t),
752 secondaryActiveTrackColor: Color.lerp(
753 a.secondaryActiveTrackColor,
754 b.secondaryActiveTrackColor,
755 t,
756 ),
757 disabledActiveTrackColor: Color.lerp(
758 a.disabledActiveTrackColor,
759 b.disabledActiveTrackColor,
760 t,
761 ),
762 disabledInactiveTrackColor: Color.lerp(
763 a.disabledInactiveTrackColor,
764 b.disabledInactiveTrackColor,
765 t,
766 ),
767 disabledSecondaryActiveTrackColor: Color.lerp(
768 a.disabledSecondaryActiveTrackColor,
769 b.disabledSecondaryActiveTrackColor,
770 t,
771 ),
772 activeTickMarkColor: Color.lerp(a.activeTickMarkColor, b.activeTickMarkColor, t),
773 inactiveTickMarkColor: Color.lerp(a.inactiveTickMarkColor, b.inactiveTickMarkColor, t),
774 disabledActiveTickMarkColor: Color.lerp(
775 a.disabledActiveTickMarkColor,
776 b.disabledActiveTickMarkColor,
777 t,
778 ),
779 disabledInactiveTickMarkColor: Color.lerp(
780 a.disabledInactiveTickMarkColor,
781 b.disabledInactiveTickMarkColor,
782 t,
783 ),
784 thumbColor: Color.lerp(a.thumbColor, b.thumbColor, t),
785 overlappingShapeStrokeColor: Color.lerp(
786 a.overlappingShapeStrokeColor,
787 b.overlappingShapeStrokeColor,
788 t,
789 ),
790 disabledThumbColor: Color.lerp(a.disabledThumbColor, b.disabledThumbColor, t),
791 overlayColor: Color.lerp(a.overlayColor, b.overlayColor, t),
792 valueIndicatorColor: Color.lerp(a.valueIndicatorColor, b.valueIndicatorColor, t),
793 valueIndicatorStrokeColor: Color.lerp(
794 a.valueIndicatorStrokeColor,
795 b.valueIndicatorStrokeColor,
796 t,
797 ),
798 overlayShape: t < 0.5 ? a.overlayShape : b.overlayShape,
799 tickMarkShape: t < 0.5 ? a.tickMarkShape : b.tickMarkShape,
800 thumbShape: t < 0.5 ? a.thumbShape : b.thumbShape,
801 trackShape: t < 0.5 ? a.trackShape : b.trackShape,
802 valueIndicatorShape: t < 0.5 ? a.valueIndicatorShape : b.valueIndicatorShape,
803 rangeTickMarkShape: t < 0.5 ? a.rangeTickMarkShape : b.rangeTickMarkShape,
804 rangeThumbShape: t < 0.5 ? a.rangeThumbShape : b.rangeThumbShape,
805 rangeTrackShape: t < 0.5 ? a.rangeTrackShape : b.rangeTrackShape,
806 rangeValueIndicatorShape: t < 0.5 ? a.rangeValueIndicatorShape : b.rangeValueIndicatorShape,
807 showValueIndicator: t < 0.5 ? a.showValueIndicator : b.showValueIndicator,
808 valueIndicatorTextStyle: TextStyle.lerp(
809 a.valueIndicatorTextStyle,
810 b.valueIndicatorTextStyle,
811 t,
812 ),
813 minThumbSeparation: lerpDouble(a.minThumbSeparation, b.minThumbSeparation, t),
814 thumbSelector: t < 0.5 ? a.thumbSelector : b.thumbSelector,
815 mouseCursor: t < 0.5 ? a.mouseCursor : b.mouseCursor,
816 allowedInteraction: t < 0.5 ? a.allowedInteraction : b.allowedInteraction,
817 padding: EdgeInsetsGeometry.lerp(a.padding, b.padding, t),
818 thumbSize: MaterialStateProperty.lerp<Size?>(a.thumbSize, b.thumbSize, t, Size.lerp),
819 trackGap: lerpDouble(a.trackGap, b.trackGap, t),
820 year2023: t < 0.5 ? a.year2023 : b.year2023,
821 );
822 }
823
824 @override
825 int get hashCode => Object.hash(
826 trackHeight,
827 activeTrackColor,
828 inactiveTrackColor,
829 secondaryActiveTrackColor,
830 disabledActiveTrackColor,
831 disabledInactiveTrackColor,
832 disabledSecondaryActiveTrackColor,
833 activeTickMarkColor,
834 inactiveTickMarkColor,
835 disabledActiveTickMarkColor,
836 disabledInactiveTickMarkColor,
837 thumbColor,
838 overlappingShapeStrokeColor,
839 disabledThumbColor,
840 overlayColor,
841 valueIndicatorColor,
842 overlayShape,
843 tickMarkShape,
844 thumbShape,
845 Object.hash(
846 trackShape,
847 valueIndicatorShape,
848 rangeTickMarkShape,
849 rangeThumbShape,
850 rangeTrackShape,
851 rangeValueIndicatorShape,
852 showValueIndicator,
853 valueIndicatorTextStyle,
854 minThumbSeparation,
855 thumbSelector,
856 mouseCursor,
857 allowedInteraction,
858 padding,
859 thumbSize,
860 trackGap,
861 year2023,
862 ),
863 );
864
865 @override
866 bool operator ==(Object other) {
867 if (identical(this, other)) {
868 return true;
869 }
870 if (other.runtimeType != runtimeType) {
871 return false;
872 }
873 return other is SliderThemeData &&
874 other.trackHeight == trackHeight &&
875 other.activeTrackColor == activeTrackColor &&
876 other.inactiveTrackColor == inactiveTrackColor &&
877 other.secondaryActiveTrackColor == secondaryActiveTrackColor &&
878 other.disabledActiveTrackColor == disabledActiveTrackColor &&
879 other.disabledInactiveTrackColor == disabledInactiveTrackColor &&
880 other.disabledSecondaryActiveTrackColor == disabledSecondaryActiveTrackColor &&
881 other.activeTickMarkColor == activeTickMarkColor &&
882 other.inactiveTickMarkColor == inactiveTickMarkColor &&
883 other.disabledActiveTickMarkColor == disabledActiveTickMarkColor &&
884 other.disabledInactiveTickMarkColor == disabledInactiveTickMarkColor &&
885 other.thumbColor == thumbColor &&
886 other.overlappingShapeStrokeColor == overlappingShapeStrokeColor &&
887 other.disabledThumbColor == disabledThumbColor &&
888 other.overlayColor == overlayColor &&
889 other.valueIndicatorColor == valueIndicatorColor &&
890 other.valueIndicatorStrokeColor == valueIndicatorStrokeColor &&
891 other.overlayShape == overlayShape &&
892 other.tickMarkShape == tickMarkShape &&
893 other.thumbShape == thumbShape &&
894 other.trackShape == trackShape &&
895 other.valueIndicatorShape == valueIndicatorShape &&
896 other.rangeTickMarkShape == rangeTickMarkShape &&
897 other.rangeThumbShape == rangeThumbShape &&
898 other.rangeTrackShape == rangeTrackShape &&
899 other.rangeValueIndicatorShape == rangeValueIndicatorShape &&
900 other.showValueIndicator == showValueIndicator &&
901 other.valueIndicatorTextStyle == valueIndicatorTextStyle &&
902 other.minThumbSeparation == minThumbSeparation &&
903 other.thumbSelector == thumbSelector &&
904 other.mouseCursor == mouseCursor &&
905 other.allowedInteraction == allowedInteraction &&
906 other.padding == padding &&
907 other.thumbSize == thumbSize &&
908 other.trackGap == trackGap &&
909 other.year2023 == year2023;
910 }
911
912 @override
913 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
914 super.debugFillProperties(properties);
915 const SliderThemeData defaultData = SliderThemeData();
916 properties.add(
917 DoubleProperty('trackHeight', trackHeight, defaultValue: defaultData.trackHeight),
918 );
919 properties.add(
920 ColorProperty(
921 'activeTrackColor',
922 activeTrackColor,
923 defaultValue: defaultData.activeTrackColor,
924 ),
925 );
926 properties.add(
927 ColorProperty(
928 'inactiveTrackColor',
929 inactiveTrackColor,
930 defaultValue: defaultData.inactiveTrackColor,
931 ),
932 );
933 properties.add(
934 ColorProperty(
935 'secondaryActiveTrackColor',
936 secondaryActiveTrackColor,
937 defaultValue: defaultData.secondaryActiveTrackColor,
938 ),
939 );
940 properties.add(
941 ColorProperty(
942 'disabledActiveTrackColor',
943 disabledActiveTrackColor,
944 defaultValue: defaultData.disabledActiveTrackColor,
945 ),
946 );
947 properties.add(
948 ColorProperty(
949 'disabledInactiveTrackColor',
950 disabledInactiveTrackColor,
951 defaultValue: defaultData.disabledInactiveTrackColor,
952 ),
953 );
954 properties.add(
955 ColorProperty(
956 'disabledSecondaryActiveTrackColor',
957 disabledSecondaryActiveTrackColor,
958 defaultValue: defaultData.disabledSecondaryActiveTrackColor,
959 ),
960 );
961 properties.add(
962 ColorProperty(
963 'activeTickMarkColor',
964 activeTickMarkColor,
965 defaultValue: defaultData.activeTickMarkColor,
966 ),
967 );
968 properties.add(
969 ColorProperty(
970 'inactiveTickMarkColor',
971 inactiveTickMarkColor,
972 defaultValue: defaultData.inactiveTickMarkColor,
973 ),
974 );
975 properties.add(
976 ColorProperty(
977 'disabledActiveTickMarkColor',
978 disabledActiveTickMarkColor,
979 defaultValue: defaultData.disabledActiveTickMarkColor,
980 ),
981 );
982 properties.add(
983 ColorProperty(
984 'disabledInactiveTickMarkColor',
985 disabledInactiveTickMarkColor,
986 defaultValue: defaultData.disabledInactiveTickMarkColor,
987 ),
988 );
989 properties.add(ColorProperty('thumbColor', thumbColor, defaultValue: defaultData.thumbColor));
990 properties.add(
991 ColorProperty(
992 'overlappingShapeStrokeColor',
993 overlappingShapeStrokeColor,
994 defaultValue: defaultData.overlappingShapeStrokeColor,
995 ),
996 );
997 properties.add(
998 ColorProperty(
999 'disabledThumbColor',
1000 disabledThumbColor,
1001 defaultValue: defaultData.disabledThumbColor,
1002 ),
1003 );
1004 properties.add(
1005 ColorProperty('overlayColor', overlayColor, defaultValue: defaultData.overlayColor),
1006 );
1007 properties.add(
1008 ColorProperty(
1009 'valueIndicatorColor',
1010 valueIndicatorColor,
1011 defaultValue: defaultData.valueIndicatorColor,
1012 ),
1013 );
1014 properties.add(
1015 ColorProperty(
1016 'valueIndicatorStrokeColor',
1017 valueIndicatorStrokeColor,
1018 defaultValue: defaultData.valueIndicatorStrokeColor,
1019 ),
1020 );
1021 properties.add(
1022 DiagnosticsProperty<SliderComponentShape>(
1023 'overlayShape',
1024 overlayShape,
1025 defaultValue: defaultData.overlayShape,
1026 ),
1027 );
1028 properties.add(
1029 DiagnosticsProperty<SliderTickMarkShape>(
1030 'tickMarkShape',
1031 tickMarkShape,
1032 defaultValue: defaultData.tickMarkShape,
1033 ),
1034 );
1035 properties.add(
1036 DiagnosticsProperty<SliderComponentShape>(
1037 'thumbShape',
1038 thumbShape,
1039 defaultValue: defaultData.thumbShape,
1040 ),
1041 );
1042 properties.add(
1043 DiagnosticsProperty<SliderTrackShape>(
1044 'trackShape',
1045 trackShape,
1046 defaultValue: defaultData.trackShape,
1047 ),
1048 );
1049 properties.add(
1050 DiagnosticsProperty<SliderComponentShape>(
1051 'valueIndicatorShape',
1052 valueIndicatorShape,
1053 defaultValue: defaultData.valueIndicatorShape,
1054 ),
1055 );
1056 properties.add(
1057 DiagnosticsProperty<RangeSliderTickMarkShape>(
1058 'rangeTickMarkShape',
1059 rangeTickMarkShape,
1060 defaultValue: defaultData.rangeTickMarkShape,
1061 ),
1062 );
1063 properties.add(
1064 DiagnosticsProperty<RangeSliderThumbShape>(
1065 'rangeThumbShape',
1066 rangeThumbShape,
1067 defaultValue: defaultData.rangeThumbShape,
1068 ),
1069 );
1070 properties.add(
1071 DiagnosticsProperty<RangeSliderTrackShape>(
1072 'rangeTrackShape',
1073 rangeTrackShape,
1074 defaultValue: defaultData.rangeTrackShape,
1075 ),
1076 );
1077 properties.add(
1078 DiagnosticsProperty<RangeSliderValueIndicatorShape>(
1079 'rangeValueIndicatorShape',
1080 rangeValueIndicatorShape,
1081 defaultValue: defaultData.rangeValueIndicatorShape,
1082 ),
1083 );
1084 properties.add(
1085 EnumProperty<ShowValueIndicator>(
1086 'showValueIndicator',
1087 showValueIndicator,
1088 defaultValue: defaultData.showValueIndicator,
1089 ),
1090 );
1091 properties.add(
1092 DiagnosticsProperty<TextStyle>(
1093 'valueIndicatorTextStyle',
1094 valueIndicatorTextStyle,
1095 defaultValue: defaultData.valueIndicatorTextStyle,
1096 ),
1097 );
1098 properties.add(
1099 DoubleProperty(
1100 'minThumbSeparation',
1101 minThumbSeparation,
1102 defaultValue: defaultData.minThumbSeparation,
1103 ),
1104 );
1105 properties.add(
1106 DiagnosticsProperty<RangeThumbSelector>(
1107 'thumbSelector',
1108 thumbSelector,
1109 defaultValue: defaultData.thumbSelector,
1110 ),
1111 );
1112 properties.add(
1113 DiagnosticsProperty<MaterialStateProperty<MouseCursor?>>(
1114 'mouseCursor',
1115 mouseCursor,
1116 defaultValue: defaultData.mouseCursor,
1117 ),
1118 );
1119 properties.add(
1120 EnumProperty<SliderInteraction>(
1121 'allowedInteraction',
1122 allowedInteraction,
1123 defaultValue: defaultData.allowedInteraction,
1124 ),
1125 );
1126 properties.add(
1127 DiagnosticsProperty<EdgeInsetsGeometry>(
1128 'padding',
1129 padding,
1130 defaultValue: defaultData.padding,
1131 ),
1132 );
1133 properties.add(
1134 DiagnosticsProperty<MaterialStateProperty<Size?>>(
1135 'thumbSize',
1136 thumbSize,
1137 defaultValue: defaultData.thumbSize,
1138 ),
1139 );
1140 properties.add(DoubleProperty('trackGap', trackGap, defaultValue: defaultData.trackGap));
1141 properties.add(
1142 DiagnosticsProperty<bool>('year2023', year2023, defaultValue: defaultData.year2023),
1143 );
1144 }
1145}
1146
1147/// A callback that formats a numeric value from a [Slider] or [RangeSlider] widget.
1148///
1149/// See also:
1150///
1151/// * [Slider.semanticFormatterCallback], which shows an example use case.
1152/// * [RangeSlider.semanticFormatterCallback], which shows an example use case.
1153typedef SemanticFormatterCallback = String Function(double value);
1154