mirror of
https://github.com/flutter/flutter
synced 2024-08-28 04:21:14 +00:00
Add Material 3 support for Slider
- Part 1 (#114079)
This commit is contained in:
parent
f10021b378
commit
97d0247d59
|
@ -38,6 +38,7 @@ import 'package:gen_defaults/navigation_rail_template.dart';
|
|||
import 'package:gen_defaults/popup_menu_template.dart';
|
||||
import 'package:gen_defaults/progress_indicator_template.dart';
|
||||
import 'package:gen_defaults/radio_template.dart';
|
||||
import 'package:gen_defaults/slider_template.dart';
|
||||
import 'package:gen_defaults/surface_tint.dart';
|
||||
import 'package:gen_defaults/switch_template.dart';
|
||||
import 'package:gen_defaults/text_field_template.dart';
|
||||
|
@ -144,6 +145,7 @@ Future<void> main(List<String> args) async {
|
|||
PopupMenuTemplate('PopupMenu', '$materialLib/popup_menu.dart', tokens).updateFile();
|
||||
ProgressIndicatorTemplate('ProgressIndicator', '$materialLib/progress_indicator.dart', tokens).updateFile();
|
||||
RadioTemplate('Radio<T>', '$materialLib/radio.dart', tokens).updateFile();
|
||||
SliderTemplate('md.comp.slider', 'Slider', '$materialLib/slider.dart', tokens).updateFile();
|
||||
SurfaceTintTemplate('SurfaceTint', '$materialLib/elevation_overlay.dart', tokens).updateFile();
|
||||
SwitchTemplate('Switch', '$materialLib/switch.dart', tokens).updateFile();
|
||||
TextFieldTemplate('TextField', '$materialLib/text_field.dart', tokens).updateFile();
|
||||
|
|
77
dev/tools/gen_defaults/lib/slider_template.dart
Normal file
77
dev/tools/gen_defaults/lib/slider_template.dart
Normal file
|
@ -0,0 +1,77 @@
|
|||
// 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 'template.dart';
|
||||
|
||||
class SliderTemplate extends TokenTemplate {
|
||||
const SliderTemplate(this.tokenGroup, super.blockName, super.fileName, super.tokens, {
|
||||
super.colorSchemePrefix = '_colors.',
|
||||
});
|
||||
|
||||
final String tokenGroup;
|
||||
|
||||
@override
|
||||
String generate() => '''
|
||||
class _${blockName}DefaultsM3 extends SliderThemeData {
|
||||
_${blockName}DefaultsM3(this.context)
|
||||
: _colors = Theme.of(context).colorScheme,
|
||||
super(trackHeight: ${tokens['$tokenGroup.active.track.height']});
|
||||
|
||||
final BuildContext context;
|
||||
final ColorScheme _colors;
|
||||
|
||||
@override
|
||||
Color? get activeTrackColor => ${componentColor('$tokenGroup.active.track')};
|
||||
|
||||
@override
|
||||
Color? get inactiveTrackColor => ${componentColor('$tokenGroup.inactive.track')};
|
||||
|
||||
@override
|
||||
Color? get secondaryActiveTrackColor => _colors.primary.withOpacity(0.54);
|
||||
|
||||
@override
|
||||
Color? get disabledActiveTrackColor => ${componentColor('$tokenGroup.disabled.active.track')};
|
||||
|
||||
@override
|
||||
Color? get disabledInactiveTrackColor => ${componentColor('$tokenGroup.disabled.inactive.track')};
|
||||
|
||||
@override
|
||||
Color? get disabledSecondaryActiveTrackColor => _colors.onSurface.withOpacity(0.12);
|
||||
|
||||
@override
|
||||
Color? get activeTickMarkColor => ${componentColor('$tokenGroup.with-tick-marks.active.container')};
|
||||
|
||||
@override
|
||||
Color? get inactiveTickMarkColor => ${componentColor('$tokenGroup.with-tick-marks.inactive.container')};
|
||||
|
||||
@override
|
||||
Color? get disabledActiveTickMarkColor => ${componentColor('$tokenGroup.with-tick-marks.disabled.container')};
|
||||
|
||||
@override
|
||||
Color? get disabledInactiveTickMarkColor => ${componentColor('$tokenGroup.with-tick-marks.disabled.container')};
|
||||
|
||||
@override
|
||||
Color? get thumbColor => ${componentColor('$tokenGroup.handle')};
|
||||
|
||||
@override
|
||||
Color? get disabledThumbColor => Color.alphaBlend(${componentColor('$tokenGroup.disabled.handle')}, _colors.surface);
|
||||
|
||||
@override
|
||||
Color? get overlayColor => MaterialStateColor.resolveWith((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.hovered)) {
|
||||
return ${componentColor('$tokenGroup.hover.state-layer')};
|
||||
}
|
||||
if (states.contains(MaterialState.focused)) {
|
||||
return ${componentColor('$tokenGroup.focus.state-layer')};
|
||||
}
|
||||
if (states.contains(MaterialState.dragged)) {
|
||||
return ${componentColor('$tokenGroup.pressed.state-layer')};
|
||||
}
|
||||
|
||||
return Colors.transparent;
|
||||
});
|
||||
}
|
||||
''';
|
||||
|
||||
}
|
|
@ -12,6 +12,8 @@ import 'package:flutter/rendering.dart';
|
|||
import 'package:flutter/scheduler.dart' show timeDilation;
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'color_scheme.dart';
|
||||
import 'colors.dart';
|
||||
import 'constants.dart';
|
||||
import 'debug.dart';
|
||||
import 'material.dart';
|
||||
|
@ -374,8 +376,9 @@ class Slider extends StatefulWidget {
|
|||
/// The "active" side of the slider is the side between the thumb and the
|
||||
/// minimum value.
|
||||
///
|
||||
/// Defaults to [SliderThemeData.activeTrackColor] of the current
|
||||
/// [SliderTheme].
|
||||
/// If null, [SliderThemeData.activeTrackColor] of the ambient
|
||||
/// [SliderTheme] is used. If that is null, [ColorScheme.primary] of the
|
||||
/// surrounding [ThemeData] is used.
|
||||
///
|
||||
/// Using a [SliderTheme] gives much more fine-grained control over the
|
||||
/// appearance of various components of the slider.
|
||||
|
@ -386,8 +389,10 @@ class Slider extends StatefulWidget {
|
|||
/// The "inactive" side of the slider is the side between the thumb and the
|
||||
/// maximum value.
|
||||
///
|
||||
/// Defaults to the [SliderThemeData.inactiveTrackColor] of the current
|
||||
/// [SliderTheme].
|
||||
/// If null, [SliderThemeData.inactiveTrackColor] of the ambient [SliderTheme]
|
||||
/// is used. If that is null and [ThemeData.useMaterial3] is true,
|
||||
/// [ColorScheme.surfaceVariant] will be used, otherwise [ColorScheme.primary]
|
||||
/// with an opacity of 0.24 will be used.
|
||||
///
|
||||
/// Using a [SliderTheme] gives much more fine-grained control over the
|
||||
/// appearance of various components of the slider.
|
||||
|
@ -401,6 +406,9 @@ class Slider extends StatefulWidget {
|
|||
/// Defaults to the [SliderThemeData.secondaryActiveTrackColor] of the current
|
||||
/// [SliderTheme].
|
||||
///
|
||||
/// If that is also null, defaults to [ColorScheme.primary] with an
|
||||
/// opacity of 0.54.
|
||||
///
|
||||
/// Using a [SliderTheme] gives much more fine-grained control over the
|
||||
/// appearance of various components of the slider.
|
||||
///
|
||||
|
@ -409,19 +417,27 @@ class Slider extends StatefulWidget {
|
|||
|
||||
/// The color of the thumb.
|
||||
///
|
||||
/// If this color is null:
|
||||
/// * [Slider] will use [activeColor].
|
||||
/// If this color is null, [Slider] will use [activeColor], If [activeColor]
|
||||
/// is also null, [Slider] will use [SliderThemeData.thumbColor].
|
||||
///
|
||||
/// If that is also null, defaults to [ColorScheme.primary].
|
||||
///
|
||||
/// * [CupertinoSlider] will have a white thumb
|
||||
/// (like the native default iOS slider).
|
||||
final Color? thumbColor;
|
||||
|
||||
/// The highlight color that's typically used to indicate that
|
||||
/// the slider is focused, hovered, or dragged.
|
||||
/// the slider thumb is focused, hovered, or dragged.
|
||||
///
|
||||
/// If this property is null, [Slider] will use [activeColor] with
|
||||
/// with an opacity of 0.12, If null, [SliderThemeData.overlayColor]
|
||||
/// will be used, If this is also null, defaults to [ColorScheme.primary]
|
||||
/// with an opacity of 0.12.
|
||||
/// will be used.
|
||||
///
|
||||
/// If that is also null, If [ThemeData.useMaterial3] is true,
|
||||
/// Slider will use [ColorScheme.primary] with an opacity of 0.08 when
|
||||
/// slider thumb is hovered and with an opacity of 0.12 when slider thumb
|
||||
/// is focused or dragged, If [ThemeData.useMaterial3] is false, defaults
|
||||
/// to [ColorScheme.primary] with an opacity of 0.12.
|
||||
final MaterialStateProperty<Color?>? overlayColor;
|
||||
|
||||
/// {@template flutter.material.slider.mouseCursor}
|
||||
|
@ -730,6 +746,7 @@ class _SliderState extends State<Slider> with TickerProviderStateMixin {
|
|||
Widget _buildMaterialSlider(BuildContext context) {
|
||||
final ThemeData theme = Theme.of(context);
|
||||
SliderThemeData sliderTheme = SliderTheme.of(context);
|
||||
final SliderThemeData defaults = theme.useMaterial3 ? _SliderDefaultsM3(context) : _SliderDefaultsM2(context);
|
||||
|
||||
// If the widget has active or inactive colors specified, then we plug them
|
||||
// in to the slider theme as best we can. If the developer wants more
|
||||
|
@ -738,7 +755,6 @@ class _SliderState extends State<Slider> with TickerProviderStateMixin {
|
|||
// the default shapes and text styles are aligned to the Material
|
||||
// Guidelines.
|
||||
|
||||
const double defaultTrackHeight = 4;
|
||||
const SliderTrackShape defaultTrackShape = RoundedRectSliderTrackShape();
|
||||
const SliderTickMarkShape defaultTickMarkShape = RoundSliderTickMarkShape();
|
||||
const SliderComponentShape defaultOverlayShape = RoundSliderOverlayShape();
|
||||
|
@ -769,23 +785,23 @@ class _SliderState extends State<Slider> with TickerProviderStateMixin {
|
|||
return widget.overlayColor?.resolve(states)
|
||||
?? widget.activeColor?.withOpacity(0.12)
|
||||
?? MaterialStateProperty.resolveAs<Color?>(sliderTheme.overlayColor, states)
|
||||
?? theme.colorScheme.primary.withOpacity(0.12);
|
||||
?? MaterialStateProperty.resolveAs<Color?>(defaults.overlayColor, states);
|
||||
}
|
||||
|
||||
sliderTheme = sliderTheme.copyWith(
|
||||
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),
|
||||
disabledInactiveTickMarkColor: sliderTheme.disabledInactiveTickMarkColor ?? theme.colorScheme.onSurface.withOpacity(0.12),
|
||||
thumbColor: widget.thumbColor ?? widget.activeColor ?? sliderTheme.thumbColor ?? theme.colorScheme.primary,
|
||||
disabledThumbColor: sliderTheme.disabledThumbColor ?? Color.alphaBlend(theme.colorScheme.onSurface.withOpacity(.38), theme.colorScheme.surface),
|
||||
trackHeight: sliderTheme.trackHeight ?? defaults.trackHeight,
|
||||
activeTrackColor: widget.activeColor ?? sliderTheme.activeTrackColor ?? defaults.activeTrackColor,
|
||||
inactiveTrackColor: widget.inactiveColor ?? sliderTheme.inactiveTrackColor ?? defaults.inactiveTrackColor,
|
||||
secondaryActiveTrackColor: widget.secondaryActiveColor ?? sliderTheme.secondaryActiveTrackColor ?? defaults.secondaryActiveTrackColor,
|
||||
disabledActiveTrackColor: sliderTheme.disabledActiveTrackColor ?? defaults.disabledActiveTrackColor,
|
||||
disabledInactiveTrackColor: sliderTheme.disabledInactiveTrackColor ?? defaults.disabledInactiveTrackColor,
|
||||
disabledSecondaryActiveTrackColor: sliderTheme.disabledSecondaryActiveTrackColor ?? defaults.disabledSecondaryActiveTrackColor,
|
||||
activeTickMarkColor: widget.inactiveColor ?? sliderTheme.activeTickMarkColor ?? defaults.activeTickMarkColor,
|
||||
inactiveTickMarkColor: widget.activeColor ?? sliderTheme.inactiveTickMarkColor ?? defaults.inactiveTickMarkColor,
|
||||
disabledActiveTickMarkColor: sliderTheme.disabledActiveTickMarkColor ?? defaults.disabledActiveTickMarkColor,
|
||||
disabledInactiveTickMarkColor: sliderTheme.disabledInactiveTickMarkColor ?? defaults.disabledInactiveTickMarkColor,
|
||||
thumbColor: widget.thumbColor ?? widget.activeColor ?? sliderTheme.thumbColor ?? defaults.thumbColor,
|
||||
disabledThumbColor: sliderTheme.disabledThumbColor ?? defaults.disabledThumbColor,
|
||||
overlayColor: effectiveOverlayColor(),
|
||||
valueIndicatorColor: valueIndicatorColor,
|
||||
trackShape: sliderTheme.trackShape ?? defaultTrackShape,
|
||||
|
@ -1795,3 +1811,122 @@ class _RenderValueIndicator extends RenderBox with RelayoutWhenSystemFontsChange
|
|||
return constraints.smallest;
|
||||
}
|
||||
}
|
||||
|
||||
class _SliderDefaultsM2 extends SliderThemeData {
|
||||
_SliderDefaultsM2(this.context)
|
||||
: _colors = Theme.of(context).colorScheme,
|
||||
super(trackHeight: 4.0);
|
||||
|
||||
final BuildContext context;
|
||||
final ColorScheme _colors;
|
||||
|
||||
@override
|
||||
Color? get activeTrackColor => _colors.primary;
|
||||
|
||||
@override
|
||||
Color? get inactiveTrackColor => _colors.primary.withOpacity(0.24);
|
||||
|
||||
@override
|
||||
Color? get secondaryActiveTrackColor => _colors.primary.withOpacity(0.54);
|
||||
|
||||
@override
|
||||
Color? get disabledActiveTrackColor => _colors.onSurface.withOpacity(0.32);
|
||||
|
||||
@override
|
||||
Color? get disabledInactiveTrackColor => _colors.onSurface.withOpacity(0.12);
|
||||
|
||||
@override
|
||||
Color? get disabledSecondaryActiveTrackColor => _colors.onSurface.withOpacity(0.12);
|
||||
|
||||
@override
|
||||
Color? get activeTickMarkColor => _colors.onPrimary.withOpacity(0.54);
|
||||
|
||||
@override
|
||||
Color? get inactiveTickMarkColor => _colors.primary.withOpacity(0.54);
|
||||
|
||||
@override
|
||||
Color? get disabledActiveTickMarkColor => _colors.onPrimary.withOpacity(0.12);
|
||||
|
||||
@override
|
||||
Color? get disabledInactiveTickMarkColor => _colors.onSurface.withOpacity(0.12);
|
||||
|
||||
@override
|
||||
Color? get thumbColor => _colors.primary;
|
||||
|
||||
@override
|
||||
Color? get disabledThumbColor => Color.alphaBlend(_colors.onSurface.withOpacity(.38), _colors.surface);
|
||||
|
||||
@override
|
||||
Color? get overlayColor => _colors.primary.withOpacity(0.12);
|
||||
}
|
||||
|
||||
// BEGIN GENERATED TOKEN PROPERTIES - Slider
|
||||
|
||||
// Do not edit by hand. The code between the "BEGIN GENERATED" and
|
||||
// "END GENERATED" comments are generated from data in the Material
|
||||
// Design token database by the script:
|
||||
// dev/tools/gen_defaults/bin/gen_defaults.dart.
|
||||
|
||||
// Token database version: v0_137
|
||||
|
||||
class _SliderDefaultsM3 extends SliderThemeData {
|
||||
_SliderDefaultsM3(this.context)
|
||||
: _colors = Theme.of(context).colorScheme,
|
||||
super(trackHeight: 4.0);
|
||||
|
||||
final BuildContext context;
|
||||
final ColorScheme _colors;
|
||||
|
||||
@override
|
||||
Color? get activeTrackColor => _colors.primary;
|
||||
|
||||
@override
|
||||
Color? get inactiveTrackColor => _colors.surfaceVariant;
|
||||
|
||||
@override
|
||||
Color? get secondaryActiveTrackColor => _colors.primary.withOpacity(0.54);
|
||||
|
||||
@override
|
||||
Color? get disabledActiveTrackColor => _colors.onSurface.withOpacity(0.38);
|
||||
|
||||
@override
|
||||
Color? get disabledInactiveTrackColor => _colors.onSurface.withOpacity(0.12);
|
||||
|
||||
@override
|
||||
Color? get disabledSecondaryActiveTrackColor => _colors.onSurface.withOpacity(0.12);
|
||||
|
||||
@override
|
||||
Color? get activeTickMarkColor => _colors.onPrimary.withOpacity(0.38);
|
||||
|
||||
@override
|
||||
Color? get inactiveTickMarkColor => _colors.onSurfaceVariant.withOpacity(0.38);
|
||||
|
||||
@override
|
||||
Color? get disabledActiveTickMarkColor => _colors.onSurface.withOpacity(0.38);
|
||||
|
||||
@override
|
||||
Color? get disabledInactiveTickMarkColor => _colors.onSurface.withOpacity(0.38);
|
||||
|
||||
@override
|
||||
Color? get thumbColor => _colors.primary;
|
||||
|
||||
@override
|
||||
Color? get disabledThumbColor => Color.alphaBlend(_colors.onSurface.withOpacity(0.38), _colors.surface);
|
||||
|
||||
@override
|
||||
Color? get overlayColor => MaterialStateColor.resolveWith((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.hovered)) {
|
||||
return _colors.primary.withOpacity(0.08);
|
||||
}
|
||||
if (states.contains(MaterialState.focused)) {
|
||||
return _colors.primary.withOpacity(0.12);
|
||||
}
|
||||
if (states.contains(MaterialState.dragged)) {
|
||||
return _colors.primary.withOpacity(0.12);
|
||||
}
|
||||
|
||||
return Colors.transparent;
|
||||
});
|
||||
}
|
||||
|
||||
// END GENERATED TOKEN PROPERTIES - Slider
|
||||
|
|
|
@ -1710,28 +1710,25 @@ void main() {
|
|||
testWidgets('Slider is focusable and has correct focus color', (WidgetTester tester) async {
|
||||
final FocusNode focusNode = FocusNode(debugLabel: 'Slider');
|
||||
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
||||
final ThemeData theme = ThemeData(useMaterial3: true);
|
||||
double value = 0.5;
|
||||
Widget buildApp({bool enabled = true}) {
|
||||
return MaterialApp(
|
||||
theme: theme,
|
||||
home: Material(
|
||||
child: Center(
|
||||
child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
|
||||
return SliderTheme(
|
||||
data: SliderThemeData(
|
||||
overlayColor: Colors.orange[500],
|
||||
),
|
||||
child: Slider(
|
||||
value: value,
|
||||
onChanged: enabled
|
||||
? (double newValue) {
|
||||
setState(() {
|
||||
value = newValue;
|
||||
});
|
||||
}
|
||||
: null,
|
||||
autofocus: true,
|
||||
focusNode: focusNode,
|
||||
),
|
||||
return Slider(
|
||||
value: value,
|
||||
onChanged: enabled
|
||||
? (double newValue) {
|
||||
setState(() {
|
||||
value = newValue;
|
||||
});
|
||||
}
|
||||
: null,
|
||||
autofocus: true,
|
||||
focusNode: focusNode,
|
||||
);
|
||||
}),
|
||||
),
|
||||
|
@ -1745,7 +1742,7 @@ void main() {
|
|||
expect(focusNode.hasPrimaryFocus, isTrue);
|
||||
expect(
|
||||
Material.of(tester.element(find.byType(Slider))),
|
||||
paints..circle(color: Colors.orange[500]),
|
||||
paints..circle(color: theme.colorScheme.primary.withOpacity(0.12)),
|
||||
);
|
||||
|
||||
// Check that the overlay does not show when unfocused and disabled.
|
||||
|
@ -1754,7 +1751,7 @@ void main() {
|
|||
expect(focusNode.hasPrimaryFocus, isFalse);
|
||||
expect(
|
||||
Material.of(tester.element(find.byType(Slider))),
|
||||
isNot(paints..circle(color: Colors.orange[500])),
|
||||
isNot(paints..circle(color: theme.colorScheme.primary.withOpacity(0.12))),
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -1813,26 +1810,23 @@ void main() {
|
|||
|
||||
testWidgets('Slider can be hovered and has correct hover color', (WidgetTester tester) async {
|
||||
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
||||
final ThemeData theme = ThemeData(useMaterial3: true);
|
||||
double value = 0.5;
|
||||
Widget buildApp({bool enabled = true}) {
|
||||
return MaterialApp(
|
||||
theme: theme,
|
||||
home: Material(
|
||||
child: Center(
|
||||
child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
|
||||
return SliderTheme(
|
||||
data: SliderThemeData(
|
||||
overlayColor: Colors.orange[500],
|
||||
),
|
||||
child: Slider(
|
||||
value: value,
|
||||
onChanged: enabled
|
||||
? (double newValue) {
|
||||
setState(() {
|
||||
value = newValue;
|
||||
});
|
||||
}
|
||||
: null,
|
||||
),
|
||||
return Slider(
|
||||
value: value,
|
||||
onChanged: enabled
|
||||
? (double newValue) {
|
||||
setState(() {
|
||||
value = newValue;
|
||||
});
|
||||
}
|
||||
: null,
|
||||
);
|
||||
}),
|
||||
),
|
||||
|
@ -1858,7 +1852,7 @@ void main() {
|
|||
await tester.pumpAndSettle();
|
||||
expect(
|
||||
Material.of(tester.element(find.byType(Slider))),
|
||||
paints..circle(color: Colors.orange[500]),
|
||||
paints..circle(color: theme.colorScheme.primary.withOpacity(0.08)),
|
||||
);
|
||||
|
||||
// Slider does not have an overlay when disabled and hovered.
|
||||
|
@ -1931,6 +1925,67 @@ void main() {
|
|||
);
|
||||
});
|
||||
|
||||
testWidgets('Slider is draggable and has correct dragged color', (WidgetTester tester) async {
|
||||
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
||||
double value = 0.5;
|
||||
final ThemeData theme = ThemeData(useMaterial3: true);
|
||||
final Key sliderKey = UniqueKey();
|
||||
|
||||
Widget buildApp({bool enabled = true}) {
|
||||
return MaterialApp(
|
||||
theme: theme,
|
||||
home: Material(
|
||||
child: Center(
|
||||
child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
|
||||
return Slider(
|
||||
value: value,
|
||||
key: sliderKey,
|
||||
onChanged: enabled
|
||||
? (double newValue) {
|
||||
setState(() {
|
||||
value = newValue;
|
||||
});
|
||||
}
|
||||
: null,
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
await tester.pumpWidget(buildApp());
|
||||
|
||||
// Slider does not have overlay when enabled and not dragged.
|
||||
await tester.pumpAndSettle();
|
||||
expect(
|
||||
Material.of(tester.element(find.byType(Slider))),
|
||||
isNot(paints..circle(color: theme.colorScheme.primary.withOpacity(0.12))),
|
||||
);
|
||||
|
||||
// Start dragging.
|
||||
final TestGesture drag = await tester.startGesture(tester.getCenter(find.byKey(sliderKey)));
|
||||
await tester.pump(kPressTimeout);
|
||||
|
||||
// Less than configured touch slop, more than default touch slop
|
||||
await drag.moveBy(const Offset(19.0, 0));
|
||||
await tester.pump();
|
||||
|
||||
// Slider has overlay when enabled and dragged.
|
||||
expect(
|
||||
Material.of(tester.element(find.byType(Slider))),
|
||||
paints..circle(color: theme.colorScheme.primary.withOpacity(0.12)),
|
||||
);
|
||||
|
||||
await drag.up();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Slider still has overlay when stopped dragging.
|
||||
expect(
|
||||
Material.of(tester.element(find.byType(Slider))),
|
||||
paints..circle(color: theme.colorScheme.primary.withOpacity(0.12)),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Slider has correct dragged color from overlayColor property', (WidgetTester tester) async {
|
||||
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
||||
double value = 0.5;
|
||||
|
@ -3381,4 +3436,171 @@ void main() {
|
|||
isNot(paints..path(color: const Color(0xff000000))..paragraph()),
|
||||
);
|
||||
}, variant: TargetPlatformVariant.desktop());
|
||||
|
||||
group('Material 2', () {
|
||||
// Tests that are only relevant for Material 2. Once ThemeData.useMaterial3
|
||||
// is turned on by default, these tests can be removed.
|
||||
|
||||
testWidgets('Slider can be hovered and has correct hover color', (WidgetTester tester) async {
|
||||
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
||||
final ThemeData theme = ThemeData();
|
||||
double value = 0.5;
|
||||
Widget buildApp({bool enabled = true}) {
|
||||
return MaterialApp(
|
||||
home: Material(
|
||||
child: Center(
|
||||
child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
|
||||
return Slider(
|
||||
value: value,
|
||||
onChanged: enabled
|
||||
? (double newValue) {
|
||||
setState(() {
|
||||
value = newValue;
|
||||
});
|
||||
}
|
||||
: null,
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
await tester.pumpWidget(buildApp());
|
||||
|
||||
// Slider does not have overlay when enabled and not hovered.
|
||||
await tester.pumpAndSettle();
|
||||
expect(
|
||||
Material.of(tester.element(find.byType(Slider))),
|
||||
isNot(paints..circle(color: theme.colorScheme.primary.withOpacity(0.12))),
|
||||
);
|
||||
|
||||
// Start hovering.
|
||||
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
|
||||
await gesture.addPointer();
|
||||
await gesture.moveTo(tester.getCenter(find.byType(Slider)));
|
||||
|
||||
// Slider has overlay when enabled and hovered.
|
||||
await tester.pumpWidget(buildApp());
|
||||
await tester.pumpAndSettle();
|
||||
expect(
|
||||
Material.of(tester.element(find.byType(Slider))),
|
||||
paints..circle(color: theme.colorScheme.primary.withOpacity(0.12)),
|
||||
);
|
||||
|
||||
// Slider does not have an overlay when disabled and hovered.
|
||||
await tester.pumpWidget(buildApp(enabled: false));
|
||||
await tester.pumpAndSettle();
|
||||
expect(
|
||||
Material.of(tester.element(find.byType(Slider))),
|
||||
isNot(paints..circle(color: theme.colorScheme.primary.withOpacity(0.12))),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Slider is focusable and has correct focus color', (WidgetTester tester) async {
|
||||
final FocusNode focusNode = FocusNode(debugLabel: 'Slider');
|
||||
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
||||
final ThemeData theme = ThemeData();
|
||||
double value = 0.5;
|
||||
Widget buildApp({bool enabled = true}) {
|
||||
return MaterialApp(
|
||||
home: Material(
|
||||
child: Center(
|
||||
child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
|
||||
return Slider(
|
||||
value: value,
|
||||
onChanged: enabled
|
||||
? (double newValue) {
|
||||
setState(() {
|
||||
value = newValue;
|
||||
});
|
||||
}
|
||||
: null,
|
||||
autofocus: true,
|
||||
focusNode: focusNode,
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
await tester.pumpWidget(buildApp());
|
||||
|
||||
// Check that the overlay shows when focused.
|
||||
await tester.pumpAndSettle();
|
||||
expect(focusNode.hasPrimaryFocus, isTrue);
|
||||
expect(
|
||||
Material.of(tester.element(find.byType(Slider))),
|
||||
paints..circle(color: theme.colorScheme.primary.withOpacity(0.12)),
|
||||
);
|
||||
|
||||
// Check that the overlay does not show when unfocused and disabled.
|
||||
await tester.pumpWidget(buildApp(enabled: false));
|
||||
await tester.pumpAndSettle();
|
||||
expect(focusNode.hasPrimaryFocus, isFalse);
|
||||
expect(
|
||||
Material.of(tester.element(find.byType(Slider))),
|
||||
isNot(paints..circle(color: theme.colorScheme.primary.withOpacity(0.12))),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Slider is draggable and has correct dragged color', (WidgetTester tester) async {
|
||||
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
||||
double value = 0.5;
|
||||
final ThemeData theme = ThemeData();
|
||||
final Key sliderKey = UniqueKey();
|
||||
|
||||
Widget buildApp({bool enabled = true}) {
|
||||
return MaterialApp(
|
||||
home: Material(
|
||||
child: Center(
|
||||
child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
|
||||
return Slider(
|
||||
value: value,
|
||||
key: sliderKey,
|
||||
onChanged: enabled
|
||||
? (double newValue) {
|
||||
setState(() {
|
||||
value = newValue;
|
||||
});
|
||||
}
|
||||
: null,
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
await tester.pumpWidget(buildApp());
|
||||
|
||||
// Slider does not have overlay when enabled and not dragged.
|
||||
await tester.pumpAndSettle();
|
||||
expect(
|
||||
Material.of(tester.element(find.byType(Slider))),
|
||||
isNot(paints..circle(color: theme.colorScheme.primary.withOpacity(0.12))),
|
||||
);
|
||||
|
||||
// Start dragging.
|
||||
final TestGesture drag = await tester.startGesture(tester.getCenter(find.byKey(sliderKey)));
|
||||
await tester.pump(kPressTimeout);
|
||||
|
||||
// Less than configured touch slop, more than default touch slop
|
||||
await drag.moveBy(const Offset(19.0, 0));
|
||||
await tester.pump();
|
||||
|
||||
// Slider has overlay when enabled and dragged.
|
||||
expect(
|
||||
Material.of(tester.element(find.byType(Slider))),
|
||||
paints..circle(color: theme.colorScheme.primary.withOpacity(0.12)),
|
||||
);
|
||||
|
||||
await drag.up();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Slider still has overlay when stopped dragging.
|
||||
expect(
|
||||
Material.of(tester.element(find.byType(Slider))),
|
||||
paints..circle(color: theme.colorScheme.primary.withOpacity(0.12)),
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -97,6 +97,137 @@ void main() {
|
|||
]);
|
||||
});
|
||||
|
||||
testWidgets('Slider defaults', (WidgetTester tester) async {
|
||||
debugDisableShadows = false;
|
||||
final ThemeData theme = ThemeData(useMaterial3: true);
|
||||
final ColorScheme colorScheme = theme.colorScheme;
|
||||
const double trackHeight = 4.0;
|
||||
final Color activeTrackColor = Color(colorScheme.primary.value);
|
||||
final Color inactiveTrackColor = colorScheme.surfaceVariant;
|
||||
final Color secondaryActiveTrackColor = colorScheme.primary.withOpacity(0.54);
|
||||
final Color disabledActiveTrackColor = colorScheme.onSurface.withOpacity(0.38);
|
||||
final Color disabledInactiveTrackColor = colorScheme.onSurface.withOpacity(0.12);
|
||||
final Color disabledSecondaryActiveTrackColor = colorScheme.onSurface.withOpacity(0.12);
|
||||
final Color shadowColor = colorScheme.shadow;
|
||||
final Color thumbColor = Color(colorScheme.primary.value);
|
||||
final Color disabledThumbColor = Color.alphaBlend(colorScheme.onSurface.withOpacity(0.38), colorScheme.surface);
|
||||
final Color activeTickMarkColor = colorScheme.onPrimary.withOpacity(0.38);
|
||||
final Color inactiveTickMarkColor = colorScheme.onSurfaceVariant.withOpacity(0.38);
|
||||
final Color disabledActiveTickMarkColor = colorScheme.onSurface.withOpacity(0.38);
|
||||
final Color disabledInactiveTickMarkColor = colorScheme.onSurface.withOpacity(0.38);
|
||||
|
||||
try {
|
||||
double value = 0.45;
|
||||
Widget buildApp({
|
||||
int? divisions,
|
||||
bool enabled = true,
|
||||
}) {
|
||||
final ValueChanged<double>? onChanged = !enabled
|
||||
? null
|
||||
: (double d) {
|
||||
value = d;
|
||||
};
|
||||
return MaterialApp(
|
||||
home: Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Material(
|
||||
child: Center(
|
||||
child: Theme(
|
||||
data: theme,
|
||||
child: Slider(
|
||||
value: value,
|
||||
secondaryTrackValue: 0.75,
|
||||
label: '$value',
|
||||
divisions: divisions,
|
||||
onChanged: onChanged,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(buildApp());
|
||||
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
|
||||
|
||||
// Test default track height.
|
||||
const Radius radius = Radius.circular(trackHeight / 2);
|
||||
const Radius activatedRadius = Radius.circular((trackHeight + 2) / 2);
|
||||
expect(
|
||||
material,
|
||||
paints
|
||||
..rrect(rrect: RRect.fromLTRBAndCorners(24.0, 297.0, 362.4, 303.0, topLeft: activatedRadius, bottomLeft: activatedRadius), color: activeTrackColor)
|
||||
..rrect(rrect: RRect.fromLTRBAndCorners(362.4, 298.0, 776.0, 302.0, topRight: radius, bottomRight: radius), color: inactiveTrackColor),
|
||||
);
|
||||
|
||||
// Test default colors for enabled slider.
|
||||
expect(material, paints..rrect(color: activeTrackColor)..rrect(color: inactiveTrackColor)..rrect(color: secondaryActiveTrackColor));
|
||||
expect(material, paints..shadow(color: shadowColor));
|
||||
expect(material, paints..circle(color: thumbColor));
|
||||
expect(material, isNot(paints..circle(color: disabledThumbColor)));
|
||||
expect(material, isNot(paints..rrect(color: disabledActiveTrackColor)));
|
||||
expect(material, isNot(paints..rrect(color: disabledInactiveTrackColor)));
|
||||
expect(material, isNot(paints..rrect(color: disabledSecondaryActiveTrackColor)));
|
||||
expect(material, isNot(paints..circle(color: activeTickMarkColor)));
|
||||
expect(material, isNot(paints..circle(color: inactiveTickMarkColor)));
|
||||
|
||||
// Test defaults colors for discrete slider.
|
||||
await tester.pumpWidget(buildApp(divisions: 3));
|
||||
expect(material, paints..rrect(color: activeTrackColor)..rrect(color: inactiveTrackColor)..rrect(color: secondaryActiveTrackColor));
|
||||
expect(
|
||||
material,
|
||||
paints
|
||||
..circle(color: activeTickMarkColor)
|
||||
..circle(color: activeTickMarkColor)
|
||||
..circle(color: inactiveTickMarkColor)
|
||||
..circle(color: inactiveTickMarkColor)
|
||||
..shadow(color: Colors.black)
|
||||
..circle(color: thumbColor),
|
||||
);
|
||||
expect(material, isNot(paints..circle(color: disabledThumbColor)));
|
||||
expect(material, isNot(paints..rrect(color: disabledActiveTrackColor)));
|
||||
expect(material, isNot(paints..rrect(color: disabledInactiveTrackColor)));
|
||||
expect(material, isNot(paints..rrect(color: disabledSecondaryActiveTrackColor)));
|
||||
|
||||
// Test defaults colors for disabled slider.
|
||||
await tester.pumpWidget(buildApp(enabled: false));
|
||||
await tester.pumpAndSettle();
|
||||
expect(
|
||||
material,
|
||||
paints
|
||||
..rrect(color: disabledActiveTrackColor)
|
||||
..rrect(color: disabledInactiveTrackColor)
|
||||
..rrect(color: disabledSecondaryActiveTrackColor),
|
||||
);
|
||||
expect(material, paints..shadow(color: shadowColor)..circle(color: disabledThumbColor));
|
||||
expect(material, isNot(paints..circle(color: thumbColor)));
|
||||
expect(material, isNot(paints..rrect(color: activeTrackColor)));
|
||||
expect(material, isNot(paints..rrect(color: inactiveTrackColor)));
|
||||
expect(material, isNot(paints..rrect(color: secondaryActiveTrackColor)));
|
||||
|
||||
// Test defaults colors for disabled discrete slider.
|
||||
await tester.pumpWidget(buildApp(divisions: 3, enabled: false));
|
||||
expect(
|
||||
material,
|
||||
paints
|
||||
..circle(color: disabledActiveTickMarkColor)
|
||||
..circle(color: disabledActiveTickMarkColor)
|
||||
..circle(color: disabledInactiveTickMarkColor)
|
||||
..circle(color: disabledInactiveTickMarkColor)
|
||||
..shadow(color: shadowColor)
|
||||
..circle(color: disabledThumbColor),
|
||||
);
|
||||
expect(material, isNot(paints..circle(color: thumbColor)));
|
||||
expect(material, isNot(paints..rrect(color: activeTrackColor)));
|
||||
expect(material, isNot(paints..rrect(color: inactiveTrackColor)));
|
||||
expect(material, isNot(paints..rrect(color: secondaryActiveTrackColor)));
|
||||
} finally {
|
||||
debugDisableShadows = true;
|
||||
}
|
||||
});
|
||||
|
||||
testWidgets('Slider uses the right theme colors for the right components', (WidgetTester tester) async {
|
||||
debugDisableShadows = false;
|
||||
try {
|
||||
|
@ -279,6 +410,25 @@ void main() {
|
|||
expect(material, isNot(paints..rrect(color: sliderTheme.inactiveTrackColor)));
|
||||
expect(material, isNot(paints..rrect(color: sliderTheme.secondaryActiveTrackColor)));
|
||||
|
||||
// Test default theme for disabled discrete widget.
|
||||
await tester.pumpWidget(buildApp(divisions: 3, enabled: false));
|
||||
expect(
|
||||
material,
|
||||
paints
|
||||
..circle(color: sliderTheme.disabledActiveTickMarkColor)
|
||||
..circle(color: sliderTheme.disabledActiveTickMarkColor)
|
||||
..circle(color: sliderTheme.disabledInactiveTickMarkColor)
|
||||
..circle(color: sliderTheme.disabledInactiveTickMarkColor)
|
||||
..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)));
|
||||
expect(material, isNot(paints..circle(color: sliderTheme.activeTickMarkColor)));
|
||||
expect(material, isNot(paints..circle(color: sliderTheme.inactiveTickMarkColor)));
|
||||
|
||||
// Test setting the activeColor, inactiveColor and secondaryActiveColor for disabled widget.
|
||||
await tester.pumpWidget(buildApp(activeColor: customColor1, inactiveColor: customColor2, secondaryActiveColor: customColor3, enabled: false));
|
||||
expect(
|
||||
|
@ -343,6 +493,60 @@ void main() {
|
|||
}
|
||||
});
|
||||
|
||||
testWidgets('Slider parameters overrides theme properties', (WidgetTester tester) async {
|
||||
debugDisableShadows = false;
|
||||
const Color activeTrackColor = Color(0xffff0001);
|
||||
const Color inactiveTrackColor = Color(0xffff0002);
|
||||
const Color secondaryActiveTrackColor = Color(0xffff0003);
|
||||
const Color thumbColor = Color(0xffff0004);
|
||||
|
||||
final ThemeData theme = ThemeData(
|
||||
platform: TargetPlatform.android,
|
||||
primarySwatch: Colors.blue,
|
||||
sliderTheme: const SliderThemeData(
|
||||
activeTrackColor: Color(0xff000001),
|
||||
inactiveTickMarkColor: Color(0xff000002),
|
||||
secondaryActiveTrackColor: Color(0xff000003),
|
||||
thumbColor: Color(0xff000004),
|
||||
),
|
||||
);
|
||||
try {
|
||||
const double value = 0.45;
|
||||
Widget buildApp({ bool enabled = true }) {
|
||||
return MaterialApp(
|
||||
theme: theme,
|
||||
home: Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Material(
|
||||
child: Center(
|
||||
child: Slider(
|
||||
activeColor: activeTrackColor,
|
||||
inactiveColor: inactiveTrackColor,
|
||||
secondaryActiveColor: secondaryActiveTrackColor,
|
||||
thumbColor: thumbColor,
|
||||
value: value,
|
||||
secondaryTrackValue: 0.75,
|
||||
label: '$value',
|
||||
onChanged: (double value) { },
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(buildApp());
|
||||
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
|
||||
|
||||
// Test Slider parameters.
|
||||
expect(material, paints..rrect(color: activeTrackColor)..rrect(color: inactiveTrackColor)..rrect(color: secondaryActiveTrackColor));
|
||||
expect(material, paints..circle(color: thumbColor));
|
||||
} finally {
|
||||
debugDisableShadows = true;
|
||||
}
|
||||
});
|
||||
|
||||
testWidgets('Slider uses ThemeData slider theme if present', (WidgetTester tester) async {
|
||||
final ThemeData theme = ThemeData(
|
||||
platform: TargetPlatform.android,
|
||||
|
@ -1652,6 +1856,161 @@ void main() {
|
|||
await tester.pumpAndSettle();
|
||||
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text);
|
||||
});
|
||||
|
||||
|
||||
group('Material 2', () {
|
||||
// Tests that are only relevant for Material 2. Once ThemeData.useMaterial3
|
||||
// is turned on by default, these tests can be removed.
|
||||
|
||||
testWidgets('Slider defaults', (WidgetTester tester) async {
|
||||
debugDisableShadows = false;
|
||||
final ThemeData theme = ThemeData();
|
||||
const double trackHeight = 4.0;
|
||||
final ColorScheme colorScheme = theme.colorScheme;
|
||||
final Color activeTrackColor = Color(colorScheme.primary.value);
|
||||
final Color inactiveTrackColor = colorScheme.primary.withOpacity(0.24);
|
||||
final Color secondaryActiveTrackColor = colorScheme.primary.withOpacity(0.54);
|
||||
final Color disabledActiveTrackColor = colorScheme.onSurface.withOpacity(0.32);
|
||||
final Color disabledInactiveTrackColor = colorScheme.onSurface.withOpacity(0.12);
|
||||
final Color disabledSecondaryActiveTrackColor = colorScheme.onSurface.withOpacity(0.12);
|
||||
final Color shadowColor = colorScheme.shadow;
|
||||
final Color thumbColor = Color(colorScheme.primary.value);
|
||||
final Color disabledThumbColor = Color.alphaBlend(colorScheme.onSurface.withOpacity(.38), colorScheme.surface);
|
||||
final Color activeTickMarkColor = colorScheme.onPrimary.withOpacity(0.54);
|
||||
final Color inactiveTickMarkColor = colorScheme.primary.withOpacity(0.54);
|
||||
final Color disabledActiveTickMarkColor = colorScheme.onPrimary.withOpacity(0.12);
|
||||
final Color disabledInactiveTickMarkColor = colorScheme.onSurface.withOpacity(0.12);
|
||||
final Color valueIndicatorColor = Color.alphaBlend(colorScheme.onSurface.withOpacity(0.60), colorScheme.surface.withOpacity(0.90));
|
||||
|
||||
try {
|
||||
double value = 0.45;
|
||||
Widget buildApp({
|
||||
int? divisions,
|
||||
bool enabled = true,
|
||||
}) {
|
||||
final ValueChanged<double>? onChanged = !enabled
|
||||
? null
|
||||
: (double d) {
|
||||
value = d;
|
||||
};
|
||||
return MaterialApp(
|
||||
home: Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Material(
|
||||
child: Center(
|
||||
child: Slider(
|
||||
value: value,
|
||||
secondaryTrackValue: 0.75,
|
||||
label: '$value',
|
||||
divisions: divisions,
|
||||
onChanged: onChanged,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(buildApp());
|
||||
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
|
||||
final RenderBox valueIndicatorBox = tester.renderObject(find.byType(Overlay));
|
||||
|
||||
// Test default track height.
|
||||
const Radius radius = Radius.circular(trackHeight / 2);
|
||||
const Radius activatedRadius = Radius.circular((trackHeight + 2) / 2);
|
||||
expect(
|
||||
material,
|
||||
paints
|
||||
..rrect(rrect: RRect.fromLTRBAndCorners(24.0, 297.0, 362.4, 303.0, topLeft: activatedRadius, bottomLeft: activatedRadius), color: activeTrackColor)
|
||||
..rrect(rrect: RRect.fromLTRBAndCorners(362.4, 298.0, 776.0, 302.0, topRight: radius, bottomRight: radius), color: inactiveTrackColor),
|
||||
);
|
||||
|
||||
// Test default colors for enabled slider.
|
||||
expect(material, paints..rrect(color: activeTrackColor)..rrect(color: inactiveTrackColor)..rrect(color: secondaryActiveTrackColor));
|
||||
expect(material, paints..shadow(color: shadowColor));
|
||||
expect(material, paints..circle(color: thumbColor));
|
||||
expect(material, isNot(paints..circle(color: disabledThumbColor)));
|
||||
expect(material, isNot(paints..rrect(color: disabledActiveTrackColor)));
|
||||
expect(material, isNot(paints..rrect(color: disabledInactiveTrackColor)));
|
||||
expect(material, isNot(paints..rrect(color: disabledSecondaryActiveTrackColor)));
|
||||
expect(material, isNot(paints..circle(color: activeTickMarkColor)));
|
||||
expect(material, isNot(paints..circle(color: inactiveTickMarkColor)));
|
||||
|
||||
// Test defaults colors for discrete slider.
|
||||
await tester.pumpWidget(buildApp(divisions: 3));
|
||||
expect(material, paints..rrect(color: activeTrackColor)..rrect(color: inactiveTrackColor)..rrect(color: secondaryActiveTrackColor));
|
||||
expect(
|
||||
material,
|
||||
paints
|
||||
..circle(color: activeTickMarkColor)
|
||||
..circle(color: activeTickMarkColor)
|
||||
..circle(color: inactiveTickMarkColor)
|
||||
..circle(color: inactiveTickMarkColor)
|
||||
..shadow(color: Colors.black)
|
||||
..circle(color: thumbColor),
|
||||
);
|
||||
expect(material, isNot(paints..circle(color: disabledThumbColor)));
|
||||
expect(material, isNot(paints..rrect(color: disabledActiveTrackColor)));
|
||||
expect(material, isNot(paints..rrect(color: disabledInactiveTrackColor)));
|
||||
expect(material, isNot(paints..rrect(color: disabledSecondaryActiveTrackColor)));
|
||||
|
||||
// Test defaults colors for disabled slider.
|
||||
await tester.pumpWidget(buildApp(enabled: false));
|
||||
await tester.pumpAndSettle();
|
||||
expect(
|
||||
material,
|
||||
paints
|
||||
..rrect(color: disabledActiveTrackColor)
|
||||
..rrect(color: disabledInactiveTrackColor)
|
||||
..rrect(color: disabledSecondaryActiveTrackColor),
|
||||
);
|
||||
expect(material, paints..shadow(color: Colors.black)..circle(color: disabledThumbColor));
|
||||
expect(material, isNot(paints..circle(color: thumbColor)));
|
||||
expect(material, isNot(paints..rrect(color: activeTrackColor)));
|
||||
expect(material, isNot(paints..rrect(color: inactiveTrackColor)));
|
||||
expect(material, isNot(paints..rrect(color: secondaryActiveTrackColor)));
|
||||
|
||||
// Test defaults colors for disabled discrete slider.
|
||||
await tester.pumpWidget(buildApp(divisions: 3, enabled: false));
|
||||
expect(
|
||||
material,
|
||||
paints
|
||||
..circle(color: disabledActiveTickMarkColor)
|
||||
..circle(color: disabledActiveTickMarkColor)
|
||||
..circle(color: disabledInactiveTickMarkColor)
|
||||
..circle(color: disabledInactiveTickMarkColor)
|
||||
..shadow(color: Colors.black)
|
||||
..circle(color: disabledThumbColor),
|
||||
);
|
||||
expect(material, isNot(paints..circle(color: thumbColor)));
|
||||
expect(material, isNot(paints..rrect(color: activeTrackColor)));
|
||||
expect(material, isNot(paints..rrect(color: inactiveTrackColor)));
|
||||
expect(material, isNot(paints..rrect(color: secondaryActiveTrackColor)));
|
||||
expect(material, isNot(paints..circle(color: activeTickMarkColor)));
|
||||
expect(material, isNot(paints..circle(color: inactiveTickMarkColor)));
|
||||
|
||||
// Test the default color for value indicator.
|
||||
await tester.pumpWidget(buildApp(divisions: 3));
|
||||
final Offset center = tester.getCenter(find.byType(Slider));
|
||||
final TestGesture gesture = await tester.startGesture(center);
|
||||
// Wait for value indicator animation to finish.
|
||||
await tester.pumpAndSettle();
|
||||
expect(value, equals(2.0 / 3.0));
|
||||
expect(
|
||||
valueIndicatorBox,
|
||||
paints
|
||||
..path(color: valueIndicatorColor)
|
||||
..paragraph(),
|
||||
);
|
||||
await gesture.up();
|
||||
// Wait for value indicator animation to finish.
|
||||
await tester.pumpAndSettle();
|
||||
} finally {
|
||||
debugDisableShadows = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class RoundedRectSliderTrackShapeWithCustomAdditionalActiveTrackHeight extends RoundedRectSliderTrackShape {
|
||||
|
@ -1681,6 +2040,7 @@ Widget _buildApp(
|
|||
double? secondaryTrackValue,
|
||||
bool enabled = true,
|
||||
int? divisions,
|
||||
FocusNode? focusNode,
|
||||
}) {
|
||||
final ValueChanged<double>? onChanged = enabled ? (double d) => value = d : null;
|
||||
return MaterialApp(
|
||||
|
@ -1694,6 +2054,7 @@ Widget _buildApp(
|
|||
label: '$value',
|
||||
onChanged: onChanged,
|
||||
divisions: divisions,
|
||||
focusNode: focusNode,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
Loading…
Reference in a new issue