Update Scrollbar behavior for mobile devices (#72531)
This commit is contained in:
parent
ff8203dcdc
commit
26ccbd9ff6
@ -18,18 +18,18 @@ const Radius _kScrollbarRadius = Radius.circular(8.0);
|
||||
const Duration _kScrollbarFadeDuration = Duration(milliseconds: 300);
|
||||
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.
|
||||
///
|
||||
/// {@macro flutter.widgets.Scrollbar}
|
||||
///
|
||||
/// The color of the Scrollbar will change when dragged, as well as when
|
||||
/// hovered over. A scrollbar track can also been drawn when triggered by a
|
||||
/// hover event, which is controlled by [showTrackOnHover]. The thickness of the
|
||||
/// track and scrollbar thumb will become larger when hovering, unless
|
||||
/// overridden by [hoverThickness].
|
||||
/// The color of the Scrollbar will change when dragged. A hover animation is
|
||||
/// also triggered when used on web and desktop platforms. A scrollbar track
|
||||
/// can also been drawn when triggered by a hover event, which is controlled by
|
||||
/// [showTrackOnHover]. The thickness of the track and scrollbar thumb will
|
||||
/// become larger when hovering, unless overridden by [hoverThickness].
|
||||
///
|
||||
// TODO(Piinks): Add code sample
|
||||
///
|
||||
@ -50,8 +50,11 @@ class Scrollbar extends RawScrollbar {
|
||||
/// If the [controller] is null, the default behavior is to
|
||||
/// enable scrollbar dragging using the [PrimaryScrollController].
|
||||
///
|
||||
/// When null, [thickness] and [radius] defaults will result in a rounded
|
||||
/// rectangular thumb that is 8.0 dp wide with a radius of 8.0 pixels.
|
||||
/// When null, [thickness] defaults to 8.0 pixels on desktop and web, and 4.0
|
||||
/// 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({
|
||||
Key? key,
|
||||
required Widget child,
|
||||
@ -66,7 +69,7 @@ class Scrollbar extends RawScrollbar {
|
||||
child: child,
|
||||
controller: controller,
|
||||
isAlwaysShown: isAlwaysShown,
|
||||
thickness: thickness ?? _kScrollbarThickness,
|
||||
thickness: thickness,
|
||||
radius: radius,
|
||||
fadeDuration: _kScrollbarFadeDuration,
|
||||
timeToFade: _kScrollbarTimeToFade,
|
||||
@ -93,6 +96,11 @@ class _ScrollbarState extends RawScrollbarState<Scrollbar> {
|
||||
bool _dragIsActive = false;
|
||||
bool _hoverIsActive = false;
|
||||
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>{
|
||||
if (_dragIsActive) MaterialState.dragged,
|
||||
@ -165,7 +173,8 @@ class _ScrollbarState extends RawScrollbarState<Scrollbar> {
|
||||
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.hovered) && widget.showTrackOnHover)
|
||||
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> {
|
||||
});
|
||||
}
|
||||
|
||||
@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
|
||||
void updateScrollbarPainter() {
|
||||
_colorScheme = Theme.of(context).colorScheme;
|
||||
@ -190,8 +222,8 @@ class _ScrollbarState extends RawScrollbarState<Scrollbar> {
|
||||
..trackBorderColor = _trackBorderColor.resolve(_states)
|
||||
..textDirection = Directionality.of(context)
|
||||
..thickness = _thickness.resolve(_states)
|
||||
..radius = widget.radius ?? _kScrollbarRadius
|
||||
..crossAxisMargin = _kScrollbarMargin
|
||||
..radius = widget.radius ?? (_useAndroidScrollbar ? null : _kScrollbarRadius)
|
||||
..crossAxisMargin = (_useAndroidScrollbar ? 0.0 : _kScrollbarMargin)
|
||||
..minLength = _kScrollbarMinLength
|
||||
..padding = MediaQuery.of(context).padding;
|
||||
}
|
||||
@ -210,6 +242,8 @@ class _ScrollbarState extends RawScrollbarState<Scrollbar> {
|
||||
|
||||
@override
|
||||
void handleHover(PointerHoverEvent event) {
|
||||
// Hover events should not be triggered on mobile.
|
||||
assert(!_isMobile);
|
||||
super.handleHover(event);
|
||||
// Check if the position of the pointer falls over the painted scrollbar
|
||||
if (isPointerOverScrollbar(event.position)) {
|
||||
@ -225,6 +259,8 @@ class _ScrollbarState extends RawScrollbarState<Scrollbar> {
|
||||
|
||||
@override
|
||||
void handleHoverExit(PointerExitEvent event) {
|
||||
// Hover events should not be triggered on mobile.
|
||||
assert(!_isMobile);
|
||||
super.handleHoverExit(event);
|
||||
setState(() { _hoverIsActive = false; });
|
||||
_hoverAnimationController.reverse();
|
||||
|
@ -781,6 +781,7 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
|
||||
late Animation<double> _fadeoutOpacityAnimation;
|
||||
final GlobalKey _scrollbarPainterKey = GlobalKey();
|
||||
bool _hoverIsActive = false;
|
||||
late bool _isMobile;
|
||||
|
||||
|
||||
/// Used to paint the scrollbar.
|
||||
@ -811,6 +812,18 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
|
||||
@override
|
||||
void 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();
|
||||
}
|
||||
|
||||
@ -1145,20 +1158,28 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
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>(
|
||||
onNotification: _handleScrollNotification,
|
||||
child: RepaintBoundary(
|
||||
child: RawGestureDetector(
|
||||
gestures: _gestures,
|
||||
child: MouseRegion(
|
||||
onExit: handleHoverExit,
|
||||
onHover: handleHover,
|
||||
child: CustomPaint(
|
||||
key: _scrollbarPainterKey,
|
||||
foregroundPainter: scrollbarPainter,
|
||||
child: RepaintBoundary(child: widget.child),
|
||||
),
|
||||
),
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -30,7 +30,24 @@ void main() {
|
||||
));
|
||||
expect(find.byType(Scrollbar), isNot(paints..rect()));
|
||||
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 {
|
||||
@ -40,7 +57,24 @@ void main() {
|
||||
));
|
||||
expect(find.byType(Scrollbar), isNot(paints..rect()));
|
||||
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 {
|
||||
@ -67,15 +101,24 @@ void main() {
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(milliseconds: 500));
|
||||
|
||||
expect(find.byType(Scrollbar), paints..rect(
|
||||
rect: const Rect.fromLTWH(
|
||||
800.0 - 12, // screen width - default thickness and margin
|
||||
0, // the paint area starts from the bottom of the app bar
|
||||
12, // thickness
|
||||
// 56 being the height of the app bar
|
||||
600.0 - 56 - 34 - 20,
|
||||
),
|
||||
));
|
||||
expect(
|
||||
find.byType(Scrollbar),
|
||||
paints
|
||||
..rect(
|
||||
rect: const Rect.fromLTRB(796.0, 0.0, 800.0, 490.0),
|
||||
color: const Color(0x00000000),
|
||||
)
|
||||
..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 {
|
||||
|
@ -502,12 +502,27 @@ void main() {
|
||||
await tester.pump();
|
||||
|
||||
// Long press on the scrollbar thumb and expect it to grow
|
||||
expect(find.byType(Scrollbar), paints..rrect(
|
||||
rrect: RRect.fromRectAndRadius(const Rect.fromLTWH(778, 0, 20, 300), const Radius.circular(8)),
|
||||
));
|
||||
expect(
|
||||
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)));
|
||||
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();
|
||||
@ -536,9 +551,21 @@ void main() {
|
||||
expect(scrollController.offset, 0.0);
|
||||
expect(
|
||||
find.byType(Scrollbar),
|
||||
paints..rrect(
|
||||
rrect: RRect.fromLTRBR(790.0, 0.0, 798.0, 360.0, const Radius.circular(8.0)),
|
||||
)
|
||||
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, 0.0, 800.0, 360.0),
|
||||
color: const Color(0x1a000000),
|
||||
),
|
||||
);
|
||||
|
||||
// Tap on the track area below the thumb.
|
||||
@ -548,12 +575,21 @@ void main() {
|
||||
expect(scrollController.offset, 400.0);
|
||||
expect(
|
||||
find.byType(Scrollbar),
|
||||
paints..rrect(
|
||||
rrect: RRect.fromRectAndRadius(
|
||||
const Rect.fromLTRB(790.0, 240.0, 798.0, 600.0),
|
||||
const Radius.circular(8.0),
|
||||
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, 240.0, 800.0, 600.0),
|
||||
color: const Color(0x1a000000),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
// Tap on the track area above the thumb.
|
||||
@ -563,9 +599,21 @@ void main() {
|
||||
expect(scrollController.offset, 0.0);
|
||||
expect(
|
||||
find.byType(Scrollbar),
|
||||
paints..rrect(
|
||||
rrect: RRect.fromLTRBR(790.0, 0.0, 798.0, 360.0, const Radius.circular(8.0)),
|
||||
)
|
||||
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, 0.0, 800.0, 360.0),
|
||||
color: const Color(0x1a000000),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
@ -586,13 +634,21 @@ void main() {
|
||||
await tester.pump(const Duration(milliseconds: 500));
|
||||
expect(
|
||||
find.byType(Scrollbar),
|
||||
paints..rrect(
|
||||
rrect: RRect.fromRectAndRadius(
|
||||
const Rect.fromLTRB(790.0, 3.0, 798.0, 93.0),
|
||||
const Radius.circular(8.0),
|
||||
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, 3.0, 800.0, 93.0),
|
||||
color: const Color(0x1a000000),
|
||||
),
|
||||
color: const Color(0x1a000000),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pump(const Duration(seconds: 3));
|
||||
@ -600,13 +656,21 @@ void main() {
|
||||
// Still there.
|
||||
expect(
|
||||
find.byType(Scrollbar),
|
||||
paints..rrect(
|
||||
rrect: RRect.fromRectAndRadius(
|
||||
const Rect.fromLTRB(790.0, 3.0, 798.0, 93.0),
|
||||
const Radius.circular(8.0),
|
||||
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, 3.0, 800.0, 93.0),
|
||||
color: const Color(0x1a000000),
|
||||
),
|
||||
color: const Color(0x1a000000),
|
||||
),
|
||||
);
|
||||
|
||||
await gesture.up();
|
||||
@ -616,13 +680,21 @@ void main() {
|
||||
// Opacity going down now.
|
||||
expect(
|
||||
find.byType(Scrollbar),
|
||||
paints..rrect(
|
||||
rrect: RRect.fromRectAndRadius(
|
||||
const Rect.fromLTRB(790.0, 3.0, 798.0, 93.0),
|
||||
const Radius.circular(8.0),
|
||||
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, 3.0, 800.0, 93.0),
|
||||
color: const Color(0x14000000),
|
||||
),
|
||||
color: const Color(0x14000000),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
@ -646,13 +718,21 @@ void main() {
|
||||
expect(scrollController.offset, 0.0);
|
||||
expect(
|
||||
find.byType(Scrollbar),
|
||||
paints..rrect(
|
||||
rrect: RRect.fromRectAndRadius(
|
||||
const Rect.fromLTRB(790.0, 0.0, 798.0, 90.0),
|
||||
const Radius.circular(8.0),
|
||||
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, 0.0, 800.0, 90.0),
|
||||
color: const Color(0x1a000000),
|
||||
),
|
||||
color: const Color(0x1a000000),
|
||||
),
|
||||
);
|
||||
|
||||
// Drag the thumb down to scroll down.
|
||||
@ -662,14 +742,22 @@ void main() {
|
||||
|
||||
expect(
|
||||
find.byType(Scrollbar),
|
||||
paints..rrect(
|
||||
rrect: RRect.fromRectAndRadius(
|
||||
const Rect.fromLTRB(790.0, 0.0, 798.0, 90.0),
|
||||
const Radius.circular(8.0),
|
||||
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, 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));
|
||||
@ -682,13 +770,21 @@ void main() {
|
||||
expect(scrollController.offset, greaterThan(scrollAmount * 2));
|
||||
expect(
|
||||
find.byType(Scrollbar),
|
||||
paints..rrect(
|
||||
rrect: RRect.fromRectAndRadius(
|
||||
const Rect.fromLTRB(790.0, 10.0, 798.0, 100.0),
|
||||
const Radius.circular(8.0),
|
||||
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, 10.0, 800.0, 100.0),
|
||||
color: const Color(0x1a000000),
|
||||
),
|
||||
color: const Color(0x1a000000),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
@ -737,7 +833,63 @@ void main() {
|
||||
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 {
|
||||
final ScrollController scrollController = ScrollController();
|
||||
@ -797,5 +949,12 @@ void main() {
|
||||
color: const Color(0x80000000),
|
||||
),
|
||||
);
|
||||
});
|
||||
},
|
||||
variant: const TargetPlatformVariant(<TargetPlatform>{
|
||||
TargetPlatform.linux,
|
||||
TargetPlatform.macOS,
|
||||
TargetPlatform.windows,
|
||||
TargetPlatform.fuchsia,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user