Unverified Commit e854b8cc authored by Kate Lovett's avatar Kate Lovett Committed by GitHub

Update RawScrollbar to support the track (#97335)

parent 40c4da5c
...@@ -142,7 +142,7 @@ class Scrollbar extends StatelessWidget { ...@@ -142,7 +142,7 @@ class Scrollbar extends StatelessWidget {
) )
final bool? isAlwaysShown; final bool? isAlwaysShown;
/// Controls the track visibility. /// {@macro flutter.widgets.Scrollbar.trackVisibility}
/// ///
/// If this property is null, then [ScrollbarThemeData.trackVisibility] of /// If this property is null, then [ScrollbarThemeData.trackVisibility] of
/// [ThemeData.scrollbarTheme] is used. If that is also null, the default value /// [ThemeData.scrollbarTheme] is used. If that is also null, the default value
...@@ -246,7 +246,7 @@ class _MaterialScrollbar extends RawScrollbar { ...@@ -246,7 +246,7 @@ class _MaterialScrollbar extends RawScrollbar {
required Widget child, required Widget child,
ScrollController? controller, ScrollController? controller,
bool? thumbVisibility, bool? thumbVisibility,
this.trackVisibility, bool? trackVisibility,
this.showTrackOnHover, this.showTrackOnHover,
this.hoverThickness, this.hoverThickness,
double? thickness, double? thickness,
...@@ -261,6 +261,7 @@ class _MaterialScrollbar extends RawScrollbar { ...@@ -261,6 +261,7 @@ class _MaterialScrollbar extends RawScrollbar {
thumbVisibility: thumbVisibility, thumbVisibility: thumbVisibility,
thickness: thickness, thickness: thickness,
radius: radius, radius: radius,
trackVisibility: trackVisibility,
fadeDuration: _kScrollbarFadeDuration, fadeDuration: _kScrollbarFadeDuration,
timeToFade: _kScrollbarTimeToFade, timeToFade: _kScrollbarTimeToFade,
pressDuration: Duration.zero, pressDuration: Duration.zero,
...@@ -269,7 +270,6 @@ class _MaterialScrollbar extends RawScrollbar { ...@@ -269,7 +270,6 @@ class _MaterialScrollbar extends RawScrollbar {
scrollbarOrientation: scrollbarOrientation, scrollbarOrientation: scrollbarOrientation,
); );
final bool? trackVisibility;
final bool? showTrackOnHover; final bool? showTrackOnHover;
final double? hoverThickness; final double? hoverThickness;
...@@ -350,7 +350,7 @@ class _MaterialScrollbarState extends RawScrollbarState<_MaterialScrollbar> { ...@@ -350,7 +350,7 @@ class _MaterialScrollbarState extends RawScrollbarState<_MaterialScrollbar> {
final Color onSurface = _colorScheme.onSurface; final Color onSurface = _colorScheme.onSurface;
final Brightness brightness = _colorScheme.brightness; final Brightness brightness = _colorScheme.brightness;
return MaterialStateProperty.resolveWith((Set<MaterialState> states) { return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (_trackVisibility.resolve(states)) { if (showScrollbar && _trackVisibility.resolve(states)) {
return _scrollbarTheme.trackColor?.resolve(states) return _scrollbarTheme.trackColor?.resolve(states)
?? (brightness == Brightness.light ?? (brightness == Brightness.light
? onSurface.withOpacity(0.03) ? onSurface.withOpacity(0.03)
...@@ -364,7 +364,7 @@ class _MaterialScrollbarState extends RawScrollbarState<_MaterialScrollbar> { ...@@ -364,7 +364,7 @@ class _MaterialScrollbarState extends RawScrollbarState<_MaterialScrollbar> {
final Color onSurface = _colorScheme.onSurface; final Color onSurface = _colorScheme.onSurface;
final Brightness brightness = _colorScheme.brightness; final Brightness brightness = _colorScheme.brightness;
return MaterialStateProperty.resolveWith((Set<MaterialState> states) { return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (_trackVisibility.resolve(states)) { if (showScrollbar && _trackVisibility.resolve(states)) {
return _scrollbarTheme.trackBorderColor?.resolve(states) return _scrollbarTheme.trackBorderColor?.resolve(states)
?? (brightness == Brightness.light ?? (brightness == Brightness.light
? onSurface.withOpacity(0.1) ? onSurface.withOpacity(0.1)
......
...@@ -875,6 +875,9 @@ class RawScrollbar extends StatefulWidget { ...@@ -875,6 +875,9 @@ class RawScrollbar extends StatefulWidget {
this.thumbColor, this.thumbColor,
this.minThumbLength = _kMinThumbExtent, this.minThumbLength = _kMinThumbExtent,
this.minOverscrollLength, this.minOverscrollLength,
this.trackVisibility,
this.trackColor,
this.trackBorderColor,
this.fadeDuration = _kScrollbarFadeDuration, this.fadeDuration = _kScrollbarFadeDuration,
this.timeToFade = _kScrollbarTimeToFade, this.timeToFade = _kScrollbarTimeToFade,
this.pressDuration = Duration.zero, this.pressDuration = Duration.zero,
...@@ -894,6 +897,10 @@ class RawScrollbar extends StatefulWidget { ...@@ -894,6 +897,10 @@ class RawScrollbar extends StatefulWidget {
'Scrollbar thumb appearance should only be controlled with thumbVisibility, ' 'Scrollbar thumb appearance should only be controlled with thumbVisibility, '
'isAlwaysShown is deprecated.' 'isAlwaysShown is deprecated.'
), ),
assert(
!((thumbVisibility == false || isAlwaysShown == false) && trackVisibility == true),
'A scrollbar track cannot be drawn without a scrollbar thumb.'
),
assert(minThumbLength != null), assert(minThumbLength != null),
assert(minThumbLength >= 0), assert(minThumbLength >= 0),
assert(minOverscrollLength == null || minOverscrollLength <= minThumbLength), assert(minOverscrollLength == null || minOverscrollLength <= minThumbLength),
...@@ -1199,6 +1206,36 @@ class RawScrollbar extends StatefulWidget { ...@@ -1199,6 +1206,36 @@ class RawScrollbar extends StatefulWidget {
/// When null, it will default to the value of [minThumbLength]. /// When null, it will default to the value of [minThumbLength].
final double? minOverscrollLength; final double? minOverscrollLength;
/// {@template flutter.widgets.Scrollbar.trackVisibility}
/// Indicates that the scrollbar track should be visible.
///
/// When true, the scrollbar track will always be visible so long as the thumb
/// is visible. If the scrollbar thumb is not visible, the track will not be
/// visible either.
///
/// Defaults to false when null.
/// {@endtemplate}
///
/// Subclass [Scrollbar] can hide and show the scrollbar thumb in response to
/// [MaterialState]s by using [ScrollbarThemeData.trackVisibility].
final bool? trackVisibility;
/// The color of the scrollbar track.
///
/// The scrollbar track will only be visible when [trackVisibility] and
/// [thumbVisibility] are true.
///
/// If null, defaults to Color(0x08000000).
final Color? trackColor;
/// The color of the scrollbar track's border.
///
/// The scrollbar track will only be visible when [trackVisibility] and
/// [thumbVisibility] are true.
///
/// If null, defaults to Color(0x1a000000).
final Color? trackBorderColor;
/// The [Duration] of the fade animation. /// The [Duration] of the fade animation.
/// ///
/// Cannot be null, defaults to a [Duration] of 300 milliseconds. /// Cannot be null, defaults to a [Duration] of 300 milliseconds.
...@@ -1304,6 +1341,8 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv ...@@ -1304,6 +1341,8 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
@protected @protected
bool get showScrollbar => widget.isAlwaysShown ?? widget.thumbVisibility ?? false; bool get showScrollbar => widget.isAlwaysShown ?? widget.thumbVisibility ?? false;
bool get _showTrack => showScrollbar && (widget.trackVisibility ?? false);
/// Overridable getter to indicate is gestures should be enabled on the /// Overridable getter to indicate is gestures should be enabled on the
/// scrollbar. /// scrollbar.
/// ///
...@@ -1470,6 +1509,8 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv ...@@ -1470,6 +1509,8 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
void updateScrollbarPainter() { void updateScrollbarPainter() {
scrollbarPainter scrollbarPainter
..color = widget.thumbColor ?? const Color(0x66BCBCBC) ..color = widget.thumbColor ?? const Color(0x66BCBCBC)
..trackColor = _showTrack ? const Color(0x08000000) : const Color(0x00000000)
..trackBorderColor = _showTrack ? const Color(0x1a000000) : const Color(0x00000000)
..textDirection = Directionality.of(context) ..textDirection = Directionality.of(context)
..thickness = widget.thickness ?? _kScrollbarThickness ..thickness = widget.thickness ?? _kScrollbarThickness
..radius = widget.radius ..radius = widget.radius
......
...@@ -2245,4 +2245,71 @@ void main() { ...@@ -2245,4 +2245,71 @@ void main() {
expect(painter.shouldRepaint(createPainter(minOverscrollLength: 1.0)), true); expect(painter.shouldRepaint(createPainter(minOverscrollLength: 1.0)), true);
expect(painter.shouldRepaint(createPainter(scrollbarOrientation: ScrollbarOrientation.bottom)), true); expect(painter.shouldRepaint(createPainter(scrollbarOrientation: ScrollbarOrientation.bottom)), true);
}); });
testWidgets('Scrollbar track can be drawn', (WidgetTester tester) async {
final ScrollController scrollController = ScrollController();
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: MediaQuery(
data: const MediaQueryData(),
child: PrimaryScrollController(
controller: scrollController,
child: RawScrollbar(
thumbVisibility: true,
trackVisibility: true,
controller: scrollController,
child: const SingleChildScrollView(
child: SizedBox(width: 4000.0, height: 4000.0),
),
),
),
),
),
);
await tester.pumpAndSettle();
expect(scrollController.offset, 0.0);
expect(
find.byType(RawScrollbar),
paints
..rect(
rect: const Rect.fromLTRB(794.0, 0.0, 800.0, 600.0),
color: const Color(0x08000000),
)
..line(
p1: const Offset(794.0, 0.0),
p2: const Offset(794.0, 600.0),
strokeWidth: 1.0,
color: const Color(0x1a000000),
)
..rect(
rect: const Rect.fromLTRB(794.0, 0.0, 800.0, 90.0),
color: const Color(0x66BCBCBC),
),
);
});
testWidgets('Scrollbar asserts that a visible track has a visible thumb', (WidgetTester tester) async {
final ScrollController scrollController = ScrollController();
Widget _buildApp() {
return Directionality(
textDirection: TextDirection.ltr,
child: MediaQuery(
data: const MediaQueryData(),
child: PrimaryScrollController(
controller: scrollController,
child: RawScrollbar(
thumbVisibility: false,
trackVisibility: true,
controller: scrollController,
child: const SingleChildScrollView(
child: SizedBox(width: 4000.0, height: 4000.0),
),
),
),
),
);
}
expect(() => tester.pumpWidget(_buildApp()), throwsAssertionError);
});
} }
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