Unverified Commit 519a5783 authored by Akshdeep Singh's avatar Akshdeep Singh Committed by GitHub

add material slider secondary value (#109808)

parent 1b8fb4c0
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flutter code sample for Slider
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: const MyStatefulWidget(),
),
);
}
}
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({super.key});
@override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
double _currentSliderPrimaryValue = 0.2;
double _currentSliderSecondaryValue = 0.5;
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Slider(
value: _currentSliderPrimaryValue,
secondaryTrackValue: _currentSliderSecondaryValue,
label: _currentSliderPrimaryValue.round().toString(),
onChanged: (double value) {
setState(() {
_currentSliderPrimaryValue = value;
});
},
),
Slider(
value: _currentSliderSecondaryValue,
label: _currentSliderSecondaryValue.round().toString(),
onChanged: (double value) {
setState(() {
_currentSliderSecondaryValue = value;
});
},
),
],
);
}
}
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
import 'package:flutter_api_samples/material/slider/slider.1.dart' as example;
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Slider shows secondary track', (WidgetTester tester) async {
await tester.pumpWidget(
const example.MyApp(),
);
expect(find.byType(Slider), findsNWidgets(2));
final Finder slider1Finder = find.byType(Slider).at(0);
final Finder slider2Finder = find.byType(Slider).at(1);
Slider slider1 = tester.widget(slider1Finder);
Slider slider2 = tester.widget(slider2Finder);
expect(slider1.secondaryTrackValue, slider2.value);
const double targetValue = 0.8;
final Rect rect = tester.getRect(slider2Finder);
final Offset target = Offset(rect.left + (rect.right - rect.left) * targetValue, rect.top + (rect.bottom - rect.top) / 2);
await tester.tapAt(target);
await tester.pump();
slider1 = tester.widget(slider1Finder);
slider2 = tester.widget(slider2Finder);
expect(slider1.secondaryTrackValue, closeTo(targetValue, 0.05));
expect(slider1.secondaryTrackValue, slider2.value);
});
}
......@@ -48,6 +48,13 @@ enum _SliderType { material, adaptive }
/// ** See code in examples/api/lib/material/slider/slider.0.dart **
/// {@end-tool}
///
/// {@tool dartpad}
/// This example shows a [Slider] widget using the [Slider.secondaryTrackValue]
/// to show a secondary track in the slider.
///
/// ** See code in examples/api/lib/material/slider/slider.1.dart **
/// {@end-tool}
///
/// A slider can be used to select from either a continuous or a discrete set of
/// values. The default is to use a continuous range of values from [min] to
/// [max]. To use discrete values, use a non-null value for [divisions], which
......@@ -125,6 +132,7 @@ class Slider extends StatefulWidget {
const Slider({
super.key,
required this.value,
this.secondaryTrackValue,
required this.onChanged,
this.onChangeStart,
this.onChangeEnd,
......@@ -134,6 +142,7 @@ class Slider extends StatefulWidget {
this.label,
this.activeColor,
this.inactiveColor,
this.secondaryActiveColor,
this.thumbColor,
this.mouseCursor,
this.semanticFormatterCallback,
......@@ -146,6 +155,8 @@ class Slider extends StatefulWidget {
assert(min <= max),
assert(value >= min && value <= max,
'Value $value is not between minimum $min and maximum $max'),
assert(secondaryTrackValue == null || (secondaryTrackValue >= min && secondaryTrackValue <= max),
'SecondaryValue $secondaryTrackValue is not between $min and $max'),
assert(divisions == null || divisions > 0);
/// Creates an adaptive [Slider] based on the target platform, following
......@@ -155,13 +166,15 @@ class Slider extends StatefulWidget {
/// Creates a [CupertinoSlider] if the target platform is iOS or macOS, creates a
/// Material Design slider otherwise.
///
/// If a [CupertinoSlider] is created, the following parameters are
/// ignored: [label], [inactiveColor], [semanticFormatterCallback].
/// If a [CupertinoSlider] is created, the following parameters are ignored:
/// [secondaryTrackValue], [label], [inactiveColor], [secondaryActiveColor],
/// [semanticFormatterCallback].
///
/// The target platform is based on the current [Theme]: [ThemeData.platform].
const Slider.adaptive({
super.key,
required this.value,
this.secondaryTrackValue,
required this.onChanged,
this.onChangeStart,
this.onChangeEnd,
......@@ -172,6 +185,7 @@ class Slider extends StatefulWidget {
this.mouseCursor,
this.activeColor,
this.inactiveColor,
this.secondaryActiveColor,
this.thumbColor,
this.semanticFormatterCallback,
this.focusNode,
......@@ -181,7 +195,10 @@ class Slider extends StatefulWidget {
assert(min != null),
assert(max != null),
assert(min <= max),
assert(value >= min && value <= max),
assert(value >= min && value <= max,
'Value $value is not between minimum $min and maximum $max'),
assert(secondaryTrackValue == null || (secondaryTrackValue >= min && secondaryTrackValue <= max),
'SecondaryValue $secondaryTrackValue is not between $min and $max'),
assert(divisions == null || divisions > 0);
/// The currently selected value for this slider.
......@@ -189,6 +206,17 @@ class Slider extends StatefulWidget {
/// The slider's thumb is drawn at a position that corresponds to this value.
final double value;
/// The secondary track value for this slider.
///
/// If not null, a secondary track using [Slider.secondaryActiveColor] color
/// is drawn between the thumb and this value, over the inactive track.
///
/// If less than [Slider.value], then the secondary track is not shown.
///
/// It can be ideal for media scenarios such as showing the buffering progress
/// while the [Slider.value] shows the play progress.
final double? secondaryTrackValue;
/// Called during a drag when the user is selecting a new value for the slider
/// by dragging.
///
......@@ -365,6 +393,18 @@ class Slider extends StatefulWidget {
/// Ignored if this slider is created with [Slider.adaptive].
final Color? inactiveColor;
/// The color to use for the portion of the slider track between the thumb and
/// the [Slider.secondaryTrackValue].
///
/// Defaults to the [SliderThemeData.secondaryActiveTrackColor] of the current
/// [SliderTheme].
///
/// Using a [SliderTheme] gives much more fine-grained control over the
/// appearance of various components of the slider.
///
/// Ignored if this slider is created with [Slider.adaptive].
final Color? secondaryActiveColor;
/// The color of the thumb.
///
/// If this color is null:
......@@ -443,6 +483,7 @@ class Slider extends StatefulWidget {
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(DoubleProperty('value', value));
properties.add(DoubleProperty('secondaryTrackValue', secondaryTrackValue));
properties.add(ObjectFlagProperty<ValueChanged<double>>('onChanged', onChanged, ifNull: 'disabled'));
properties.add(ObjectFlagProperty<ValueChanged<double>>.has('onChangeStart', onChangeStart));
properties.add(ObjectFlagProperty<ValueChanged<double>>.has('onChangeEnd', onChangeEnd));
......@@ -452,6 +493,7 @@ class Slider extends StatefulWidget {
properties.add(StringProperty('label', label));
properties.add(ColorProperty('activeColor', activeColor));
properties.add(ColorProperty('inactiveColor', inactiveColor));
properties.add(ColorProperty('secondaryActiveColor', secondaryActiveColor));
properties.add(ObjectFlagProperty<ValueChanged<double>>.has('semanticFormatterCallback', semanticFormatterCallback));
properties.add(ObjectFlagProperty<FocusNode>.has('focusNode', focusNode));
properties.add(FlagProperty('autofocus', value: autofocus, ifTrue: 'autofocus'));
......@@ -708,8 +750,10 @@ class _SliderState extends State<Slider> with TickerProviderStateMixin {
trackHeight: sliderTheme.trackHeight ?? defaultTrackHeight,
activeTrackColor: widget.activeColor ?? sliderTheme.activeTrackColor ?? theme.colorScheme.primary,
inactiveTrackColor: widget.inactiveColor ?? sliderTheme.inactiveTrackColor ?? theme.colorScheme.primary.withOpacity(0.24),
secondaryActiveTrackColor: widget.secondaryActiveColor ?? sliderTheme.secondaryActiveTrackColor ?? theme.colorScheme.primary.withOpacity(0.54),
disabledActiveTrackColor: sliderTheme.disabledActiveTrackColor ?? theme.colorScheme.onSurface.withOpacity(0.32),
disabledInactiveTrackColor: sliderTheme.disabledInactiveTrackColor ?? theme.colorScheme.onSurface.withOpacity(0.12),
disabledSecondaryActiveTrackColor: sliderTheme.disabledSecondaryActiveTrackColor ?? theme.colorScheme.onSurface.withOpacity(0.12),
activeTickMarkColor: widget.inactiveColor ?? sliderTheme.activeTickMarkColor ?? theme.colorScheme.onPrimary.withOpacity(0.54),
inactiveTickMarkColor: widget.activeColor ?? sliderTheme.inactiveTickMarkColor ?? theme.colorScheme.primary.withOpacity(0.54),
disabledActiveTickMarkColor: sliderTheme.disabledActiveTickMarkColor ?? theme.colorScheme.onPrimary.withOpacity(0.12),
......@@ -789,6 +833,7 @@ class _SliderState extends State<Slider> with TickerProviderStateMixin {
child: _SliderRenderObjectWidget(
key: _renderObjectKey,
value: _convert(widget.value),
secondaryTrackValue: (widget.secondaryTrackValue != null) ? _convert(widget.secondaryTrackValue!) : null,
divisions: widget.divisions,
label: widget.label,
sliderTheme: sliderTheme,
......@@ -852,6 +897,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget {
const _SliderRenderObjectWidget({
super.key,
required this.value,
required this.secondaryTrackValue,
required this.divisions,
required this.label,
required this.sliderTheme,
......@@ -867,6 +913,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget {
});
final double value;
final double? secondaryTrackValue;
final int? divisions;
final String? label;
final SliderThemeData sliderTheme;
......@@ -884,6 +931,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget {
_RenderSlider createRenderObject(BuildContext context) {
return _RenderSlider(
value: value,
secondaryTrackValue: secondaryTrackValue,
divisions: divisions,
label: label,
sliderTheme: sliderTheme,
......@@ -909,6 +957,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget {
// setter dependent on the `divisions`.
..divisions = divisions
..value = value
..secondaryTrackValue = secondaryTrackValue
..label = label
..sliderTheme = sliderTheme
..textScaleFactor = textScaleFactor
......@@ -930,6 +979,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget {
class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
_RenderSlider({
required double value,
required double? secondaryTrackValue,
required int? divisions,
required String? label,
required SliderThemeData sliderTheme,
......@@ -946,12 +996,14 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
required bool hovering,
required DeviceGestureSettings gestureSettings,
}) : assert(value != null && value >= 0.0 && value <= 1.0),
assert(secondaryTrackValue == null || (secondaryTrackValue >= 0.0 && secondaryTrackValue <= 1.0)),
assert(state != null),
assert(textDirection != null),
_platform = platform,
_semanticFormatterCallback = semanticFormatterCallback,
_label = label,
_value = value,
_secondaryTrackValue = secondaryTrackValue,
_divisions = divisions,
_sliderTheme = sliderTheme,
_textScaleFactor = textScaleFactor,
......@@ -1059,6 +1111,17 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
markNeedsSemanticsUpdate();
}
double? get secondaryTrackValue => _secondaryTrackValue;
double? _secondaryTrackValue;
set secondaryTrackValue(double? newValue) {
assert(newValue == null || (newValue >= 0.0 && newValue <= 1.0));
if (newValue == _secondaryTrackValue) {
return;
}
_secondaryTrackValue = newValue;
markNeedsSemanticsUpdate();
}
DeviceGestureSettings? get gestureSettings => _drag.gestureSettings;
set gestureSettings(DeviceGestureSettings? gestureSettings) {
_drag.gestureSettings = gestureSettings;
......@@ -1417,17 +1480,21 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
@override
void paint(PaintingContext context, Offset offset) {
final double value = _state.positionController.value;
final double? secondaryValue = _secondaryTrackValue;
// The visual position is the position of the thumb from 0 to 1 from left
// to right. In left to right, this is the same as the value, but it is
// reversed for right to left text.
final double visualPosition;
final double? secondaryVisualPosition;
switch (textDirection) {
case TextDirection.rtl:
visualPosition = 1.0 - value;
secondaryVisualPosition = (secondaryValue != null) ? (1.0 - secondaryValue) : null;
break;
case TextDirection.ltr:
visualPosition = value;
secondaryVisualPosition = (secondaryValue != null) ? secondaryValue : null;
break;
}
......@@ -1438,6 +1505,7 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
isDiscrete: isDiscrete,
);
final Offset thumbCenter = Offset(trackRect.left + visualPosition * trackRect.width, trackRect.center.dy);
final Offset? secondaryOffset = (secondaryVisualPosition != null) ? Offset(trackRect.left + secondaryVisualPosition * trackRect.width, trackRect.center.dy) : null;
_sliderTheme.trackShape!.paint(
context,
......@@ -1447,6 +1515,7 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
enableAnimation: _enableAnimation,
textDirection: _textDirection,
thumbCenter: thumbCenter,
secondaryOffset: secondaryOffset,
isDiscrete: isDiscrete,
isEnabled: isInteractive,
);
......
......@@ -266,8 +266,10 @@ class SliderThemeData with Diagnosticable {
this.trackHeight,
this.activeTrackColor,
this.inactiveTrackColor,
this.secondaryActiveTrackColor,
this.disabledActiveTrackColor,
this.disabledInactiveTrackColor,
this.disabledSecondaryActiveTrackColor,
this.activeTickMarkColor,
this.inactiveTickMarkColor,
this.disabledActiveTickMarkColor,
......@@ -317,8 +319,10 @@ class SliderThemeData with Diagnosticable {
// component Colors (with opacity) from base colors.
const int activeTrackAlpha = 0xff;
const int inactiveTrackAlpha = 0x3d; // 24% opacity
const int secondaryActiveTrackAlpha = 0x8a; // 54% opacity
const int disabledActiveTrackAlpha = 0x52; // 32% opacity
const int disabledInactiveTrackAlpha = 0x1f; // 12% opacity
const int disabledSecondaryActiveTrackAlpha = 0x1f; // 12% opacity
const int activeTickMarkAlpha = 0x8a; // 54% opacity
const int inactiveTickMarkAlpha = 0x8a; // 54% opacity
const int disabledActiveTickMarkAlpha = 0x1f; // 12% opacity
......@@ -332,8 +336,10 @@ class SliderThemeData with Diagnosticable {
trackHeight: 2.0,
activeTrackColor: primaryColor.withAlpha(activeTrackAlpha),
inactiveTrackColor: primaryColor.withAlpha(inactiveTrackAlpha),
secondaryActiveTrackColor: primaryColor.withAlpha(secondaryActiveTrackAlpha),
disabledActiveTrackColor: primaryColorDark.withAlpha(disabledActiveTrackAlpha),
disabledInactiveTrackColor: primaryColorDark.withAlpha(disabledInactiveTrackAlpha),
disabledSecondaryActiveTrackColor: primaryColorDark.withAlpha(disabledSecondaryActiveTrackAlpha),
activeTickMarkColor: primaryColorLight.withAlpha(activeTickMarkAlpha),
inactiveTickMarkColor: primaryColor.withAlpha(inactiveTickMarkAlpha),
disabledActiveTickMarkColor: primaryColorLight.withAlpha(disabledActiveTickMarkAlpha),
......@@ -368,10 +374,18 @@ class SliderThemeData with Diagnosticable {
/// [Slider.max] position.
final Color? inactiveTrackColor;
/// The color of the [Slider] track between the current thumb position and the
/// [Slider.secondaryTrackValue] position.
final Color? secondaryActiveTrackColor;
/// The color of the [Slider] track between the [Slider.min] position and the
/// current thumb position when the [Slider] is disabled.
final Color? disabledActiveTrackColor;
/// The color of the [Slider] track between the current thumb position and the
/// [Slider.secondaryTrackValue] position when the [Slider] is disabled.
final Color? disabledSecondaryActiveTrackColor;
/// The color of the [Slider] track between the current thumb position and the
/// [Slider.max] position when the [Slider] is disabled.
final Color? disabledInactiveTrackColor;
......@@ -573,8 +587,10 @@ class SliderThemeData with Diagnosticable {
double? trackHeight,
Color? activeTrackColor,
Color? inactiveTrackColor,
Color? secondaryActiveTrackColor,
Color? disabledActiveTrackColor,
Color? disabledInactiveTrackColor,
Color? disabledSecondaryActiveTrackColor,
Color? activeTickMarkColor,
Color? inactiveTickMarkColor,
Color? disabledActiveTickMarkColor,
......@@ -603,8 +619,10 @@ class SliderThemeData with Diagnosticable {
trackHeight: trackHeight ?? this.trackHeight,
activeTrackColor: activeTrackColor ?? this.activeTrackColor,
inactiveTrackColor: inactiveTrackColor ?? this.inactiveTrackColor,
secondaryActiveTrackColor: secondaryActiveTrackColor ?? this.secondaryActiveTrackColor,
disabledActiveTrackColor: disabledActiveTrackColor ?? this.disabledActiveTrackColor,
disabledInactiveTrackColor: disabledInactiveTrackColor ?? this.disabledInactiveTrackColor,
disabledSecondaryActiveTrackColor: disabledSecondaryActiveTrackColor ?? this.disabledSecondaryActiveTrackColor,
activeTickMarkColor: activeTickMarkColor ?? this.activeTickMarkColor,
inactiveTickMarkColor: inactiveTickMarkColor ?? this.inactiveTickMarkColor,
disabledActiveTickMarkColor: disabledActiveTickMarkColor ?? this.disabledActiveTickMarkColor,
......@@ -644,8 +662,10 @@ class SliderThemeData with Diagnosticable {
trackHeight: lerpDouble(a.trackHeight, b.trackHeight, t),
activeTrackColor: Color.lerp(a.activeTrackColor, b.activeTrackColor, t),
inactiveTrackColor: Color.lerp(a.inactiveTrackColor, b.inactiveTrackColor, t),
secondaryActiveTrackColor: Color.lerp(a.secondaryActiveTrackColor, b.secondaryActiveTrackColor, t),
disabledActiveTrackColor: Color.lerp(a.disabledActiveTrackColor, b.disabledActiveTrackColor, t),
disabledInactiveTrackColor: Color.lerp(a.disabledInactiveTrackColor, b.disabledInactiveTrackColor, t),
disabledSecondaryActiveTrackColor: Color.lerp(a.disabledSecondaryActiveTrackColor, b.disabledSecondaryActiveTrackColor, t),
activeTickMarkColor: Color.lerp(a.activeTickMarkColor, b.activeTickMarkColor, t),
inactiveTickMarkColor: Color.lerp(a.inactiveTickMarkColor, b.inactiveTickMarkColor, t),
disabledActiveTickMarkColor: Color.lerp(a.disabledActiveTickMarkColor, b.disabledActiveTickMarkColor, t),
......@@ -677,8 +697,10 @@ class SliderThemeData with Diagnosticable {
trackHeight,
activeTrackColor,
inactiveTrackColor,
secondaryActiveTrackColor,
disabledActiveTrackColor,
disabledInactiveTrackColor,
disabledSecondaryActiveTrackColor,
activeTickMarkColor,
inactiveTickMarkColor,
disabledActiveTickMarkColor,
......@@ -691,9 +713,9 @@ class SliderThemeData with Diagnosticable {
overlayShape,
tickMarkShape,
thumbShape,
trackShape,
valueIndicatorShape,
Object.hash(
trackShape,
valueIndicatorShape,
rangeTickMarkShape,
rangeThumbShape,
rangeTrackShape,
......@@ -718,8 +740,10 @@ class SliderThemeData with Diagnosticable {
&& other.trackHeight == trackHeight
&& other.activeTrackColor == activeTrackColor
&& other.inactiveTrackColor == inactiveTrackColor
&& other.secondaryActiveTrackColor == secondaryActiveTrackColor
&& other.disabledActiveTrackColor == disabledActiveTrackColor
&& other.disabledInactiveTrackColor == disabledInactiveTrackColor
&& other.disabledSecondaryActiveTrackColor == disabledSecondaryActiveTrackColor
&& other.activeTickMarkColor == activeTickMarkColor
&& other.inactiveTickMarkColor == inactiveTickMarkColor
&& other.disabledActiveTickMarkColor == disabledActiveTickMarkColor
......@@ -752,8 +776,10 @@ class SliderThemeData with Diagnosticable {
properties.add(DoubleProperty('trackHeight', trackHeight, defaultValue: defaultData.trackHeight));
properties.add(ColorProperty('activeTrackColor', activeTrackColor, defaultValue: defaultData.activeTrackColor));
properties.add(ColorProperty('inactiveTrackColor', inactiveTrackColor, defaultValue: defaultData.inactiveTrackColor));
properties.add(ColorProperty('secondaryActiveTrackColor', secondaryActiveTrackColor, defaultValue: defaultData.secondaryActiveTrackColor));
properties.add(ColorProperty('disabledActiveTrackColor', disabledActiveTrackColor, defaultValue: defaultData.disabledActiveTrackColor));
properties.add(ColorProperty('disabledInactiveTrackColor', disabledInactiveTrackColor, defaultValue: defaultData.disabledInactiveTrackColor));
properties.add(ColorProperty('disabledSecondaryActiveTrackColor', disabledSecondaryActiveTrackColor, defaultValue: defaultData.disabledSecondaryActiveTrackColor));
properties.add(ColorProperty('activeTickMarkColor', activeTickMarkColor, defaultValue: defaultData.activeTickMarkColor));
properties.add(ColorProperty('inactiveTickMarkColor', inactiveTickMarkColor, defaultValue: defaultData.inactiveTickMarkColor));
properties.add(ColorProperty('disabledActiveTickMarkColor', disabledActiveTickMarkColor, defaultValue: defaultData.disabledActiveTickMarkColor));
......@@ -1047,6 +1073,11 @@ abstract class SliderTrackShape {
/// relative to the origin of the [PaintingContext.canvas]. It can be used as
/// the point that divides the track into 2 segments.
///
/// The `secondaryOffset` argument is the offset of the secondary value
/// relative to the origin of the [PaintingContext.canvas].
///
/// If not null, the track is divided into 3 segments.
///
/// {@macro flutter.material.SliderTickMarkShape.getPreferredSize.isEnabled}
///
/// {@macro flutter.material.SliderComponentShape.paint.isDiscrete}
......@@ -1068,6 +1099,7 @@ abstract class SliderTrackShape {
required SliderThemeData sliderTheme,
required Animation<double> enableAnimation,
required Offset thumbCenter,
Offset? secondaryOffset,
bool isEnabled,
bool isDiscrete,
required TextDirection textDirection,
......@@ -1534,6 +1566,7 @@ class RectangularSliderTrackShape extends SliderTrackShape with BaseSliderTrackS
required Animation<double> enableAnimation,
required TextDirection textDirection,
required Offset thumbCenter,
Offset? secondaryOffset,
bool isDiscrete = false,
bool isEnabled = false,
}) {
......@@ -1593,6 +1626,25 @@ class RectangularSliderTrackShape extends SliderTrackShape with BaseSliderTrackS
if (!rightTrackSegment.isEmpty) {
context.canvas.drawRect(rightTrackSegment, rightTrackPaint);
}
final bool showSecondaryTrack = (secondaryOffset != null) &&
((textDirection == TextDirection.ltr)
? (secondaryOffset.dx > thumbCenter.dx)
: (secondaryOffset.dx < thumbCenter.dx));
if (showSecondaryTrack) {
final ColorTween secondaryTrackColorTween = ColorTween(begin: sliderTheme.disabledSecondaryActiveTrackColor, end: sliderTheme.secondaryActiveTrackColor);
final Paint secondaryTrackPaint = Paint()..color = secondaryTrackColorTween.evaluate(enableAnimation)!;
final Rect secondaryTrackSegment = Rect.fromLTRB(
(textDirection == TextDirection.ltr) ? thumbCenter.dx : secondaryOffset.dx,
trackRect.top,
(textDirection == TextDirection.ltr) ? secondaryOffset.dx : thumbCenter.dx,
trackRect.bottom,
);
if (!secondaryTrackSegment.isEmpty) {
context.canvas.drawRect(secondaryTrackSegment, secondaryTrackPaint);
}
}
}
}
......@@ -1635,6 +1687,7 @@ class RoundedRectSliderTrackShape extends SliderTrackShape with BaseSliderTrackS
required Animation<double> enableAnimation,
required TextDirection textDirection,
required Offset thumbCenter,
Offset? secondaryOffset,
bool isDiscrete = false,
bool isEnabled = false,
double additionalActiveTrackHeight = 2,
......@@ -1709,6 +1762,41 @@ class RoundedRectSliderTrackShape extends SliderTrackShape with BaseSliderTrackS
),
rightTrackPaint,
);
final bool showSecondaryTrack = (secondaryOffset != null) &&
((textDirection == TextDirection.ltr)
? (secondaryOffset.dx > thumbCenter.dx)
: (secondaryOffset.dx < thumbCenter.dx));
if (showSecondaryTrack) {
final ColorTween secondaryTrackColorTween = ColorTween(begin: sliderTheme.disabledSecondaryActiveTrackColor, end: sliderTheme.secondaryActiveTrackColor);
final Paint secondaryTrackPaint = Paint()..color = secondaryTrackColorTween.evaluate(enableAnimation)!;
if (textDirection == TextDirection.ltr) {
context.canvas.drawRRect(
RRect.fromLTRBAndCorners(
thumbCenter.dx,
trackRect.top,
secondaryOffset.dx,
trackRect.bottom,
topRight: trackRadius,
bottomRight: trackRadius,
),
secondaryTrackPaint,
);
} else {
context.canvas.drawRRect(
RRect.fromLTRBAndCorners(
secondaryOffset.dx,
trackRect.top,
thumbCenter.dx,
trackRect.bottom,
topLeft: trackRadius,
bottomLeft: trackRadius,
),
secondaryTrackPaint,
);
}
}
}
}
......
......@@ -631,6 +631,7 @@ void main() {
try {
const Color customColor1 = Color(0xcafefeed);
const Color customColor2 = Color(0xdeadbeef);
const Color customColor3 = Color(0xdecaface);
final ThemeData theme = ThemeData(
platform: TargetPlatform.android,
primarySwatch: Colors.blue,
......@@ -647,6 +648,8 @@ void main() {
overlayColor: Color(0xff000010),
thumbColor: Color(0xff000011),
valueIndicatorColor: Color(0xff000012),
disabledSecondaryActiveTrackColor: Color(0xff000013),
secondaryActiveTrackColor: Color(0xff000014),
),
);
final SliderThemeData sliderTheme = theme.sliderTheme;
......@@ -654,6 +657,7 @@ void main() {
Widget buildApp({
Color? activeColor,
Color? inactiveColor,
Color? secondaryActiveColor,
int? divisions,
bool enabled = true,
}) {
......@@ -671,10 +675,12 @@ void main() {
data: theme,
child: Slider(
value: value,
secondaryTrackValue: 0.75,
label: '$value',
divisions: divisions,
activeColor: activeColor,
inactiveColor: inactiveColor,
secondaryActiveColor: secondaryActiveColor,
onChanged: onChanged,
),
),
......@@ -690,47 +696,61 @@ void main() {
final RenderBox valueIndicatorBox = tester.renderObject(find.byType(Overlay));
// Check default theme for enabled widget.
expect(material, paints..rrect(color: sliderTheme.activeTrackColor)..rrect(color: sliderTheme.inactiveTrackColor));
expect(material, paints..rrect(color: sliderTheme.activeTrackColor)..rrect(color: sliderTheme.inactiveTrackColor)..rrect(color: sliderTheme.secondaryActiveTrackColor));
expect(material, paints..shadow(color: const Color(0xff000000)));
expect(material, paints..circle(color: sliderTheme.thumbColor));
expect(material, isNot(paints..circle(color: sliderTheme.disabledThumbColor)));
expect(material, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor)));
expect(material, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor)));
expect(material, isNot(paints..rrect(color: sliderTheme.disabledSecondaryActiveTrackColor)));
expect(material, isNot(paints..circle(color: sliderTheme.activeTickMarkColor)));
expect(material, isNot(paints..circle(color: sliderTheme.inactiveTickMarkColor)));
// Test setting only the activeColor.
await tester.pumpWidget(buildApp(activeColor: customColor1));
expect(material, paints..rrect(color: customColor1)..rrect(color: sliderTheme.inactiveTrackColor));
expect(material, paints..rrect(color: customColor1)..rrect(color: sliderTheme.inactiveTrackColor)..rrect(color: sliderTheme.secondaryActiveTrackColor));
expect(material, paints..shadow(color: Colors.black));
expect(material, paints..circle(color: customColor1));
expect(material, isNot(paints..circle(color: sliderTheme.thumbColor)));
expect(material, isNot(paints..circle(color: sliderTheme.disabledThumbColor)));
expect(material, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor)));
expect(material, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor)));
expect(material, isNot(paints..rrect(color: sliderTheme.disabledSecondaryActiveTrackColor)));
// Test setting only the inactiveColor.
await tester.pumpWidget(buildApp(inactiveColor: customColor1));
expect(material, paints..rrect(color: sliderTheme.activeTrackColor)..rrect(color: customColor1));
expect(material, paints..rrect(color: sliderTheme.activeTrackColor)..rrect(color: customColor1)..rrect(color: sliderTheme.secondaryActiveTrackColor));
expect(material, paints..shadow(color: Colors.black));
expect(material, paints..circle(color: sliderTheme.thumbColor));
expect(material, isNot(paints..circle(color: sliderTheme.disabledThumbColor)));
expect(material, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor)));
expect(material, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor)));
expect(material, isNot(paints..rrect(color: sliderTheme.disabledSecondaryActiveTrackColor)));
// Test setting both activeColor and inactiveColor.
await tester.pumpWidget(buildApp(activeColor: customColor1, inactiveColor: customColor2));
expect(material, paints..rrect(color: customColor1)..rrect(color: customColor2));
// Test setting only the secondaryActiveColor.
await tester.pumpWidget(buildApp(secondaryActiveColor: customColor1));
expect(material, paints..rrect(color: sliderTheme.activeTrackColor)..rrect(color: sliderTheme.inactiveTrackColor)..rrect(color: customColor1));
expect(material, paints..shadow(color: Colors.black));
expect(material, paints..circle(color: sliderTheme.thumbColor));
expect(material, isNot(paints..circle(color: sliderTheme.disabledThumbColor)));
expect(material, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor)));
expect(material, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor)));
expect(material, isNot(paints..rrect(color: sliderTheme.disabledSecondaryActiveTrackColor)));
// Test setting both activeColor, inactiveColor, and secondaryActiveColor.
await tester.pumpWidget(buildApp(activeColor: customColor1, inactiveColor: customColor2, secondaryActiveColor: customColor3));
expect(material, paints..rrect(color: customColor1)..rrect(color: customColor2)..rrect(color: customColor3));
expect(material, paints..shadow(color: Colors.black));
expect(material, paints..circle(color: customColor1));
expect(material, isNot(paints..circle(color: sliderTheme.thumbColor)));
expect(material, isNot(paints..circle(color: sliderTheme.disabledThumbColor)));
expect(material, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor)));
expect(material, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor)));
expect(material, isNot(paints..rrect(color: sliderTheme.disabledSecondaryActiveTrackColor)));
// Test colors for discrete slider.
await tester.pumpWidget(buildApp(divisions: 3));
expect(material, paints..rrect(color: sliderTheme.activeTrackColor)..rrect(color: sliderTheme.inactiveTrackColor));
expect(material, paints..rrect(color: sliderTheme.activeTrackColor)..rrect(color: sliderTheme.inactiveTrackColor)..rrect(color: sliderTheme.secondaryActiveTrackColor));
expect(
material,
paints
......@@ -744,14 +764,16 @@ void main() {
expect(material, isNot(paints..circle(color: sliderTheme.disabledThumbColor)));
expect(material, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor)));
expect(material, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor)));
expect(material, isNot(paints..rrect(color: sliderTheme.disabledSecondaryActiveTrackColor)));
// Test colors for discrete slider with inactiveColor and activeColor set.
await tester.pumpWidget(buildApp(
activeColor: customColor1,
inactiveColor: customColor2,
secondaryActiveColor: customColor3,
divisions: 3,
));
expect(material, paints..rrect(color: customColor1)..rrect(color: customColor2));
expect(material, paints..rrect(color: customColor1)..rrect(color: customColor2)..rrect(color: customColor3));
expect(
material,
paints
......@@ -766,6 +788,7 @@ void main() {
expect(material, isNot(paints..circle(color: sliderTheme.disabledThumbColor)));
expect(material, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor)));
expect(material, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor)));
expect(material, isNot(paints..rrect(color: sliderTheme.disabledSecondaryActiveTrackColor)));
expect(material, isNot(paints..circle(color: sliderTheme.activeTickMarkColor)));
expect(material, isNot(paints..circle(color: sliderTheme.inactiveTickMarkColor)));
......@@ -776,25 +799,29 @@ void main() {
material,
paints
..rrect(color: sliderTheme.disabledActiveTrackColor)
..rrect(color: sliderTheme.disabledInactiveTrackColor),
..rrect(color: sliderTheme.disabledInactiveTrackColor)
..rrect(color: sliderTheme.disabledSecondaryActiveTrackColor),
);
expect(material, paints..shadow(color: Colors.black)..circle(color: sliderTheme.disabledThumbColor));
expect(material, isNot(paints..circle(color: sliderTheme.thumbColor)));
expect(material, isNot(paints..rrect(color: sliderTheme.activeTrackColor)));
expect(material, isNot(paints..rrect(color: sliderTheme.inactiveTrackColor)));
expect(material, isNot(paints..rrect(color: sliderTheme.secondaryActiveTrackColor)));
// Test setting the activeColor and inactiveColor for disabled widget.
await tester.pumpWidget(buildApp(activeColor: customColor1, inactiveColor: customColor2, enabled: false));
// Test setting the activeColor, inactiveColor and secondaryActiveColor for disabled widget.
await tester.pumpWidget(buildApp(activeColor: customColor1, inactiveColor: customColor2, secondaryActiveColor: customColor3, enabled: false));
expect(
material,
paints
..rrect(color: sliderTheme.disabledActiveTrackColor)
..rrect(color: sliderTheme.disabledInactiveTrackColor),
..rrect(color: sliderTheme.disabledInactiveTrackColor)
..rrect(color: sliderTheme.disabledSecondaryActiveTrackColor),
);
expect(material, paints..circle(color: sliderTheme.disabledThumbColor));
expect(material, isNot(paints..circle(color: sliderTheme.thumbColor)));
expect(material, isNot(paints..rrect(color: sliderTheme.activeTrackColor)));
expect(material, isNot(paints..rrect(color: sliderTheme.inactiveTrackColor)));
expect(material, isNot(paints..rrect(color: sliderTheme.secondaryActiveTrackColor)));
// Test that the default value indicator has the right colors.
await tester.pumpWidget(buildApp(divisions: 3));
......@@ -2813,10 +2840,12 @@ void main() {
activeColor: Colors.blue,
divisions: 10,
inactiveColor: Colors.grey,
secondaryActiveColor: Colors.blueGrey,
label: 'Set a value',
max: 100.0,
onChanged: null,
value: 50.0,
secondaryTrackValue: 75.0,
).debugFillProperties(builder);
final List<String> description = builder.properties
......@@ -2825,6 +2854,7 @@ void main() {
expect(description, <String>[
'value: 50.0',
'secondaryTrackValue: 75.0',
'disabled',
'min: 0.0',
'max: 100.0',
......@@ -2832,6 +2862,7 @@ void main() {
'label: "Set a value"',
'activeColor: MaterialColor(primary value: Color(0xff2196f3))',
'inactiveColor: MaterialColor(primary value: Color(0xff9e9e9e))',
'secondaryActiveColor: MaterialColor(primary value: Color(0xff607d8b))',
]);
});
......
......@@ -34,17 +34,19 @@ void main() {
trackHeight: 7.0,
activeTrackColor: Color(0xFF000001),
inactiveTrackColor: Color(0xFF000002),
disabledActiveTrackColor: Color(0xFF000003),
disabledInactiveTrackColor: Color(0xFF000004),
activeTickMarkColor: Color(0xFF000005),
inactiveTickMarkColor: Color(0xFF000006),
disabledActiveTickMarkColor: Color(0xFF000007),
disabledInactiveTickMarkColor: Color(0xFF000008),
thumbColor: Color(0xFF000009),
overlappingShapeStrokeColor: Color(0xFF000010),
disabledThumbColor: Color(0xFF000011),
overlayColor: Color(0xFF000012),
valueIndicatorColor: Color(0xFF000013),
secondaryActiveTrackColor: Color(0xFF000003),
disabledActiveTrackColor: Color(0xFF000004),
disabledInactiveTrackColor: Color(0xFF000005),
disabledSecondaryActiveTrackColor: Color(0xFF000006),
activeTickMarkColor: Color(0xFF000007),
inactiveTickMarkColor: Color(0xFF000008),
disabledActiveTickMarkColor: Color(0xFF000009),
disabledInactiveTickMarkColor: Color(0xFF000010),
thumbColor: Color(0xFF000011),
overlappingShapeStrokeColor: Color(0xFF000012),
disabledThumbColor: Color(0xFF000013),
overlayColor: Color(0xFF000014),
valueIndicatorColor: Color(0xFF000015),
overlayShape: RoundSliderOverlayShape(),
tickMarkShape: RoundSliderTickMarkShape(),
thumbShape: RoundSliderThumbShape(),
......@@ -68,17 +70,19 @@ void main() {
'trackHeight: 7.0',
'activeTrackColor: Color(0xff000001)',
'inactiveTrackColor: Color(0xff000002)',
'disabledActiveTrackColor: Color(0xff000003)',
'disabledInactiveTrackColor: Color(0xff000004)',
'activeTickMarkColor: Color(0xff000005)',
'inactiveTickMarkColor: Color(0xff000006)',
'disabledActiveTickMarkColor: Color(0xff000007)',
'disabledInactiveTickMarkColor: Color(0xff000008)',
'thumbColor: Color(0xff000009)',
'overlappingShapeStrokeColor: Color(0xff000010)',
'disabledThumbColor: Color(0xff000011)',
'overlayColor: Color(0xff000012)',
'valueIndicatorColor: Color(0xff000013)',
'secondaryActiveTrackColor: Color(0xff000003)',
'disabledActiveTrackColor: Color(0xff000004)',
'disabledInactiveTrackColor: Color(0xff000005)',
'disabledSecondaryActiveTrackColor: Color(0xff000006)',
'activeTickMarkColor: Color(0xff000007)',
'inactiveTickMarkColor: Color(0xff000008)',
'disabledActiveTickMarkColor: Color(0xff000009)',
'disabledInactiveTickMarkColor: Color(0xff000010)',
'thumbColor: Color(0xff000011)',
'overlappingShapeStrokeColor: Color(0xff000012)',
'disabledThumbColor: Color(0xff000013)',
'overlayColor: Color(0xff000014)',
'valueIndicatorColor: Color(0xff000015)',
"overlayShape: Instance of 'RoundSliderOverlayShape'",
"tickMarkShape: Instance of 'RoundSliderTickMarkShape'",
"thumbShape: Instance of 'RoundSliderThumbShape'",
......@@ -103,16 +107,18 @@ void main() {
final SliderThemeData customTheme = sliderTheme.copyWith(
activeTrackColor: Colors.purple,
inactiveTrackColor: Colors.purple.withAlpha(0x3d),
secondaryActiveTrackColor: Colors.purple.withAlpha(0x8a),
);
await tester.pumpWidget(_buildApp(sliderTheme, value: 0.5, enabled: false));
await tester.pumpWidget(_buildApp(sliderTheme, value: 0.5, secondaryTrackValue: 0.75, enabled: false));
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!;
expect(
material,
paints
..rrect(color: customTheme.disabledActiveTrackColor)
..rrect(color: customTheme.disabledInactiveTrackColor),
..rrect(color: customTheme.disabledInactiveTrackColor)
..rrect(color: customTheme.disabledSecondaryActiveTrackColor),
);
});
......@@ -125,16 +131,18 @@ void main() {
final SliderThemeData customTheme = sliderTheme.copyWith(
activeTrackColor: Colors.purple,
inactiveTrackColor: Colors.purple.withAlpha(0x3d),
secondaryActiveTrackColor: Colors.purple.withAlpha(0x8a),
);
await tester.pumpWidget(_buildApp(sliderTheme, value: 0.5, enabled: false));
await tester.pumpWidget(_buildApp(sliderTheme, value: 0.5, secondaryTrackValue: 0.75, enabled: false));
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!;
expect(
material,
paints
..rrect(color: customTheme.disabledActiveTrackColor)
..rrect(color: customTheme.disabledInactiveTrackColor),
..rrect(color: customTheme.disabledInactiveTrackColor)
..rrect(color: customTheme.disabledSecondaryActiveTrackColor),
);
});
......@@ -153,8 +161,10 @@ void main() {
expect(sliderTheme.activeTrackColor, equals(customColor1.withAlpha(0xff)));
expect(sliderTheme.inactiveTrackColor, equals(customColor1.withAlpha(0x3d)));
expect(sliderTheme.secondaryActiveTrackColor, equals(customColor1.withAlpha(0x8a)));
expect(sliderTheme.disabledActiveTrackColor, equals(customColor2.withAlpha(0x52)));
expect(sliderTheme.disabledInactiveTrackColor, equals(customColor2.withAlpha(0x1f)));
expect(sliderTheme.disabledSecondaryActiveTrackColor, equals(customColor2.withAlpha(0x1f)));
expect(sliderTheme.activeTickMarkColor, equals(customColor3.withAlpha(0x8a)));
expect(sliderTheme.inactiveTickMarkColor, equals(customColor1.withAlpha(0x8a)));
expect(sliderTheme.disabledActiveTickMarkColor, equals(customColor3.withAlpha(0x1f)));
......@@ -209,8 +219,10 @@ void main() {
expect(lerp.trackHeight, equals(4.0));
expect(lerp.activeTrackColor, equals(middleGrey.withAlpha(0xff)));
expect(lerp.inactiveTrackColor, equals(middleGrey.withAlpha(0x3d)));
expect(lerp.secondaryActiveTrackColor, equals(middleGrey.withAlpha(0x8a)));
expect(lerp.disabledActiveTrackColor, equals(middleGrey.withAlpha(0x52)));
expect(lerp.disabledInactiveTrackColor, equals(middleGrey.withAlpha(0x1f)));
expect(lerp.disabledSecondaryActiveTrackColor, equals(middleGrey.withAlpha(0x1f)));
expect(lerp.activeTickMarkColor, equals(middleGrey.withAlpha(0x8a)));
expect(lerp.inactiveTickMarkColor, equals(middleGrey.withAlpha(0x8a)));
expect(lerp.disabledActiveTickMarkColor, equals(middleGrey.withAlpha(0x1f)));
......@@ -229,7 +241,7 @@ void main() {
);
final SliderThemeData sliderTheme = theme.sliderTheme.copyWith(thumbColor: Colors.red.shade500);
await tester.pumpWidget(_buildApp(sliderTheme, value: 0.25));
await tester.pumpWidget(_buildApp(sliderTheme, value: 0.25, secondaryTrackValue: 0.5));
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!;
const Radius radius = Radius.circular(2);
......@@ -241,10 +253,11 @@ void main() {
material,
paints
..rrect(rrect: RRect.fromLTRBAndCorners(24.0, 297.0, 212.0, 303.0, topLeft: activatedRadius, bottomLeft: activatedRadius), color: sliderTheme.activeTrackColor)
..rrect(rrect: RRect.fromLTRBAndCorners(212.0, 298.0, 776.0, 302.0, topRight: radius, bottomRight: radius), color: sliderTheme.inactiveTrackColor),
..rrect(rrect: RRect.fromLTRBAndCorners(212.0, 298.0, 776.0, 302.0, topRight: radius, bottomRight: radius), color: sliderTheme.inactiveTrackColor)
..rrect(rrect: RRect.fromLTRBAndCorners(212.0, 298.0, 400.0, 302.0, topRight: radius, bottomRight: radius), color: sliderTheme.secondaryActiveTrackColor),
);
await tester.pumpWidget(_buildApp(sliderTheme, value: 0.25, enabled: false));
await tester.pumpWidget(_buildApp(sliderTheme, value: 0.25, secondaryTrackValue: 0.5, enabled: false));
await tester.pumpAndSettle(); // wait for disable animation
// The disabled slider thumb is the same size as the enabled thumb.
......@@ -252,7 +265,8 @@ void main() {
material,
paints
..rrect(rrect: RRect.fromLTRBAndCorners(24.0, 297.0, 212.0, 303.0, topLeft: activatedRadius, bottomLeft: activatedRadius), color: sliderTheme.disabledActiveTrackColor)
..rrect(rrect: RRect.fromLTRBAndCorners(212.0, 298.0, 776.0, 302.0, topRight: radius, bottomRight: radius), color: sliderTheme.disabledInactiveTrackColor),
..rrect(rrect: RRect.fromLTRBAndCorners(212.0, 298.0, 776.0, 302.0, topRight: radius, bottomRight: radius), color: sliderTheme.disabledInactiveTrackColor)
..rrect(rrect: RRect.fromLTRBAndCorners(212.0, 298.0, 400.0, 302.0, topRight: radius, bottomRight: radius), color: sliderTheme.disabledSecondaryActiveTrackColor),
);
});
......@@ -1348,17 +1362,19 @@ class RoundedRectSliderTrackShapeWithCustomAdditionalActiveTrackHeight extends R
required Animation<double> enableAnimation,
required TextDirection textDirection,
required Offset thumbCenter,
Offset? secondaryOffset,
bool isDiscrete = false,
bool isEnabled = false,
double additionalActiveTrackHeight = 2.0,
}) {
super.paint(context, offset, parentBox: parentBox, sliderTheme: sliderTheme, enableAnimation: enableAnimation, textDirection: textDirection, thumbCenter: thumbCenter, additionalActiveTrackHeight: this.additionalActiveTrackHeight);
super.paint(context, offset, parentBox: parentBox, sliderTheme: sliderTheme, enableAnimation: enableAnimation, textDirection: textDirection, thumbCenter: thumbCenter, secondaryOffset: secondaryOffset, additionalActiveTrackHeight: this.additionalActiveTrackHeight);
}
}
Widget _buildApp(
SliderThemeData sliderTheme, {
double value = 0.0,
double? secondaryTrackValue,
bool enabled = true,
int? divisions,
}) {
......@@ -1370,6 +1386,7 @@ Widget _buildApp(
data: sliderTheme,
child: Slider(
value: value,
secondaryTrackValue: secondaryTrackValue,
label: '$value',
onChanged: onChanged,
divisions: divisions,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment