[Material] Simple API for skipping over certain Slider shapes (#27613)
* Provide a simmplified API for skipping over slider thumb, overlay, and tick mark painting * doc fixes * comments * comments * comments * comments * comments * analyzer * comments
This commit is contained in:
parent
20d4770136
commit
39bb6712f6
@ -154,6 +154,16 @@ enum ShowValueIndicator {
|
||||
/// [RoundSliderTickMarkShape], [PaddleSliderValueIndicatorShape], and
|
||||
/// [RoundSliderOverlayShape] for examples.
|
||||
///
|
||||
/// The track painting can be skipped by specifying 0 for [trackHeight].
|
||||
/// The thumb painting can be skipped by specifying
|
||||
/// [SliderComponentShape.noThumb] for [SliderThemeData.thumbShape].
|
||||
/// The overlay painting can be skipped by specifying
|
||||
/// [SliderComponentShape.noOverlay] for [SliderThemeData.overlayShape].
|
||||
/// The tick mark painting can be skipped by specifying
|
||||
/// [SliderTickMarkShape.noTickMark] for [SliderThemeData.tickMarkShape].
|
||||
/// The value indicator painting can be skipped by specifying the
|
||||
/// appropriate [ShowValueIndicator] for [SliderThemeData.showValueIndicator].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [SliderTheme] widget, which can override the slider theme of its
|
||||
@ -706,6 +716,9 @@ abstract class SliderTrackShape {
|
||||
/// This is a simplified version of [SliderComponentShape] with a
|
||||
/// [SliderThemeData] passed when getting the preferred size.
|
||||
///
|
||||
/// The tick mark painting can be skipped by specifying [noTickMark] for
|
||||
/// [SliderThemeData.tickMarkShape].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [RoundSliderTickMarkShape] for a simple example of a tick mark shape.
|
||||
@ -759,6 +772,45 @@ abstract class SliderTickMarkShape {
|
||||
bool isEnabled,
|
||||
TextDirection textDirection,
|
||||
});
|
||||
|
||||
/// Special instance of [SliderTickMarkShape] to skip the tick mark painting.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [SliderThemeData.tickMarkShape], which is the shape that the [Slider]
|
||||
/// uses when painting tick marks.
|
||||
static final SliderTickMarkShape noTickMark = _EmptySliderTickMarkShape();
|
||||
}
|
||||
|
||||
/// A special version of [SliderTickMarkShape] that has a zero size and paints
|
||||
/// nothing.
|
||||
///
|
||||
/// This class is used to create a special instance of a [SliderTickMarkShape]
|
||||
/// that will not paint any tick mark shape. A static reference is stored in
|
||||
/// [SliderTickMarkShape.noTickMark]. When this value is specified for
|
||||
/// [SliderThemeData.tickMarkShape], the tick mark painting is skipped.
|
||||
class _EmptySliderTickMarkShape extends SliderTickMarkShape {
|
||||
@override
|
||||
Size getPreferredSize({
|
||||
SliderThemeData sliderTheme,
|
||||
bool isEnabled,
|
||||
}) {
|
||||
return Size.zero;
|
||||
}
|
||||
|
||||
@override
|
||||
void paint(
|
||||
PaintingContext context,
|
||||
Offset center, {
|
||||
RenderBox parentBox,
|
||||
SliderThemeData sliderTheme,
|
||||
Animation<double> enableAnimation,
|
||||
Offset thumbCenter,
|
||||
bool isEnabled,
|
||||
TextDirection textDirection,
|
||||
}) {
|
||||
// no-op.
|
||||
}
|
||||
}
|
||||
|
||||
/// Base class for slider thumb, thumb overlay, and value indicator shapes.
|
||||
@ -768,6 +820,12 @@ abstract class SliderTickMarkShape {
|
||||
/// All shapes are painted to the same canvas and ordering is important.
|
||||
/// The overlay is painted first, then the value indicator, then the thumb.
|
||||
///
|
||||
/// The thumb painting can be skipped by specifying [noThumb] for
|
||||
/// [SliderThemeData.thumbShape].
|
||||
///
|
||||
/// The overlay painting can be skipped by specifying [noOverlay] for
|
||||
/// [SliderThemeData.overlayShape].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [RoundSliderThumbShape], which is the the default thumb shape.
|
||||
@ -821,6 +879,52 @@ abstract class SliderComponentShape {
|
||||
TextDirection textDirection,
|
||||
double value,
|
||||
});
|
||||
|
||||
/// Special instance of [SliderComponentShape] to skip the thumb drawing.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [SliderThemeData.thumbShape], which is the shape that the [Slider]
|
||||
/// uses when painting the thumb.
|
||||
static final SliderComponentShape noThumb = _EmptySliderComponentShape();
|
||||
|
||||
/// Special instance of [SliderComponentShape] to skip the overlay drawing.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [SliderThemeData.overlayShape], which is the shape that the [Slider]
|
||||
/// uses when painting the overlay.
|
||||
static final SliderComponentShape noOverlay = _EmptySliderComponentShape();
|
||||
}
|
||||
|
||||
/// A special version of [SliderComponentShape] that has a zero size and paints
|
||||
/// nothing.
|
||||
///
|
||||
/// This class is used to create a special instance of a [SliderComponentShape]
|
||||
/// that will not paint any component shape. A static reference is stored in
|
||||
/// [SliderTickMarkShape.noThumb] and [SliderTickMarkShape.noOverlay]. When this value
|
||||
/// is specified for [SliderThemeData.thumbShape], the thumb painting is
|
||||
/// skipped. When this value is specified for [SliderThemeData.overlaySHape],
|
||||
/// the overlay painting is skipped.
|
||||
class _EmptySliderComponentShape extends SliderComponentShape {
|
||||
@override
|
||||
Size getPreferredSize(bool isEnabled, bool isDiscrete) => Size.zero;
|
||||
|
||||
@override
|
||||
void paint(
|
||||
PaintingContext context,
|
||||
Offset center, {
|
||||
Animation<double> activationAnimation,
|
||||
Animation<double> enableAnimation,
|
||||
bool isDiscrete,
|
||||
TextPainter labelPainter,
|
||||
RenderBox parentBox,
|
||||
SliderThemeData sliderTheme,
|
||||
TextDirection textDirection,
|
||||
double value,
|
||||
}) {
|
||||
// no-op.
|
||||
}
|
||||
}
|
||||
|
||||
// The following shapes are the material defaults.
|
||||
@ -894,6 +998,12 @@ class RectangularSliderTrackShape extends SliderTrackShape {
|
||||
bool isDiscrete,
|
||||
bool isEnabled,
|
||||
}) {
|
||||
// If the slider track height is 0, then it makes no difference whether the
|
||||
// track is painted or not, therefore the painting can be a no-op.
|
||||
if (sliderTheme.trackHeight == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Assign the track segment paints, which are left: active, right: inactive,
|
||||
// but reversed for right to left text.
|
||||
final ColorTween activeTrackColorTween = ColorTween(begin: sliderTheme.disabledActiveTrackColor , end: sliderTheme.activeTrackColor);
|
||||
|
@ -590,6 +590,152 @@ void main() {
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
// Only the thumb, overlay, and tick mark have special shortcuts to provide
|
||||
// no-op or empty shapes.
|
||||
//
|
||||
// The track can also be skipped by providing 0 height.
|
||||
//
|
||||
// The value indicator can be skipped by passing the appropriate
|
||||
// [ShowValueIndicator].
|
||||
testWidgets('The slider can skip all of its comoponent painting', (WidgetTester tester) async {
|
||||
// Pump a slider with all shapes skipped.
|
||||
await tester.pumpWidget(_buildApp(
|
||||
ThemeData().sliderTheme.copyWith(
|
||||
trackHeight: 0,
|
||||
overlayShape: SliderComponentShape.noOverlay,
|
||||
thumbShape: SliderComponentShape.noThumb,
|
||||
tickMarkShape: SliderTickMarkShape.noTickMark,
|
||||
showValueIndicator: ShowValueIndicator.never,
|
||||
),
|
||||
value: 0.5,
|
||||
divisions: 4
|
||||
));
|
||||
|
||||
final RenderBox sliderBox = tester.firstRenderObject<RenderBox>(find.byType(Slider));
|
||||
|
||||
expect(sliderBox, paintsNothing);
|
||||
});
|
||||
|
||||
testWidgets('The slider can skip all component painting except the track', (WidgetTester tester) async {
|
||||
// Pump a slider with just a track.
|
||||
await tester.pumpWidget(_buildApp(
|
||||
ThemeData().sliderTheme.copyWith(
|
||||
overlayShape: SliderComponentShape.noOverlay,
|
||||
thumbShape: SliderComponentShape.noThumb,
|
||||
tickMarkShape: SliderTickMarkShape.noTickMark,
|
||||
showValueIndicator: ShowValueIndicator.never,
|
||||
),
|
||||
value: 0.5,
|
||||
divisions: 4
|
||||
));
|
||||
|
||||
final RenderBox sliderBox = tester.firstRenderObject<RenderBox>(find.byType(Slider));
|
||||
|
||||
// Only 2 track segments.
|
||||
expect(sliderBox, paintsExactlyCountTimes(#drawRect, 2));
|
||||
expect(sliderBox, paintsExactlyCountTimes(#drawCircle, 0));
|
||||
expect(sliderBox, paintsExactlyCountTimes(#drawPath, 0));
|
||||
});
|
||||
|
||||
testWidgets('The slider can skip all component painting except the tick marks', (WidgetTester tester) async {
|
||||
// Pump a slider with just tick marks.
|
||||
await tester.pumpWidget(_buildApp(
|
||||
ThemeData().sliderTheme.copyWith(
|
||||
trackHeight: 0,
|
||||
overlayShape: SliderComponentShape.noOverlay,
|
||||
thumbShape: SliderComponentShape.noThumb,
|
||||
showValueIndicator: ShowValueIndicator.never,
|
||||
),
|
||||
value: 0.5,
|
||||
divisions: 4
|
||||
));
|
||||
|
||||
final RenderBox sliderBox = tester.firstRenderObject<RenderBox>(find.byType(Slider));
|
||||
|
||||
// Only 5 tick marks.
|
||||
expect(sliderBox, paintsExactlyCountTimes(#drawRect, 0));
|
||||
expect(sliderBox, paintsExactlyCountTimes(#drawCircle, 5));
|
||||
expect(sliderBox, paintsExactlyCountTimes(#drawPath, 0));
|
||||
});
|
||||
|
||||
testWidgets('The slider can skip all component painting except the thumb', (WidgetTester tester) async {
|
||||
// Pump a slider with just a thumb.
|
||||
await tester.pumpWidget(_buildApp(
|
||||
ThemeData().sliderTheme.copyWith(
|
||||
trackHeight: 0,
|
||||
overlayShape: SliderComponentShape.noOverlay,
|
||||
tickMarkShape: SliderTickMarkShape.noTickMark,
|
||||
showValueIndicator: ShowValueIndicator.never,
|
||||
),
|
||||
value: 0.5,
|
||||
divisions: 4
|
||||
));
|
||||
|
||||
final RenderBox sliderBox = tester.firstRenderObject<RenderBox>(find.byType(Slider));
|
||||
|
||||
// Only 1 thumb.
|
||||
expect(sliderBox, paintsExactlyCountTimes(#drawRect, 0));
|
||||
expect(sliderBox, paintsExactlyCountTimes(#drawCircle, 1));
|
||||
expect(sliderBox, paintsExactlyCountTimes(#drawPath, 0));
|
||||
});
|
||||
|
||||
testWidgets('The slider can skip all component painting except the overlay', (WidgetTester tester) async {
|
||||
// Pump a slider with just an overlay.
|
||||
await tester.pumpWidget(_buildApp(
|
||||
ThemeData().sliderTheme.copyWith(
|
||||
trackHeight: 0,
|
||||
thumbShape: SliderComponentShape.noThumb,
|
||||
tickMarkShape: SliderTickMarkShape.noTickMark,
|
||||
showValueIndicator: ShowValueIndicator.never,
|
||||
),
|
||||
value: 0.5,
|
||||
divisions: 4
|
||||
));
|
||||
|
||||
final RenderBox sliderBox = tester.firstRenderObject<RenderBox>(find.byType(Slider));
|
||||
|
||||
// Tap the center of the track and wait for animations to finish.
|
||||
final Offset center = tester.getCenter(find.byType(Slider));
|
||||
final TestGesture gesture = await tester.startGesture(center);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Only 1 overlay.
|
||||
expect(sliderBox, paintsExactlyCountTimes(#drawRect, 0));
|
||||
expect(sliderBox, paintsExactlyCountTimes(#drawCircle, 1));
|
||||
expect(sliderBox, paintsExactlyCountTimes(#drawPath, 0));
|
||||
|
||||
await gesture.up();
|
||||
});
|
||||
|
||||
testWidgets('The slider can skip all component painting except the value indicator', (WidgetTester tester) async {
|
||||
// Pump a slider with just a value indicator.
|
||||
await tester.pumpWidget(_buildApp(
|
||||
ThemeData().sliderTheme.copyWith(
|
||||
trackHeight: 0,
|
||||
overlayShape: SliderComponentShape.noOverlay,
|
||||
thumbShape: SliderComponentShape.noThumb,
|
||||
tickMarkShape: SliderTickMarkShape.noTickMark,
|
||||
showValueIndicator: ShowValueIndicator.always,
|
||||
),
|
||||
value: 0.5,
|
||||
divisions: 4
|
||||
));
|
||||
|
||||
final RenderBox sliderBox = tester.firstRenderObject<RenderBox>(find.byType(Slider));
|
||||
|
||||
// Tap the center of the track and wait for animations to finish.
|
||||
final Offset center = tester.getCenter(find.byType(Slider));
|
||||
final TestGesture gesture = await tester.startGesture(center);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Only 1 value indicator.
|
||||
expect(sliderBox, paintsExactlyCountTimes(#drawRect, 0));
|
||||
expect(sliderBox, paintsExactlyCountTimes(#drawCircle, 0));
|
||||
expect(sliderBox, paintsExactlyCountTimes(#drawPath, 1));
|
||||
|
||||
await gesture.up();
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildApp(
|
||||
|
Loading…
x
Reference in New Issue
Block a user