Unverified Commit 26ccbd9f authored by Kate Lovett's avatar Kate Lovett Committed by GitHub

Update Scrollbar behavior for mobile devices (#72531)

parent ff8203dc
...@@ -18,18 +18,18 @@ const Radius _kScrollbarRadius = Radius.circular(8.0); ...@@ -18,18 +18,18 @@ const Radius _kScrollbarRadius = Radius.circular(8.0);
const Duration _kScrollbarFadeDuration = Duration(milliseconds: 300); const Duration _kScrollbarFadeDuration = Duration(milliseconds: 300);
const Duration _kScrollbarTimeToFade = Duration(milliseconds: 600); const Duration _kScrollbarTimeToFade = Duration(milliseconds: 600);
/// A material design scrollbar. /// A Material Design scrollbar.
/// ///
/// To add a scrollbar thumb to a [ScrollView], simply wrap the scroll view /// To add a scrollbar to a [ScrollView], wrap the scroll view
/// widget in a [Scrollbar] widget. /// widget in a [Scrollbar] widget.
/// ///
/// {@macro flutter.widgets.Scrollbar} /// {@macro flutter.widgets.Scrollbar}
/// ///
/// The color of the Scrollbar will change when dragged, as well as when /// The color of the Scrollbar will change when dragged. A hover animation is
/// hovered over. A scrollbar track can also been drawn when triggered by a /// also triggered when used on web and desktop platforms. A scrollbar track
/// hover event, which is controlled by [showTrackOnHover]. The thickness of the /// can also been drawn when triggered by a hover event, which is controlled by
/// track and scrollbar thumb will become larger when hovering, unless /// [showTrackOnHover]. The thickness of the track and scrollbar thumb will
/// overridden by [hoverThickness]. /// become larger when hovering, unless overridden by [hoverThickness].
/// ///
// TODO(Piinks): Add code sample // TODO(Piinks): Add code sample
/// ///
...@@ -50,8 +50,11 @@ class Scrollbar extends RawScrollbar { ...@@ -50,8 +50,11 @@ class Scrollbar extends RawScrollbar {
/// If the [controller] is null, the default behavior is to /// If the [controller] is null, the default behavior is to
/// enable scrollbar dragging using the [PrimaryScrollController]. /// enable scrollbar dragging using the [PrimaryScrollController].
/// ///
/// When null, [thickness] and [radius] defaults will result in a rounded /// When null, [thickness] defaults to 8.0 pixels on desktop and web, and 4.0
/// rectangular thumb that is 8.0 dp wide with a radius of 8.0 pixels. /// pixels when on mobile platforms. A null [radius] will result in a default
/// of an 8.0 pixel circular radius about the corners of the scrollbar thumb,
/// except for when executing on [TargetPlatform.android], which will render the
/// thumb without a radius.
const Scrollbar({ const Scrollbar({
Key? key, Key? key,
required Widget child, required Widget child,
...@@ -66,7 +69,7 @@ class Scrollbar extends RawScrollbar { ...@@ -66,7 +69,7 @@ class Scrollbar extends RawScrollbar {
child: child, child: child,
controller: controller, controller: controller,
isAlwaysShown: isAlwaysShown, isAlwaysShown: isAlwaysShown,
thickness: thickness ?? _kScrollbarThickness, thickness: thickness,
radius: radius, radius: radius,
fadeDuration: _kScrollbarFadeDuration, fadeDuration: _kScrollbarFadeDuration,
timeToFade: _kScrollbarTimeToFade, timeToFade: _kScrollbarTimeToFade,
...@@ -93,6 +96,11 @@ class _ScrollbarState extends RawScrollbarState<Scrollbar> { ...@@ -93,6 +96,11 @@ class _ScrollbarState extends RawScrollbarState<Scrollbar> {
bool _dragIsActive = false; bool _dragIsActive = false;
bool _hoverIsActive = false; bool _hoverIsActive = false;
late ColorScheme _colorScheme; late ColorScheme _colorScheme;
// On Android, scrollbars should match native appearance.
late bool _useAndroidScrollbar;
// Hover events should be ignored on mobile, the exit event cannot be
// triggered, but the enter event can on tap.
late bool _isMobile;
Set<MaterialState> get _states => <MaterialState>{ Set<MaterialState> get _states => <MaterialState>{
if (_dragIsActive) MaterialState.dragged, if (_dragIsActive) MaterialState.dragged,
...@@ -165,7 +173,8 @@ class _ScrollbarState extends RawScrollbarState<Scrollbar> { ...@@ -165,7 +173,8 @@ class _ScrollbarState extends RawScrollbarState<Scrollbar> {
return MaterialStateProperty.resolveWith((Set<MaterialState> states) { return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.hovered) && widget.showTrackOnHover) if (states.contains(MaterialState.hovered) && widget.showTrackOnHover)
return widget.hoverThickness ?? _kScrollbarThicknessWithTrack; return widget.hoverThickness ?? _kScrollbarThicknessWithTrack;
return widget.thickness ?? _kScrollbarThickness; // The default scrollbar thickness is smaller on mobile.
return widget.thickness ?? (_kScrollbarThickness / (_isMobile ? 2 : 1));
}); });
} }
...@@ -181,6 +190,29 @@ class _ScrollbarState extends RawScrollbarState<Scrollbar> { ...@@ -181,6 +190,29 @@ class _ScrollbarState extends RawScrollbarState<Scrollbar> {
}); });
} }
@override
void didChangeDependencies() {
final ThemeData theme = Theme.of(context);
switch (theme.platform) {
case TargetPlatform.android:
_useAndroidScrollbar = true;
_isMobile = true;
break;
case TargetPlatform.iOS:
_useAndroidScrollbar = false;
_isMobile = true;
break;
case TargetPlatform.linux:
case TargetPlatform.fuchsia:
case TargetPlatform.macOS:
case TargetPlatform.windows:
_useAndroidScrollbar = false;
_isMobile = false;
break;
}
super.didChangeDependencies();
}
@override @override
void updateScrollbarPainter() { void updateScrollbarPainter() {
_colorScheme = Theme.of(context).colorScheme; _colorScheme = Theme.of(context).colorScheme;
...@@ -190,8 +222,8 @@ class _ScrollbarState extends RawScrollbarState<Scrollbar> { ...@@ -190,8 +222,8 @@ class _ScrollbarState extends RawScrollbarState<Scrollbar> {
..trackBorderColor = _trackBorderColor.resolve(_states) ..trackBorderColor = _trackBorderColor.resolve(_states)
..textDirection = Directionality.of(context) ..textDirection = Directionality.of(context)
..thickness = _thickness.resolve(_states) ..thickness = _thickness.resolve(_states)
..radius = widget.radius ?? _kScrollbarRadius ..radius = widget.radius ?? (_useAndroidScrollbar ? null : _kScrollbarRadius)
..crossAxisMargin = _kScrollbarMargin ..crossAxisMargin = (_useAndroidScrollbar ? 0.0 : _kScrollbarMargin)
..minLength = _kScrollbarMinLength ..minLength = _kScrollbarMinLength
..padding = MediaQuery.of(context).padding; ..padding = MediaQuery.of(context).padding;
} }
...@@ -210,6 +242,8 @@ class _ScrollbarState extends RawScrollbarState<Scrollbar> { ...@@ -210,6 +242,8 @@ class _ScrollbarState extends RawScrollbarState<Scrollbar> {
@override @override
void handleHover(PointerHoverEvent event) { void handleHover(PointerHoverEvent event) {
// Hover events should not be triggered on mobile.
assert(!_isMobile);
super.handleHover(event); super.handleHover(event);
// Check if the position of the pointer falls over the painted scrollbar // Check if the position of the pointer falls over the painted scrollbar
if (isPointerOverScrollbar(event.position)) { if (isPointerOverScrollbar(event.position)) {
...@@ -225,6 +259,8 @@ class _ScrollbarState extends RawScrollbarState<Scrollbar> { ...@@ -225,6 +259,8 @@ class _ScrollbarState extends RawScrollbarState<Scrollbar> {
@override @override
void handleHoverExit(PointerExitEvent event) { void handleHoverExit(PointerExitEvent event) {
// Hover events should not be triggered on mobile.
assert(!_isMobile);
super.handleHoverExit(event); super.handleHoverExit(event);
setState(() { _hoverIsActive = false; }); setState(() { _hoverIsActive = false; });
_hoverAnimationController.reverse(); _hoverAnimationController.reverse();
......
...@@ -781,6 +781,7 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv ...@@ -781,6 +781,7 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
late Animation<double> _fadeoutOpacityAnimation; late Animation<double> _fadeoutOpacityAnimation;
final GlobalKey _scrollbarPainterKey = GlobalKey(); final GlobalKey _scrollbarPainterKey = GlobalKey();
bool _hoverIsActive = false; bool _hoverIsActive = false;
late bool _isMobile;
/// Used to paint the scrollbar. /// Used to paint the scrollbar.
...@@ -811,6 +812,18 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv ...@@ -811,6 +812,18 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
@override @override
void didChangeDependencies() { void didChangeDependencies() {
super.didChangeDependencies(); super.didChangeDependencies();
switch (defaultTargetPlatform) {
case TargetPlatform.android:
case TargetPlatform.iOS:
_isMobile = true;
break;
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.macOS:
case TargetPlatform.windows:
_isMobile = false;
break;
}
_maybeTriggerScrollbar(); _maybeTriggerScrollbar();
} }
...@@ -1145,20 +1158,28 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv ...@@ -1145,20 +1158,28 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
updateScrollbarPainter(); updateScrollbarPainter();
Widget child = CustomPaint(
key: _scrollbarPainterKey,
foregroundPainter: scrollbarPainter,
child: RepaintBoundary(child: widget.child),
);
if (!_isMobile) {
// Hover events not supported on mobile.
child = MouseRegion(
onExit: handleHoverExit,
onHover: handleHover,
child: child
);
}
return NotificationListener<ScrollNotification>( return NotificationListener<ScrollNotification>(
onNotification: _handleScrollNotification, onNotification: _handleScrollNotification,
child: RepaintBoundary( child: RepaintBoundary(
child: RawGestureDetector( child: RawGestureDetector(
gestures: _gestures, gestures: _gestures,
child: MouseRegion( child: child,
onExit: handleHoverExit,
onHover: handleHover,
child: CustomPaint(
key: _scrollbarPainterKey,
foregroundPainter: scrollbarPainter,
child: RepaintBoundary(child: widget.child),
),
),
), ),
), ),
); );
......
...@@ -30,7 +30,24 @@ void main() { ...@@ -30,7 +30,24 @@ void main() {
)); ));
expect(find.byType(Scrollbar), isNot(paints..rect())); expect(find.byType(Scrollbar), isNot(paints..rect()));
await tester.fling(find.byType(SingleChildScrollView), const Offset(0.0, -10.0), 10.0); await tester.fling(find.byType(SingleChildScrollView), const Offset(0.0, -10.0), 10.0);
expect(find.byType(Scrollbar), paints..rect(rect: const Rect.fromLTRB(800.0 - 12.0, 0.0, 800.0, 600.0))); expect(
find.byType(Scrollbar),
paints
..rect(
rect: const Rect.fromLTRB(796.0, 0.0, 800.0, 600.0),
color: const Color(0x00000000),
)
..line(
p1: const Offset(796.0, 0.0),
p2: const Offset(796.0, 600.0),
strokeWidth: 1.0,
color: const Color(0x00000000),
)
..rect(
rect: const Rect.fromLTRB(796.0, 1.5, 800.0, 91.5),
color: const Color(0x1a000000),
),
);
}); });
testWidgets('Viewport basic test (RTL)', (WidgetTester tester) async { testWidgets('Viewport basic test (RTL)', (WidgetTester tester) async {
...@@ -40,7 +57,24 @@ void main() { ...@@ -40,7 +57,24 @@ void main() {
)); ));
expect(find.byType(Scrollbar), isNot(paints..rect())); expect(find.byType(Scrollbar), isNot(paints..rect()));
await tester.fling(find.byType(SingleChildScrollView), const Offset(0.0, -10.0), 10.0); await tester.fling(find.byType(SingleChildScrollView), const Offset(0.0, -10.0), 10.0);
expect(find.byType(Scrollbar), paints..rect(rect: const Rect.fromLTRB(0.0, 0.0, 12.0, 600.0))); expect(
find.byType(Scrollbar),
paints
..rect(
rect: const Rect.fromLTRB(0.0, 0.0, 4.0, 600.0),
color: const Color(0x00000000),
)
..line(
p1: const Offset(0.0, 0.0),
p2: const Offset(0.0, 600.0),
strokeWidth: 1.0,
color: const Color(0x00000000),
)
..rect(
rect: const Rect.fromLTRB(0.0, 1.5, 4.0, 91.5),
color: const Color(0x1a000000),
),
);
}); });
testWidgets('works with MaterialApp and Scaffold', (WidgetTester tester) async { testWidgets('works with MaterialApp and Scaffold', (WidgetTester tester) async {
...@@ -67,15 +101,24 @@ void main() { ...@@ -67,15 +101,24 @@ void main() {
await tester.pump(); await tester.pump();
await tester.pump(const Duration(milliseconds: 500)); await tester.pump(const Duration(milliseconds: 500));
expect(find.byType(Scrollbar), paints..rect( expect(
rect: const Rect.fromLTWH( find.byType(Scrollbar),
800.0 - 12, // screen width - default thickness and margin paints
0, // the paint area starts from the bottom of the app bar ..rect(
12, // thickness rect: const Rect.fromLTRB(796.0, 0.0, 800.0, 490.0),
// 56 being the height of the app bar color: const Color(0x00000000),
600.0 - 56 - 34 - 20, )
), ..line(
)); p1: const Offset(796.0, 0.0),
p2: const Offset(796.0, 490.0),
strokeWidth: 1.0,
color: const Color(0x00000000),
)
..rect(
rect: const Rect.fromLTWH(796.0, 0.0, 4.0, (600.0 - 56 - 34 - 20) / 4000 * (600 - 56 - 34 - 20)),
color: const Color(0x1a000000),
),
);
}); });
testWidgets("should not paint when there isn't enough space", (WidgetTester tester) async { testWidgets("should not paint when there isn't enough space", (WidgetTester tester) async {
......
...@@ -502,12 +502,27 @@ void main() { ...@@ -502,12 +502,27 @@ void main() {
await tester.pump(); await tester.pump();
// Long press on the scrollbar thumb and expect it to grow // Long press on the scrollbar thumb and expect it to grow
expect(find.byType(Scrollbar), paints..rrect( expect(
rrect: RRect.fromRectAndRadius(const Rect.fromLTWH(778, 0, 20, 300), const Radius.circular(8)), find.byType(Scrollbar),
)); paints
..rect(
rect: const Rect.fromLTRB(780.0, 0.0, 800.0, 600.0),
color: const Color(0x00000000),
)
..line(
p1: const Offset(780.0, 0.0),
p2: const Offset(780.0, 600.0),
strokeWidth: 1.0,
color: const Color(0x00000000),
)
..rect(
rect: const Rect.fromLTRB(780.0, 0.0, 800.0, 300.0),
color: const Color(0x1a000000),
),
);
await tester.pumpWidget(viewWithScroll(radius: const Radius.circular(10))); await tester.pumpWidget(viewWithScroll(radius: const Radius.circular(10)));
expect(find.byType(Scrollbar), paints..rrect( expect(find.byType(Scrollbar), paints..rrect(
rrect: RRect.fromRectAndRadius(const Rect.fromLTWH(778, 0, 20, 300), const Radius.circular(10)), rrect: RRect.fromRectAndRadius(const Rect.fromLTRB(780, 0.0, 800.0, 300.0), const Radius.circular(10)),
)); ));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
...@@ -536,9 +551,21 @@ void main() { ...@@ -536,9 +551,21 @@ void main() {
expect(scrollController.offset, 0.0); expect(scrollController.offset, 0.0);
expect( expect(
find.byType(Scrollbar), find.byType(Scrollbar),
paints..rrect( paints
rrect: RRect.fromLTRBR(790.0, 0.0, 798.0, 360.0, const Radius.circular(8.0)), ..rect(
) rect: const Rect.fromLTRB(796.0, 0.0, 800.0, 600.0),
color: const Color(0x00000000),
)
..line(
p1: const Offset(796.0, 0.0),
p2: const Offset(796.0, 600.0),
strokeWidth: 1.0,
color: const Color(0x00000000),
)
..rect(
rect: const Rect.fromLTRB(796.0, 0.0, 800.0, 360.0),
color: const Color(0x1a000000),
),
); );
// Tap on the track area below the thumb. // Tap on the track area below the thumb.
...@@ -548,12 +575,21 @@ void main() { ...@@ -548,12 +575,21 @@ void main() {
expect(scrollController.offset, 400.0); expect(scrollController.offset, 400.0);
expect( expect(
find.byType(Scrollbar), find.byType(Scrollbar),
paints..rrect( paints
rrect: RRect.fromRectAndRadius( ..rect(
const Rect.fromLTRB(790.0, 240.0, 798.0, 600.0), rect: const Rect.fromLTRB(796.0, 0.0, 800.0, 600.0),
const Radius.circular(8.0), color: const Color(0x00000000),
)
..line(
p1: const Offset(796.0, 0.0),
p2: const Offset(796.0, 600.0),
strokeWidth: 1.0,
color: const Color(0x00000000),
)
..rect(
rect: const Rect.fromLTRB(796.0, 240.0, 800.0, 600.0),
color: const Color(0x1a000000),
), ),
)
); );
// Tap on the track area above the thumb. // Tap on the track area above the thumb.
...@@ -563,9 +599,21 @@ void main() { ...@@ -563,9 +599,21 @@ void main() {
expect(scrollController.offset, 0.0); expect(scrollController.offset, 0.0);
expect( expect(
find.byType(Scrollbar), find.byType(Scrollbar),
paints..rrect( paints
rrect: RRect.fromLTRBR(790.0, 0.0, 798.0, 360.0, const Radius.circular(8.0)), ..rect(
) rect: const Rect.fromLTRB(796.0, 0.0, 800.0, 600.0),
color: const Color(0x00000000),
)
..line(
p1: const Offset(796.0, 0.0),
p2: const Offset(796.0, 600.0),
strokeWidth: 1.0,
color: const Color(0x00000000),
)
..rect(
rect: const Rect.fromLTRB(796.0, 0.0, 800.0, 360.0),
color: const Color(0x1a000000),
),
); );
}); });
...@@ -586,13 +634,21 @@ void main() { ...@@ -586,13 +634,21 @@ void main() {
await tester.pump(const Duration(milliseconds: 500)); await tester.pump(const Duration(milliseconds: 500));
expect( expect(
find.byType(Scrollbar), find.byType(Scrollbar),
paints..rrect( paints
rrect: RRect.fromRectAndRadius( ..rect(
const Rect.fromLTRB(790.0, 3.0, 798.0, 93.0), rect: const Rect.fromLTRB(796.0, 0.0, 800.0, 600.0),
const Radius.circular(8.0), color: const Color(0x00000000),
)
..line(
p1: const Offset(796.0, 0.0),
p2: const Offset(796.0, 600.0),
strokeWidth: 1.0,
color: const Color(0x00000000),
)
..rect(
rect: const Rect.fromLTRB(796.0, 3.0, 800.0, 93.0),
color: const Color(0x1a000000),
), ),
color: const Color(0x1a000000),
),
); );
await tester.pump(const Duration(seconds: 3)); await tester.pump(const Duration(seconds: 3));
...@@ -600,13 +656,21 @@ void main() { ...@@ -600,13 +656,21 @@ void main() {
// Still there. // Still there.
expect( expect(
find.byType(Scrollbar), find.byType(Scrollbar),
paints..rrect( paints
rrect: RRect.fromRectAndRadius( ..rect(
const Rect.fromLTRB(790.0, 3.0, 798.0, 93.0), rect: const Rect.fromLTRB(796.0, 0.0, 800.0, 600.0),
const Radius.circular(8.0), color: const Color(0x00000000),
)
..line(
p1: const Offset(796.0, 0.0),
p2: const Offset(796.0, 600.0),
strokeWidth: 1.0,
color: const Color(0x00000000),
)
..rect(
rect: const Rect.fromLTRB(796.0, 3.0, 800.0, 93.0),
color: const Color(0x1a000000),
), ),
color: const Color(0x1a000000),
),
); );
await gesture.up(); await gesture.up();
...@@ -616,13 +680,21 @@ void main() { ...@@ -616,13 +680,21 @@ void main() {
// Opacity going down now. // Opacity going down now.
expect( expect(
find.byType(Scrollbar), find.byType(Scrollbar),
paints..rrect( paints
rrect: RRect.fromRectAndRadius( ..rect(
const Rect.fromLTRB(790.0, 3.0, 798.0, 93.0), rect: const Rect.fromLTRB(796.0, 0.0, 800.0, 600.0),
const Radius.circular(8.0), color: const Color(0x00000000),
)
..line(
p1: const Offset(796.0, 0.0),
p2: const Offset(796.0, 600.0),
strokeWidth: 1.0,
color: const Color(0x00000000),
)
..rect(
rect: const Rect.fromLTRB(796.0, 3.0, 800.0, 93.0),
color: const Color(0x14000000),
), ),
color: const Color(0x14000000),
),
); );
}); });
...@@ -646,13 +718,21 @@ void main() { ...@@ -646,13 +718,21 @@ void main() {
expect(scrollController.offset, 0.0); expect(scrollController.offset, 0.0);
expect( expect(
find.byType(Scrollbar), find.byType(Scrollbar),
paints..rrect( paints
rrect: RRect.fromRectAndRadius( ..rect(
const Rect.fromLTRB(790.0, 0.0, 798.0, 90.0), rect: const Rect.fromLTRB(796.0, 0.0, 800.0, 600.0),
const Radius.circular(8.0), color: const Color(0x00000000),
)
..line(
p1: const Offset(796.0, 0.0),
p2: const Offset(796.0, 600.0),
strokeWidth: 1.0,
color: const Color(0x00000000),
)
..rect(
rect: const Rect.fromLTRB(796.0, 0.0, 800.0, 90.0),
color: const Color(0x1a000000),
), ),
color: const Color(0x1a000000),
),
); );
// Drag the thumb down to scroll down. // Drag the thumb down to scroll down.
...@@ -662,14 +742,22 @@ void main() { ...@@ -662,14 +742,22 @@ void main() {
expect( expect(
find.byType(Scrollbar), find.byType(Scrollbar),
paints..rrect( paints
rrect: RRect.fromRectAndRadius( ..rect(
const Rect.fromLTRB(790.0, 0.0, 798.0, 90.0), rect: const Rect.fromLTRB(796.0, 0.0, 800.0, 600.0),
const Radius.circular(8.0), color: const Color(0x00000000),
)
..line(
p1: const Offset(796.0, 0.0),
p2: const Offset(796.0, 600.0),
strokeWidth: 1.0,
color: const Color(0x00000000),
)
..rect(
rect: const Rect.fromLTRB(796.0, 0.0, 800.0, 90.0),
// Drag color
color: const Color(0x99000000),
), ),
// Drag color
color: const Color(0x99000000),
),
); );
await dragScrollbarGesture.moveBy(const Offset(0.0, scrollAmount)); await dragScrollbarGesture.moveBy(const Offset(0.0, scrollAmount));
...@@ -682,13 +770,21 @@ void main() { ...@@ -682,13 +770,21 @@ void main() {
expect(scrollController.offset, greaterThan(scrollAmount * 2)); expect(scrollController.offset, greaterThan(scrollAmount * 2));
expect( expect(
find.byType(Scrollbar), find.byType(Scrollbar),
paints..rrect( paints
rrect: RRect.fromRectAndRadius( ..rect(
const Rect.fromLTRB(790.0, 10.0, 798.0, 100.0), rect: const Rect.fromLTRB(796.0, 0.0, 800.0, 600.0),
const Radius.circular(8.0), color: const Color(0x00000000),
)
..line(
p1: const Offset(796.0, 0.0),
p2: const Offset(796.0, 600.0),
strokeWidth: 1.0,
color: const Color(0x00000000),
)
..rect(
rect: const Rect.fromLTRB(796.0, 10.0, 800.0, 100.0),
color: const Color(0x1a000000),
), ),
color: const Color(0x1a000000),
),
); );
}); });
...@@ -737,7 +833,63 @@ void main() { ...@@ -737,7 +833,63 @@ void main() {
color: const Color(0x80000000), color: const Color(0x80000000),
), ),
); );
}); },
variant: const TargetPlatformVariant(<TargetPlatform>{
TargetPlatform.linux,
TargetPlatform.macOS,
TargetPlatform.windows,
TargetPlatform.fuchsia,
}),
);
testWidgets('Hover animation is not triggered on mobile', (WidgetTester tester) async {
final ScrollController scrollController = ScrollController();
await tester.pumpWidget(
MaterialApp(
home: PrimaryScrollController(
controller: scrollController,
child: Scrollbar(
isAlwaysShown: true,
showTrackOnHover: true,
controller: scrollController,
child: const SingleChildScrollView(
child: SizedBox(width: 4000.0, height: 4000.0)
),
),
),
),
);
await tester.pumpAndSettle();
expect(
find.byType(Scrollbar),
paints..rrect(
rrect: RRect.fromRectAndRadius(
const Rect.fromLTRB(794.0, 0.0, 798.0, 90.0),
const Radius.circular(8.0),
),
color: const Color(0x1a000000),
),
);
await tester.tapAt(const Offset(794.0, 5.0));
await tester.pumpAndSettle();
// Tapping on mobile triggers a hover enter event. In this case, the
// Scrollbar should be unchanged since it ignores hover events on mobile.
expect(
find.byType(Scrollbar),
paints..rrect(
rrect: RRect.fromRectAndRadius(
const Rect.fromLTRB(794.0, 0.0, 798.0, 90.0),
const Radius.circular(8.0),
),
color: const Color(0x1a000000),
),
);
},
variant: const TargetPlatformVariant(<TargetPlatform>{
TargetPlatform.iOS,
}),
);
testWidgets('Scrollbar showTrackOnHover', (WidgetTester tester) async { testWidgets('Scrollbar showTrackOnHover', (WidgetTester tester) async {
final ScrollController scrollController = ScrollController(); final ScrollController scrollController = ScrollController();
...@@ -797,5 +949,12 @@ void main() { ...@@ -797,5 +949,12 @@ void main() {
color: const Color(0x80000000), color: const Color(0x80000000),
), ),
); );
}); },
variant: const TargetPlatformVariant(<TargetPlatform>{
TargetPlatform.linux,
TargetPlatform.macOS,
TargetPlatform.windows,
TargetPlatform.fuchsia,
}),
);
} }
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