Scrollbar display always (#50752)
This commit is contained in:
parent
763f875441
commit
ac3b77bdac
@ -60,6 +60,7 @@ class CupertinoScrollbar extends StatefulWidget {
|
||||
const CupertinoScrollbar({
|
||||
Key key,
|
||||
this.controller,
|
||||
this.isAlwaysShown = false,
|
||||
@required this.child,
|
||||
}) : super(key: key);
|
||||
|
||||
@ -125,6 +126,60 @@ class CupertinoScrollbar extends StatefulWidget {
|
||||
/// {@endtemplate}
|
||||
final ScrollController controller;
|
||||
|
||||
/// {@template flutter.cupertino.cupertinoScrollbar.isAlwaysShown}
|
||||
/// Indicates whether the [Scrollbar] should always be visible.
|
||||
///
|
||||
/// When false, the scrollbar will be shown during scrolling
|
||||
/// and will fade out otherwise.
|
||||
///
|
||||
/// When true, the scrollbar will always be visible and never fade out.
|
||||
///
|
||||
/// The [controller] property must be set in this case.
|
||||
/// It should be passed the relevant [Scrollable]'s [ScrollController].
|
||||
///
|
||||
/// Defaults to false.
|
||||
///
|
||||
/// {@tool snippet}
|
||||
///
|
||||
/// ```dart
|
||||
/// final ScrollController _controllerOne = ScrollController();
|
||||
/// final ScrollController _controllerTwo = ScrollController();
|
||||
///
|
||||
/// build(BuildContext context) {
|
||||
/// return Column(
|
||||
/// children: <Widget>[
|
||||
/// Container(
|
||||
/// height: 200,
|
||||
/// child: Scrollbar(
|
||||
/// isAlwaysShown: true,
|
||||
/// controller: _controllerOne,
|
||||
/// child: ListView.builder(
|
||||
/// controller: _controllerOne,
|
||||
/// itemCount: 120,
|
||||
/// itemBuilder: (BuildContext context, int index)
|
||||
/// => Text('item $index'),
|
||||
/// ),
|
||||
/// ),
|
||||
/// ),
|
||||
/// Container(
|
||||
/// height: 200,
|
||||
/// child: CupertinoScrollbar(
|
||||
/// isAlwaysShown: true,
|
||||
/// controller: _controllerTwo,
|
||||
/// child: SingleChildScrollView(
|
||||
/// controller: _controllerTwo,
|
||||
/// child: SizedBox(height: 2000, width: 500,),
|
||||
/// ),
|
||||
/// ),
|
||||
/// ),
|
||||
/// ],
|
||||
/// );
|
||||
/// }
|
||||
/// ```
|
||||
/// {@end-tool}
|
||||
/// {@endtemplate}
|
||||
final bool isAlwaysShown;
|
||||
|
||||
@override
|
||||
_CupertinoScrollbarState createState() => _CupertinoScrollbarState();
|
||||
}
|
||||
@ -183,6 +238,28 @@ class _CupertinoScrollbarState extends State<CupertinoScrollbar> with TickerProv
|
||||
..color = CupertinoDynamicColor.resolve(_kScrollbarColor, context)
|
||||
..padding = MediaQuery.of(context).padding;
|
||||
}
|
||||
WidgetsBinding.instance.addPostFrameCallback((Duration duration) {
|
||||
if (widget.isAlwaysShown) {
|
||||
assert(widget.controller != null);
|
||||
// Wait one frame and cause an empty scroll event. This allows the
|
||||
// thumb to show immediately when isAlwaysShown is true. A scroll
|
||||
// event is required in order to paint the thumb.
|
||||
widget.controller.position.didUpdateScrollPositionBy(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(CupertinoScrollbar oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (widget.isAlwaysShown != oldWidget.isAlwaysShown) {
|
||||
if (widget.isAlwaysShown == true) {
|
||||
assert(widget.controller != null);
|
||||
_fadeoutAnimationController.animateTo(1.0);
|
||||
} else {
|
||||
_fadeoutAnimationController.reverse();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a [ScrollbarPainter] visually styled like the iOS scrollbar.
|
||||
@ -228,11 +305,13 @@ class _CupertinoScrollbarState extends State<CupertinoScrollbar> with TickerProv
|
||||
}
|
||||
|
||||
void _startFadeoutTimer() {
|
||||
_fadeoutTimer?.cancel();
|
||||
_fadeoutTimer = Timer(_kScrollbarTimeToFade, () {
|
||||
_fadeoutAnimationController.reverse();
|
||||
_fadeoutTimer = null;
|
||||
});
|
||||
if (!widget.isAlwaysShown) {
|
||||
_fadeoutTimer?.cancel();
|
||||
_fadeoutTimer = Timer(_kScrollbarTimeToFade, () {
|
||||
_fadeoutAnimationController.reverse();
|
||||
_fadeoutTimer = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bool _checkVertical() {
|
||||
@ -267,7 +346,7 @@ class _CupertinoScrollbarState extends State<CupertinoScrollbar> with TickerProv
|
||||
_fadeoutTimer?.cancel();
|
||||
_thicknessAnimationController.forward().then<void>(
|
||||
(_) => HapticFeedback.mediumImpact(),
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
void _handleLongPressMoveUpdate(LongPressMoveUpdateDetails details) {
|
||||
|
@ -37,6 +37,7 @@ class Scrollbar extends StatefulWidget {
|
||||
Key key,
|
||||
@required this.child,
|
||||
this.controller,
|
||||
this.isAlwaysShown = false,
|
||||
}) : super(key: key);
|
||||
|
||||
/// The widget below this widget in the tree.
|
||||
@ -50,6 +51,9 @@ class Scrollbar extends StatefulWidget {
|
||||
/// {@macro flutter.cupertino.cupertinoScrollbar.controller}
|
||||
final ScrollController controller;
|
||||
|
||||
/// {@macro flutter.cupertino.cupertinoScrollbar.isAlwaysShown}
|
||||
final bool isAlwaysShown;
|
||||
|
||||
@override
|
||||
_ScrollbarState createState() => _ScrollbarState();
|
||||
}
|
||||
@ -102,11 +106,33 @@ class _ScrollbarState extends State<Scrollbar> with TickerProviderStateMixin {
|
||||
_textDirection = Directionality.of(context);
|
||||
_materialPainter = _buildMaterialScrollbarPainter();
|
||||
_useCupertinoScrollbar = false;
|
||||
WidgetsBinding.instance.addPostFrameCallback((Duration duration) {
|
||||
if (widget.isAlwaysShown) {
|
||||
assert(widget.controller != null);
|
||||
// Wait one frame and cause an empty scroll event. This allows the
|
||||
// thumb to show immediately when isAlwaysShown is true. A scroll
|
||||
// event is required in order to paint the thumb.
|
||||
widget.controller.position.didUpdateScrollPositionBy(0);
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
assert(_useCupertinoScrollbar != null);
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(Scrollbar oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (widget.isAlwaysShown != oldWidget.isAlwaysShown) {
|
||||
assert(widget.controller != null);
|
||||
if (widget.isAlwaysShown == false) {
|
||||
_fadeoutAnimationController.reverse();
|
||||
} else {
|
||||
_fadeoutAnimationController.animateTo(1.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ScrollbarPainter _buildMaterialScrollbarPainter() {
|
||||
return ScrollbarPainter(
|
||||
color: _themeColor,
|
||||
@ -126,17 +152,23 @@ class _ScrollbarState extends State<Scrollbar> with TickerProviderStateMixin {
|
||||
// iOS sub-delegates to the CupertinoScrollbar instead and doesn't handle
|
||||
// scroll notifications here.
|
||||
if (!_useCupertinoScrollbar &&
|
||||
(notification is ScrollUpdateNotification || notification is OverscrollNotification)) {
|
||||
(notification is ScrollUpdateNotification ||
|
||||
notification is OverscrollNotification)) {
|
||||
if (_fadeoutAnimationController.status != AnimationStatus.forward) {
|
||||
_fadeoutAnimationController.forward();
|
||||
}
|
||||
|
||||
_materialPainter.update(notification.metrics, notification.metrics.axisDirection);
|
||||
_fadeoutTimer?.cancel();
|
||||
_fadeoutTimer = Timer(_kScrollbarTimeToFade, () {
|
||||
_fadeoutAnimationController.reverse();
|
||||
_fadeoutTimer = null;
|
||||
});
|
||||
_materialPainter.update(
|
||||
notification.metrics,
|
||||
notification.metrics.axisDirection,
|
||||
);
|
||||
if (!widget.isAlwaysShown) {
|
||||
_fadeoutTimer?.cancel();
|
||||
_fadeoutTimer = Timer(_kScrollbarTimeToFade, () {
|
||||
_fadeoutAnimationController.reverse();
|
||||
_fadeoutTimer = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -154,6 +186,7 @@ class _ScrollbarState extends State<Scrollbar> with TickerProviderStateMixin {
|
||||
if (_useCupertinoScrollbar) {
|
||||
return CupertinoScrollbar(
|
||||
child: widget.child,
|
||||
isAlwaysShown: widget.isAlwaysShown,
|
||||
controller: widget.controller,
|
||||
);
|
||||
}
|
||||
|
@ -163,4 +163,237 @@ void main() {
|
||||
await tester.pump(_kScrollbarTimeToFade);
|
||||
await tester.pump(_kScrollbarFadeDuration);
|
||||
});
|
||||
|
||||
testWidgets('On first render with isAlwaysShown: true, the thumb shows',
|
||||
(WidgetTester tester) async {
|
||||
final ScrollController controller = ScrollController();
|
||||
Widget viewWithScroll() {
|
||||
return Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: MediaQuery(
|
||||
data: const MediaQueryData(),
|
||||
child: PrimaryScrollController(
|
||||
controller: controller,
|
||||
child: CupertinoScrollbar(
|
||||
isAlwaysShown: true,
|
||||
controller: controller,
|
||||
child: const SingleChildScrollView(
|
||||
child: SizedBox(
|
||||
width: 4000.0,
|
||||
height: 4000.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(viewWithScroll());
|
||||
// The scrollbar measures its size on the first frame
|
||||
// and renders starting in the second,
|
||||
//
|
||||
// so pumpAndSettle a frame to allow it to appear.
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byType(CupertinoScrollbar), paints..rrect());
|
||||
});
|
||||
|
||||
testWidgets('On first render with isAlwaysShown: false, the thumb is hidden',
|
||||
(WidgetTester tester) async {
|
||||
final ScrollController controller = ScrollController();
|
||||
Widget viewWithScroll() {
|
||||
return Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: MediaQuery(
|
||||
data: const MediaQueryData(),
|
||||
child: PrimaryScrollController(
|
||||
controller: controller,
|
||||
child: CupertinoScrollbar(
|
||||
isAlwaysShown: false,
|
||||
controller: controller,
|
||||
child: const SingleChildScrollView(
|
||||
child: SizedBox(
|
||||
width: 4000.0,
|
||||
height: 4000.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(viewWithScroll());
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byType(CupertinoScrollbar), isNot(paints..rect()));
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'With isAlwaysShown: true, fling a scroll. While it is still scrolling, set isAlwaysShown: false. The thumb should not fade out until the scrolling stops.',
|
||||
(WidgetTester tester) async {
|
||||
final ScrollController controller = ScrollController();
|
||||
bool isAlwaysShown = true;
|
||||
Widget viewWithScroll() {
|
||||
return StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: MediaQuery(
|
||||
data: const MediaQueryData(),
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
CupertinoScrollbar(
|
||||
isAlwaysShown: isAlwaysShown,
|
||||
controller: controller,
|
||||
child: SingleChildScrollView(
|
||||
controller: controller,
|
||||
child: const SizedBox(
|
||||
width: 4000.0,
|
||||
height: 4000.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: 10,
|
||||
child: CupertinoButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
isAlwaysShown = !isAlwaysShown;
|
||||
});
|
||||
},
|
||||
child: const Text('change isAlwaysShown'),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(viewWithScroll());
|
||||
await tester.pumpAndSettle();
|
||||
await tester.fling(
|
||||
find.byType(SingleChildScrollView),
|
||||
const Offset(0.0, -10.0),
|
||||
10,
|
||||
);
|
||||
expect(find.byType(CupertinoScrollbar), paints..rrect());
|
||||
|
||||
await tester.tap(find.byType(CupertinoButton));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byType(CupertinoScrollbar), isNot(paints..rrect()));
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'With isAlwaysShown: false, fling a scroll. While it is still scrolling, set isAlwaysShown: true. The thumb should not fade even after the scrolling stops',
|
||||
(WidgetTester tester) async {
|
||||
final ScrollController controller = ScrollController();
|
||||
bool isAlwaysShown = false;
|
||||
Widget viewWithScroll() {
|
||||
return StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: MediaQuery(
|
||||
data: const MediaQueryData(),
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
CupertinoScrollbar(
|
||||
isAlwaysShown: isAlwaysShown,
|
||||
controller: controller,
|
||||
child: SingleChildScrollView(
|
||||
controller: controller,
|
||||
child: const SizedBox(
|
||||
width: 4000.0,
|
||||
height: 4000.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: 10,
|
||||
child: CupertinoButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
isAlwaysShown = !isAlwaysShown;
|
||||
});
|
||||
},
|
||||
child: const Text('change isAlwaysShown'),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(viewWithScroll());
|
||||
await tester.pumpAndSettle();
|
||||
await tester.fling(
|
||||
find.byType(SingleChildScrollView),
|
||||
const Offset(0.0, -10.0),
|
||||
10,
|
||||
);
|
||||
expect(find.byType(CupertinoScrollbar), paints..rrect());
|
||||
|
||||
await tester.tap(find.byType(CupertinoButton));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byType(CupertinoScrollbar), paints..rrect());
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'Toggling isAlwaysShown while not scrolling fades the thumb in/out. This works even when you have never scrolled at all yet',
|
||||
(WidgetTester tester) async {
|
||||
final ScrollController controller = ScrollController();
|
||||
bool isAlwaysShown = true;
|
||||
Widget viewWithScroll() {
|
||||
return StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: MediaQuery(
|
||||
data: const MediaQueryData(),
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
CupertinoScrollbar(
|
||||
isAlwaysShown: isAlwaysShown,
|
||||
controller: controller,
|
||||
child: SingleChildScrollView(
|
||||
controller: controller,
|
||||
child: const SizedBox(
|
||||
width: 4000.0,
|
||||
height: 4000.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: 10,
|
||||
child: CupertinoButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
isAlwaysShown = !isAlwaysShown;
|
||||
});
|
||||
},
|
||||
child: const Text('change isAlwaysShown'),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(viewWithScroll());
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byType(CupertinoScrollbar), paints..rrect());
|
||||
|
||||
await tester.tap(find.byType(CupertinoButton));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byType(CupertinoScrollbar), isNot(paints..rrect()));
|
||||
});
|
||||
}
|
||||
|
@ -201,4 +201,211 @@ void main() {
|
||||
expect(scrollbar.controller, isNotNull);
|
||||
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
|
||||
|
||||
testWidgets('On first render with isAlwaysShown: true, the thumb shows',
|
||||
(WidgetTester tester) async {
|
||||
final ScrollController controller = ScrollController();
|
||||
Widget viewWithScroll() {
|
||||
return _buildBoilerplate(
|
||||
child: Theme(
|
||||
data: ThemeData(),
|
||||
child: Scrollbar(
|
||||
isAlwaysShown: true,
|
||||
controller: controller,
|
||||
child: SingleChildScrollView(
|
||||
controller: controller,
|
||||
child: const SizedBox(
|
||||
width: 4000.0,
|
||||
height: 4000.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(viewWithScroll());
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byType(Scrollbar), paints..rect());
|
||||
});
|
||||
|
||||
testWidgets('On first render with isAlwaysShown: false, the thumb is hidden',
|
||||
(WidgetTester tester) async {
|
||||
final ScrollController controller = ScrollController();
|
||||
Widget viewWithScroll() {
|
||||
return _buildBoilerplate(
|
||||
child: Theme(
|
||||
data: ThemeData(),
|
||||
child: Scrollbar(
|
||||
isAlwaysShown: false,
|
||||
controller: controller,
|
||||
child: SingleChildScrollView(
|
||||
controller: controller,
|
||||
child: const SizedBox(
|
||||
width: 4000.0,
|
||||
height: 4000.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(viewWithScroll());
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byType(Scrollbar), isNot(paints..rect()));
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'With isAlwaysShown: true, fling a scroll. While it is still scrolling, set isAlwaysShown: false. The thumb should not fade out until the scrolling stops.',
|
||||
(WidgetTester tester) async {
|
||||
final ScrollController controller = ScrollController();
|
||||
bool isAlwaysShown = true;
|
||||
Widget viewWithScroll() {
|
||||
return _buildBoilerplate(
|
||||
child: StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return Theme(
|
||||
data: ThemeData(),
|
||||
child: Scaffold(
|
||||
floatingActionButton: FloatingActionButton(
|
||||
child: const Icon(Icons.threed_rotation),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
isAlwaysShown = !isAlwaysShown;
|
||||
});
|
||||
},
|
||||
),
|
||||
body: Scrollbar(
|
||||
isAlwaysShown: isAlwaysShown,
|
||||
controller: controller,
|
||||
child: SingleChildScrollView(
|
||||
controller: controller,
|
||||
child: const SizedBox(
|
||||
width: 4000.0,
|
||||
height: 4000.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(viewWithScroll());
|
||||
await tester.pumpAndSettle();
|
||||
await tester.fling(
|
||||
find.byType(SingleChildScrollView),
|
||||
const Offset(0.0, -10.0),
|
||||
10,
|
||||
);
|
||||
expect(find.byType(Scrollbar), paints..rect());
|
||||
|
||||
await tester.tap(find.byType(FloatingActionButton));
|
||||
await tester.pumpAndSettle();
|
||||
// Scrollbar is not showing after scroll finishes
|
||||
expect(find.byType(Scrollbar), isNot(paints..rect()));
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'With isAlwaysShown: false, fling a scroll. While it is still scrolling, set isAlwaysShown: true. The thumb should not fade even after the scrolling stops',
|
||||
(WidgetTester tester) async {
|
||||
final ScrollController controller = ScrollController();
|
||||
bool isAlwaysShown = false;
|
||||
Widget viewWithScroll() {
|
||||
return _buildBoilerplate(
|
||||
child: StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return Theme(
|
||||
data: ThemeData(),
|
||||
child: Scaffold(
|
||||
floatingActionButton: FloatingActionButton(
|
||||
child: const Icon(Icons.threed_rotation),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
isAlwaysShown = !isAlwaysShown;
|
||||
});
|
||||
},
|
||||
),
|
||||
body: Scrollbar(
|
||||
isAlwaysShown: isAlwaysShown,
|
||||
controller: controller,
|
||||
child: SingleChildScrollView(
|
||||
controller: controller,
|
||||
child: const SizedBox(
|
||||
width: 4000.0,
|
||||
height: 4000.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(viewWithScroll());
|
||||
await tester.pumpAndSettle();
|
||||
await tester.fling(
|
||||
find.byType(SingleChildScrollView),
|
||||
const Offset(0.0, -10.0),
|
||||
10,
|
||||
);
|
||||
expect(find.byType(Scrollbar), paints..rect());
|
||||
|
||||
await tester.tap(find.byType(FloatingActionButton));
|
||||
await tester.pumpAndSettle();
|
||||
// Scrollbar is not showing after scroll finishes
|
||||
expect(find.byType(Scrollbar), paints..rect());
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'Toggling isAlwaysShown while not scrolling fades the thumb in/out. This works even when you have never scrolled at all yet',
|
||||
(WidgetTester tester) async {
|
||||
final ScrollController controller = ScrollController();
|
||||
bool isAlwaysShown = true;
|
||||
Widget viewWithScroll() {
|
||||
return _buildBoilerplate(
|
||||
child: StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return Theme(
|
||||
data: ThemeData(),
|
||||
child: Scaffold(
|
||||
floatingActionButton: FloatingActionButton(
|
||||
child: const Icon(Icons.threed_rotation),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
isAlwaysShown = !isAlwaysShown;
|
||||
});
|
||||
},
|
||||
),
|
||||
body: Scrollbar(
|
||||
isAlwaysShown: isAlwaysShown,
|
||||
controller: controller,
|
||||
child: SingleChildScrollView(
|
||||
controller: controller,
|
||||
child: const SizedBox(
|
||||
width: 4000.0,
|
||||
height: 4000.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(viewWithScroll());
|
||||
await tester.pumpAndSettle();
|
||||
final Finder materialScrollbar = find.byType(Scrollbar);
|
||||
expect(materialScrollbar, paints..rect());
|
||||
|
||||
await tester.tap(find.byType(FloatingActionButton));
|
||||
await tester.pumpAndSettle();
|
||||
expect(materialScrollbar, isNot(paints..rect()));
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user