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 {
)
final bool? isAlwaysShown;
/// Controls the track visibility.
/// {@macro flutter.widgets.Scrollbar.trackVisibility}
///
/// If this property is null, then [ScrollbarThemeData.trackVisibility] of
/// [ThemeData.scrollbarTheme] is used. If that is also null, the default value
......@@ -246,7 +246,7 @@ class _MaterialScrollbar extends RawScrollbar {
required Widget child,
ScrollController? controller,
bool? thumbVisibility,
this.trackVisibility,
bool? trackVisibility,
this.showTrackOnHover,
this.hoverThickness,
double? thickness,
......@@ -261,6 +261,7 @@ class _MaterialScrollbar extends RawScrollbar {
thumbVisibility: thumbVisibility,
thickness: thickness,
radius: radius,
trackVisibility: trackVisibility,
fadeDuration: _kScrollbarFadeDuration,
timeToFade: _kScrollbarTimeToFade,
pressDuration: Duration.zero,
......@@ -269,7 +270,6 @@ class _MaterialScrollbar extends RawScrollbar {
scrollbarOrientation: scrollbarOrientation,
);
final bool? trackVisibility;
final bool? showTrackOnHover;
final double? hoverThickness;
......@@ -350,7 +350,7 @@ class _MaterialScrollbarState extends RawScrollbarState<_MaterialScrollbar> {
final Color onSurface = _colorScheme.onSurface;
final Brightness brightness = _colorScheme.brightness;
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (_trackVisibility.resolve(states)) {
if (showScrollbar && _trackVisibility.resolve(states)) {
return _scrollbarTheme.trackColor?.resolve(states)
?? (brightness == Brightness.light
? onSurface.withOpacity(0.03)
......@@ -364,7 +364,7 @@ class _MaterialScrollbarState extends RawScrollbarState<_MaterialScrollbar> {
final Color onSurface = _colorScheme.onSurface;
final Brightness brightness = _colorScheme.brightness;
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (_trackVisibility.resolve(states)) {
if (showScrollbar && _trackVisibility.resolve(states)) {
return _scrollbarTheme.trackBorderColor?.resolve(states)
?? (brightness == Brightness.light
? onSurface.withOpacity(0.1)
......
......@@ -875,6 +875,9 @@ class RawScrollbar extends StatefulWidget {
this.thumbColor,
this.minThumbLength = _kMinThumbExtent,
this.minOverscrollLength,
this.trackVisibility,
this.trackColor,
this.trackBorderColor,
this.fadeDuration = _kScrollbarFadeDuration,
this.timeToFade = _kScrollbarTimeToFade,
this.pressDuration = Duration.zero,
......@@ -894,6 +897,10 @@ class RawScrollbar extends StatefulWidget {
'Scrollbar thumb appearance should only be controlled with thumbVisibility, '
'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 >= 0),
assert(minOverscrollLength == null || minOverscrollLength <= minThumbLength),
......@@ -1199,6 +1206,36 @@ class RawScrollbar extends StatefulWidget {
/// When null, it will default to the value of [minThumbLength].
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.
///
/// Cannot be null, defaults to a [Duration] of 300 milliseconds.
......@@ -1304,6 +1341,8 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
@protected
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
/// scrollbar.
///
......@@ -1470,6 +1509,8 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
void updateScrollbarPainter() {
scrollbarPainter
..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)
..thickness = widget.thickness ?? _kScrollbarThickness
..radius = widget.radius
......
......@@ -2245,4 +2245,71 @@ void main() {
expect(painter.shouldRepaint(createPainter(minOverscrollLength: 1.0)), 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