828 lines
27 KiB
Dart
828 lines
27 KiB
Dart
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import 'dart:ui' as ui;
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/rendering.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
// The const represents the starting position of the scrollbar thumb for
|
|
// the below tests. The thumb is 90 pixels long, and 8 pixels wide, with a 2
|
|
// pixel margin to the right edge of the viewport.
|
|
const Rect _kMaterialDesignInitialThumbRect = Rect.fromLTRB(790.0, 0.0, 798.0, 90.0);
|
|
const Radius _kDefaultThumbRadius = Radius.circular(8.0);
|
|
const Color _kDefaultIdleThumbColor = Color(0x1a000000);
|
|
const Color _kDefaultDragThumbColor = Color(0x99000000);
|
|
|
|
void main() {
|
|
test('ScrollbarThemeData copyWith, ==, hashCode basics', () {
|
|
expect(const ScrollbarThemeData(), const ScrollbarThemeData().copyWith());
|
|
expect(const ScrollbarThemeData().hashCode, const ScrollbarThemeData().copyWith().hashCode);
|
|
});
|
|
|
|
test('ScrollbarThemeData lerp special cases', () {
|
|
expect(ScrollbarThemeData.lerp(null, null, 0), const ScrollbarThemeData());
|
|
const data = ScrollbarThemeData();
|
|
expect(identical(ScrollbarThemeData.lerp(data, data, 0.5), data), true);
|
|
});
|
|
|
|
testWidgets(
|
|
'Passing no ScrollbarTheme returns defaults',
|
|
(WidgetTester tester) async {
|
|
final scrollController = ScrollController();
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: ThemeData(
|
|
useMaterial3: false,
|
|
scrollbarTheme: ScrollbarThemeData(
|
|
trackVisibility: WidgetStateProperty.resolveWith(
|
|
(Set<WidgetState> states) => states.contains(WidgetState.hovered),
|
|
),
|
|
),
|
|
),
|
|
home: ScrollConfiguration(
|
|
behavior: const NoScrollbarBehavior(),
|
|
child: Scrollbar(
|
|
thumbVisibility: true,
|
|
controller: scrollController,
|
|
child: SingleChildScrollView(
|
|
controller: scrollController,
|
|
child: const SizedBox(width: 4000.0, height: 4000.0),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
// Idle scrollbar behavior
|
|
expect(
|
|
find.byType(Scrollbar),
|
|
paints..rrect(
|
|
rrect: RRect.fromRectAndRadius(_kMaterialDesignInitialThumbRect, _kDefaultThumbRadius),
|
|
color: _kDefaultIdleThumbColor,
|
|
),
|
|
);
|
|
|
|
// Drag scrollbar behavior
|
|
const scrollAmount = 10.0;
|
|
final TestGesture dragScrollbarGesture = await tester.startGesture(const Offset(797.0, 45.0));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(
|
|
find.byType(Scrollbar),
|
|
paints..rrect(
|
|
rrect: RRect.fromRectAndRadius(_kMaterialDesignInitialThumbRect, _kDefaultThumbRadius),
|
|
// Drag color
|
|
color: _kDefaultDragThumbColor,
|
|
),
|
|
);
|
|
|
|
await dragScrollbarGesture.moveBy(const Offset(0.0, scrollAmount));
|
|
await tester.pumpAndSettle();
|
|
await dragScrollbarGesture.up();
|
|
await tester.pumpAndSettle();
|
|
|
|
// Hover scrollbar behavior
|
|
final TestGesture gesture = await tester.createGesture(kind: ui.PointerDeviceKind.mouse);
|
|
await gesture.addPointer();
|
|
await gesture.moveTo(const Offset(794.0, 5.0));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(
|
|
find.byType(Scrollbar),
|
|
paints
|
|
..rect(
|
|
rect: const Rect.fromLTRB(784.0, 0.0, 800.0, 600.0),
|
|
color: const Color(0x08000000),
|
|
)
|
|
..line(
|
|
p1: const Offset(784.0, 0.0),
|
|
p2: const Offset(784.0, 600.0),
|
|
strokeWidth: 1.0,
|
|
color: const Color(0x1a000000),
|
|
)
|
|
..rrect(
|
|
rrect: RRect.fromRectAndRadius(
|
|
// Scrollbar thumb is larger
|
|
const Rect.fromLTRB(786.0, 10.0, 798.0, 100.0),
|
|
_kDefaultThumbRadius,
|
|
),
|
|
// Hover color
|
|
color: const Color(0x80000000),
|
|
),
|
|
);
|
|
|
|
scrollController.dispose();
|
|
},
|
|
variant: const TargetPlatformVariant(<TargetPlatform>{
|
|
TargetPlatform.linux,
|
|
TargetPlatform.macOS,
|
|
TargetPlatform.windows,
|
|
TargetPlatform.fuchsia,
|
|
}),
|
|
);
|
|
|
|
testWidgets(
|
|
'Scrollbar uses values from ScrollbarTheme',
|
|
(WidgetTester tester) async {
|
|
final ScrollbarThemeData scrollbarTheme = _scrollbarTheme();
|
|
final scrollController = ScrollController();
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: ThemeData(scrollbarTheme: scrollbarTheme),
|
|
home: ScrollConfiguration(
|
|
behavior: const NoScrollbarBehavior(),
|
|
child: Scrollbar(
|
|
thumbVisibility: true,
|
|
controller: scrollController,
|
|
child: SingleChildScrollView(
|
|
controller: scrollController,
|
|
child: const SizedBox(width: 4000.0, height: 4000.0),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
// Idle scrollbar behavior
|
|
expect(
|
|
find.byType(Scrollbar),
|
|
paints..rrect(
|
|
rrect: RRect.fromRectAndRadius(
|
|
const Rect.fromLTRB(785.0, 10.0, 795.0, 97.0),
|
|
const Radius.circular(6.0),
|
|
),
|
|
color: const Color(0xff4caf50),
|
|
),
|
|
);
|
|
|
|
// Drag scrollbar behavior
|
|
const scrollAmount = 10.0;
|
|
final TestGesture dragScrollbarGesture = await tester.startGesture(const Offset(797.0, 45.0));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(
|
|
find.byType(Scrollbar),
|
|
paints..rrect(
|
|
rrect: RRect.fromRectAndRadius(
|
|
const Rect.fromLTRB(785.0, 10.0, 795.0, 97.0),
|
|
const Radius.circular(6.0),
|
|
),
|
|
// Drag color
|
|
color: const Color(0xfff44336),
|
|
),
|
|
);
|
|
|
|
await dragScrollbarGesture.moveBy(const Offset(0.0, scrollAmount));
|
|
await tester.pumpAndSettle();
|
|
await dragScrollbarGesture.up();
|
|
await tester.pumpAndSettle();
|
|
|
|
// Hover scrollbar behavior
|
|
final TestGesture gesture = await tester.createGesture(kind: ui.PointerDeviceKind.mouse);
|
|
await gesture.addPointer();
|
|
await gesture.moveTo(const Offset(794.0, 15.0));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(
|
|
find.byType(Scrollbar),
|
|
paints
|
|
..rect(
|
|
rect: const Rect.fromLTRB(770.0, 0.0, 800.0, 600.0),
|
|
color: const Color(0xff000000),
|
|
)
|
|
..line(
|
|
p1: const Offset(770.0, 00.0),
|
|
p2: const Offset(770.0, 600.0),
|
|
strokeWidth: 1.0,
|
|
color: const Color(0xffffeb3b),
|
|
)
|
|
..rrect(
|
|
rrect: RRect.fromRectAndRadius(
|
|
// Scrollbar thumb is larger
|
|
const Rect.fromLTRB(775.0, 20.0, 795.0, 107.0),
|
|
const Radius.circular(6.0),
|
|
),
|
|
// Hover color
|
|
color: const Color(0xff2196f3),
|
|
),
|
|
);
|
|
|
|
scrollController.dispose();
|
|
},
|
|
variant: const TargetPlatformVariant(<TargetPlatform>{
|
|
TargetPlatform.linux,
|
|
TargetPlatform.macOS,
|
|
TargetPlatform.windows,
|
|
TargetPlatform.fuchsia,
|
|
}),
|
|
);
|
|
|
|
testWidgets('Scrollbar uses values from ScrollbarTheme if exists instead of values from Theme', (
|
|
WidgetTester tester,
|
|
) async {
|
|
final ScrollbarThemeData scrollbarTheme = _scrollbarTheme();
|
|
final scrollController = ScrollController();
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: ThemeData(scrollbarTheme: scrollbarTheme),
|
|
home: ScrollConfiguration(
|
|
behavior: const NoScrollbarBehavior(),
|
|
child: ScrollbarTheme(
|
|
data: _scrollbarTheme().copyWith(
|
|
thumbColor: WidgetStateProperty.all(const Color(0xFF000000)),
|
|
),
|
|
child: Scrollbar(
|
|
thumbVisibility: true,
|
|
controller: scrollController,
|
|
child: SingleChildScrollView(
|
|
controller: scrollController,
|
|
child: const SizedBox(width: 4000.0, height: 4000.0),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
// Idle scrollbar behavior
|
|
expect(
|
|
find.byType(Scrollbar),
|
|
paints..rrect(
|
|
rrect: RRect.fromRectAndRadius(
|
|
const Rect.fromLTRB(785.0, 10.0, 795.0, 97.0),
|
|
const Radius.circular(6.0),
|
|
),
|
|
color: const Color(0xFF000000),
|
|
),
|
|
);
|
|
|
|
scrollController.dispose();
|
|
});
|
|
|
|
testWidgets(
|
|
'ScrollbarTheme can disable gestures',
|
|
(WidgetTester tester) async {
|
|
final scrollController = ScrollController();
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: ThemeData(
|
|
useMaterial3: false,
|
|
scrollbarTheme: const ScrollbarThemeData(interactive: false),
|
|
),
|
|
home: Scrollbar(
|
|
thumbVisibility: true,
|
|
controller: scrollController,
|
|
child: SingleChildScrollView(
|
|
controller: scrollController,
|
|
child: const SizedBox(width: 4000.0, height: 4000.0),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
// Idle scrollbar behavior
|
|
expect(
|
|
find.byType(Scrollbar),
|
|
paints..rrect(
|
|
rrect: RRect.fromRectAndRadius(_kMaterialDesignInitialThumbRect, _kDefaultThumbRadius),
|
|
color: _kDefaultIdleThumbColor,
|
|
),
|
|
);
|
|
|
|
// Try to drag scrollbar.
|
|
const scrollAmount = 10.0;
|
|
final TestGesture dragScrollbarGesture = await tester.startGesture(const Offset(797.0, 45.0));
|
|
await tester.pumpAndSettle();
|
|
await dragScrollbarGesture.moveBy(const Offset(0.0, scrollAmount));
|
|
await tester.pumpAndSettle();
|
|
await dragScrollbarGesture.up();
|
|
await tester.pumpAndSettle();
|
|
// Expect no change
|
|
expect(
|
|
find.byType(Scrollbar),
|
|
paints..rrect(
|
|
rrect: RRect.fromRectAndRadius(_kMaterialDesignInitialThumbRect, _kDefaultThumbRadius),
|
|
color: _kDefaultIdleThumbColor,
|
|
),
|
|
);
|
|
|
|
scrollController.dispose();
|
|
},
|
|
variant: const TargetPlatformVariant(<TargetPlatform>{TargetPlatform.fuchsia}),
|
|
);
|
|
|
|
testWidgets(
|
|
'Scrollbar.interactive takes priority over ScrollbarTheme',
|
|
(WidgetTester tester) async {
|
|
final scrollController = ScrollController();
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: ThemeData(
|
|
useMaterial3: false,
|
|
scrollbarTheme: const ScrollbarThemeData(interactive: false),
|
|
),
|
|
home: Scrollbar(
|
|
interactive: true,
|
|
thumbVisibility: true,
|
|
controller: scrollController,
|
|
child: SingleChildScrollView(
|
|
controller: scrollController,
|
|
child: const SizedBox(width: 4000.0, height: 4000.0),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
// Idle scrollbar behavior
|
|
expect(
|
|
find.byType(Scrollbar),
|
|
paints..rrect(
|
|
rrect: RRect.fromRectAndRadius(_kMaterialDesignInitialThumbRect, _kDefaultThumbRadius),
|
|
color: _kDefaultIdleThumbColor,
|
|
),
|
|
);
|
|
|
|
// Drag scrollbar.
|
|
const scrollAmount = 10.0;
|
|
final TestGesture dragScrollbarGesture = await tester.startGesture(const Offset(797.0, 45.0));
|
|
await tester.pumpAndSettle();
|
|
await dragScrollbarGesture.moveBy(const Offset(0.0, scrollAmount));
|
|
await tester.pumpAndSettle();
|
|
await dragScrollbarGesture.up();
|
|
await tester.pumpAndSettle();
|
|
// Gestures handled by Scrollbar.
|
|
expect(
|
|
find.byType(Scrollbar),
|
|
paints..rrect(
|
|
rrect: RRect.fromRectAndRadius(
|
|
const Rect.fromLTRB(790.0, 10.0, 798.0, 100.0),
|
|
_kDefaultThumbRadius,
|
|
),
|
|
color: _kDefaultIdleThumbColor,
|
|
),
|
|
);
|
|
|
|
scrollController.dispose();
|
|
},
|
|
variant: const TargetPlatformVariant(<TargetPlatform>{TargetPlatform.fuchsia}),
|
|
);
|
|
|
|
testWidgets(
|
|
'Scrollbar widget properties take priority over theme',
|
|
(WidgetTester tester) async {
|
|
const thickness = 4.0;
|
|
const edgeMargin = 2.0;
|
|
const radius = Radius.circular(3.0);
|
|
final scrollController = ScrollController();
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: ThemeData(
|
|
colorScheme: const ColorScheme.light(),
|
|
scrollbarTheme: ScrollbarThemeData(
|
|
trackVisibility: WidgetStateProperty.resolveWith(
|
|
(Set<WidgetState> states) => states.contains(WidgetState.hovered),
|
|
),
|
|
),
|
|
),
|
|
home: ScrollConfiguration(
|
|
behavior: const NoScrollbarBehavior(),
|
|
child: Scrollbar(
|
|
thickness: thickness,
|
|
thumbVisibility: true,
|
|
radius: radius,
|
|
controller: scrollController,
|
|
child: SingleChildScrollView(
|
|
controller: scrollController,
|
|
child: const SizedBox(width: 4000.0, height: 4000.0),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
// Idle scrollbar behavior
|
|
expect(
|
|
find.byType(Scrollbar),
|
|
paints..rrect(
|
|
rrect: RRect.fromRectAndRadius(
|
|
const Rect.fromLTRB(800 - thickness - edgeMargin, 0.0, 798.0, 90.0),
|
|
const Radius.circular(3.0),
|
|
),
|
|
color: _kDefaultIdleThumbColor,
|
|
),
|
|
);
|
|
|
|
// Drag scrollbar behavior.
|
|
const scrollAmount = 10.0;
|
|
final TestGesture dragScrollbarGesture = await tester.startGesture(const Offset(797.0, 45.0));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(
|
|
find.byType(Scrollbar),
|
|
paints..rrect(
|
|
rrect: RRect.fromRectAndRadius(
|
|
const Rect.fromLTRB(800 - thickness - edgeMargin, 0.0, 798.0, 90.0),
|
|
const Radius.circular(3.0),
|
|
),
|
|
// Drag color
|
|
color: _kDefaultDragThumbColor,
|
|
),
|
|
);
|
|
|
|
await dragScrollbarGesture.moveBy(const Offset(0.0, scrollAmount));
|
|
await tester.pumpAndSettle();
|
|
await dragScrollbarGesture.up();
|
|
await tester.pumpAndSettle();
|
|
|
|
// Hover scrollbar behavior.
|
|
final TestGesture gesture = await tester.createGesture(kind: ui.PointerDeviceKind.mouse);
|
|
await gesture.addPointer();
|
|
await gesture.moveTo(const Offset(794.0, 5.0));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(
|
|
find.byType(Scrollbar),
|
|
paints
|
|
..rect(
|
|
rect: const Rect.fromLTRB(792.0, 0.0, 800.0, 600.0),
|
|
color: const Color(0x08000000),
|
|
)
|
|
..line(
|
|
p1: const Offset(792.0, 0.0),
|
|
p2: const Offset(792.0, 600.0),
|
|
strokeWidth: 1.0,
|
|
color: const Color(0x1a000000),
|
|
)
|
|
..rrect(
|
|
rrect: RRect.fromRectAndRadius(
|
|
const Rect.fromLTRB(800 - thickness - edgeMargin, 10.0, 798.0, 100.0),
|
|
const Radius.circular(3.0),
|
|
),
|
|
// Hover color
|
|
color: const Color(0x80000000),
|
|
),
|
|
);
|
|
|
|
scrollController.dispose();
|
|
},
|
|
variant: const TargetPlatformVariant(<TargetPlatform>{
|
|
TargetPlatform.linux,
|
|
TargetPlatform.macOS,
|
|
TargetPlatform.windows,
|
|
TargetPlatform.fuchsia,
|
|
}),
|
|
);
|
|
|
|
testWidgets(
|
|
'ThemeData colorScheme is used when no ScrollbarTheme is set',
|
|
(WidgetTester tester) async {
|
|
(ScrollController, Widget) buildFrame(ThemeData appTheme) {
|
|
final scrollController = ScrollController();
|
|
final ThemeData theme = appTheme.copyWith(
|
|
scrollbarTheme: ScrollbarThemeData(
|
|
trackVisibility: WidgetStateProperty.resolveWith(
|
|
(Set<WidgetState> states) => states.contains(WidgetState.hovered),
|
|
),
|
|
),
|
|
);
|
|
return (
|
|
scrollController,
|
|
MaterialApp(
|
|
theme: theme,
|
|
home: ScrollConfiguration(
|
|
behavior: const NoScrollbarBehavior(),
|
|
child: Scrollbar(
|
|
thumbVisibility: true,
|
|
controller: scrollController,
|
|
child: SingleChildScrollView(
|
|
controller: scrollController,
|
|
child: const SizedBox(width: 4000.0, height: 4000.0),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
// Scrollbar defaults for light themes:
|
|
// - coloring based on ColorScheme.onSurface
|
|
final (ScrollController controller1, Widget frame1) = buildFrame(
|
|
ThemeData(colorScheme: const ColorScheme.light()),
|
|
);
|
|
await tester.pumpWidget(frame1);
|
|
await tester.pumpAndSettle();
|
|
// Idle scrollbar behavior
|
|
expect(
|
|
find.byType(Scrollbar),
|
|
paints..rrect(
|
|
rrect: RRect.fromRectAndRadius(_kMaterialDesignInitialThumbRect, _kDefaultThumbRadius),
|
|
color: _kDefaultIdleThumbColor,
|
|
),
|
|
);
|
|
|
|
// Drag scrollbar behavior
|
|
const scrollAmount = 10.0;
|
|
TestGesture dragScrollbarGesture = await tester.startGesture(const Offset(797.0, 45.0));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(
|
|
find.byType(Scrollbar),
|
|
paints..rrect(
|
|
rrect: RRect.fromRectAndRadius(_kMaterialDesignInitialThumbRect, _kDefaultThumbRadius),
|
|
// Drag color
|
|
color: _kDefaultDragThumbColor,
|
|
),
|
|
);
|
|
|
|
await dragScrollbarGesture.moveBy(const Offset(0.0, scrollAmount));
|
|
await tester.pumpAndSettle();
|
|
await dragScrollbarGesture.up();
|
|
await tester.pumpAndSettle();
|
|
|
|
// Hover scrollbar behavior
|
|
final TestGesture hoverGesture = await tester.createGesture(kind: ui.PointerDeviceKind.mouse);
|
|
await hoverGesture.addPointer();
|
|
addTearDown(hoverGesture.removePointer);
|
|
await hoverGesture.moveTo(const Offset(794.0, 5.0));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(
|
|
find.byType(Scrollbar),
|
|
paints
|
|
..rect(
|
|
rect: const Rect.fromLTRB(784.0, 0.0, 800.0, 600.0),
|
|
color: const Color(0x08000000),
|
|
)
|
|
..line(
|
|
p1: const Offset(784.0, 0.0),
|
|
p2: const Offset(784.0, 600.0),
|
|
strokeWidth: 1.0,
|
|
color: const Color(0x1a000000),
|
|
)
|
|
..rrect(
|
|
rrect: RRect.fromRectAndRadius(
|
|
// Scrollbar thumb is larger
|
|
const Rect.fromLTRB(786.0, 10.0, 798.0, 100.0),
|
|
_kDefaultThumbRadius,
|
|
),
|
|
// Hover color
|
|
color: const Color(0x80000000),
|
|
),
|
|
);
|
|
|
|
await hoverGesture.moveTo(Offset.zero);
|
|
|
|
// Scrollbar defaults for dark themes:
|
|
// - coloring slightly different based on ColorScheme.onSurface
|
|
final (ScrollController controller2, Widget frame2) = buildFrame(
|
|
ThemeData(colorScheme: const ColorScheme.dark()),
|
|
);
|
|
await tester.pumpWidget(frame2);
|
|
await tester.pumpAndSettle(); // Theme change animation
|
|
|
|
// Idle scrollbar behavior
|
|
expect(
|
|
find.byType(Scrollbar),
|
|
paints..rrect(
|
|
rrect: RRect.fromRectAndRadius(
|
|
const Rect.fromLTRB(790.0, 10.0, 798.0, 100.0),
|
|
_kDefaultThumbRadius,
|
|
),
|
|
color: const Color(0x4dffffff),
|
|
),
|
|
);
|
|
|
|
// Drag scrollbar behavior
|
|
dragScrollbarGesture = await tester.startGesture(const Offset(797.0, 45.0));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(
|
|
find.byType(Scrollbar),
|
|
paints..rrect(
|
|
rrect: RRect.fromRectAndRadius(
|
|
const Rect.fromLTRB(790.0, 10.0, 798.0, 100.0),
|
|
_kDefaultThumbRadius,
|
|
),
|
|
// Drag color
|
|
color: const Color(0xbfffffff),
|
|
),
|
|
);
|
|
|
|
await dragScrollbarGesture.moveBy(const Offset(0.0, scrollAmount));
|
|
await tester.pumpAndSettle();
|
|
await dragScrollbarGesture.up();
|
|
await tester.pumpAndSettle();
|
|
|
|
// Hover scrollbar behavior
|
|
await hoverGesture.moveTo(const Offset(794.0, 5.0));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(
|
|
find.byType(Scrollbar),
|
|
paints
|
|
..rect(
|
|
rect: const Rect.fromLTRB(784.0, 0.0, 800.0, 600.0),
|
|
color: const Color(0x0dffffff),
|
|
)
|
|
..line(
|
|
p1: const Offset(784.0, 0.0),
|
|
p2: const Offset(784.0, 600.0),
|
|
strokeWidth: 1.0,
|
|
color: const Color(0x40ffffff),
|
|
)
|
|
..rrect(
|
|
rrect: RRect.fromRectAndRadius(
|
|
// Scrollbar thumb is larger
|
|
const Rect.fromLTRB(786.0, 20.0, 798.0, 110.0),
|
|
_kDefaultThumbRadius,
|
|
),
|
|
// Hover color
|
|
color: const Color(0xa6ffffff),
|
|
),
|
|
);
|
|
|
|
controller1.dispose();
|
|
controller2.dispose();
|
|
},
|
|
variant: const TargetPlatformVariant(<TargetPlatform>{
|
|
TargetPlatform.linux,
|
|
TargetPlatform.macOS,
|
|
TargetPlatform.windows,
|
|
TargetPlatform.fuchsia,
|
|
}),
|
|
);
|
|
|
|
testWidgets(
|
|
'ScrollbarThemeData.trackVisibility test',
|
|
(WidgetTester tester) async {
|
|
final scrollController = ScrollController();
|
|
bool? getTrackVisibility(Set<WidgetState> states) {
|
|
return true;
|
|
}
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: ThemeData(useMaterial3: false).copyWith(
|
|
scrollbarTheme: _scrollbarTheme(
|
|
trackVisibility: WidgetStateProperty.resolveWith(getTrackVisibility),
|
|
),
|
|
),
|
|
home: ScrollConfiguration(
|
|
behavior: const NoScrollbarBehavior(),
|
|
child: Scrollbar(
|
|
thumbVisibility: true,
|
|
controller: scrollController,
|
|
child: SingleChildScrollView(
|
|
controller: scrollController,
|
|
child: const SizedBox(width: 4000.0, height: 4000.0),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(
|
|
find.byType(Scrollbar),
|
|
paints
|
|
..rect(color: const Color(0x08000000))
|
|
..line(strokeWidth: 1.0, color: const Color(0x1a000000))
|
|
..rrect(color: const Color(0xff4caf50)),
|
|
);
|
|
|
|
scrollController.dispose();
|
|
},
|
|
variant: const TargetPlatformVariant(<TargetPlatform>{
|
|
TargetPlatform.linux,
|
|
TargetPlatform.macOS,
|
|
TargetPlatform.windows,
|
|
TargetPlatform.fuchsia,
|
|
}),
|
|
);
|
|
|
|
testWidgets('Default ScrollbarTheme debugFillProperties', (WidgetTester tester) async {
|
|
final builder = DiagnosticPropertiesBuilder();
|
|
const ScrollbarThemeData().debugFillProperties(builder);
|
|
|
|
final List<String> description = builder.properties
|
|
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
|
|
.map((DiagnosticsNode node) => node.toString())
|
|
.toList();
|
|
|
|
expect(description, <String>[]);
|
|
});
|
|
|
|
testWidgets('ScrollbarTheme implements debugFillProperties', (WidgetTester tester) async {
|
|
final builder = DiagnosticPropertiesBuilder();
|
|
ScrollbarThemeData(
|
|
thickness: WidgetStateProperty.resolveWith(_getThickness),
|
|
thumbVisibility: WidgetStateProperty.resolveWith(_getThumbVisibility),
|
|
radius: const Radius.circular(3.0),
|
|
thumbColor: WidgetStateProperty.resolveWith(_getThumbColor),
|
|
trackColor: WidgetStateProperty.resolveWith(_getTrackColor),
|
|
trackBorderColor: WidgetStateProperty.resolveWith(_getTrackBorderColor),
|
|
crossAxisMargin: 3.0,
|
|
mainAxisMargin: 6.0,
|
|
minThumbLength: 120.0,
|
|
).debugFillProperties(builder);
|
|
|
|
final List<String> description = builder.properties
|
|
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
|
|
.map((DiagnosticsNode node) => node.toString())
|
|
.toList();
|
|
|
|
expect(description, <String>[
|
|
"thumbVisibility: Instance of '_WidgetStatePropertyWith<bool?>'",
|
|
"thickness: Instance of '_WidgetStatePropertyWith<double?>'",
|
|
'radius: Radius.circular(3.0)',
|
|
"thumbColor: Instance of '_WidgetStatePropertyWith<Color?>'",
|
|
"trackColor: Instance of '_WidgetStatePropertyWith<Color?>'",
|
|
"trackBorderColor: Instance of '_WidgetStatePropertyWith<Color?>'",
|
|
'crossAxisMargin: 3.0',
|
|
'mainAxisMargin: 6.0',
|
|
'minThumbLength: 120.0',
|
|
]);
|
|
|
|
// On the web, Dart doubles and ints are backed by the same kind of object because
|
|
// JavaScript does not support integers. So, the Dart double "4.0" is identical
|
|
// to "4", which results in the web evaluating to the value "4" regardless of which
|
|
// one is used. This results in a difference for doubles in debugFillProperties between
|
|
// the web and the rest of Flutter's target platforms.
|
|
}, skip: kIsWeb); // [intended]
|
|
}
|
|
|
|
class NoScrollbarBehavior extends ScrollBehavior {
|
|
const NoScrollbarBehavior();
|
|
|
|
@override
|
|
Widget buildScrollbar(BuildContext context, Widget child, ScrollableDetails details) => child;
|
|
}
|
|
|
|
ScrollbarThemeData _scrollbarTheme({
|
|
WidgetStateProperty<double?>? thickness,
|
|
WidgetStateProperty<bool?>? trackVisibility,
|
|
WidgetStateProperty<bool?>? thumbVisibility,
|
|
Radius radius = const Radius.circular(6.0),
|
|
WidgetStateProperty<Color?>? thumbColor,
|
|
WidgetStateProperty<Color?>? trackColor,
|
|
WidgetStateProperty<Color?>? trackBorderColor,
|
|
double crossAxisMargin = 5.0,
|
|
double mainAxisMargin = 10.0,
|
|
double minThumbLength = 50.0,
|
|
}) {
|
|
return ScrollbarThemeData(
|
|
thickness: thickness ?? WidgetStateProperty.resolveWith(_getThickness),
|
|
trackVisibility:
|
|
trackVisibility ??
|
|
WidgetStateProperty.resolveWith(
|
|
(Set<WidgetState> states) => states.contains(WidgetState.hovered),
|
|
),
|
|
thumbVisibility: thumbVisibility,
|
|
radius: radius,
|
|
thumbColor: thumbColor ?? WidgetStateProperty.resolveWith(_getThumbColor),
|
|
trackColor: trackColor ?? WidgetStateProperty.resolveWith(_getTrackColor),
|
|
trackBorderColor: trackBorderColor ?? WidgetStateProperty.resolveWith(_getTrackBorderColor),
|
|
crossAxisMargin: crossAxisMargin,
|
|
mainAxisMargin: mainAxisMargin,
|
|
minThumbLength: minThumbLength,
|
|
);
|
|
}
|
|
|
|
double? _getThickness(Set<WidgetState> states) {
|
|
if (states.contains(WidgetState.hovered)) {
|
|
return 20.0;
|
|
}
|
|
return 10.0;
|
|
}
|
|
|
|
bool? _getThumbVisibility(Set<WidgetState> states) => true;
|
|
|
|
Color? _getThumbColor(Set<WidgetState> states) {
|
|
if (states.contains(WidgetState.dragged)) {
|
|
return Colors.red;
|
|
}
|
|
if (states.contains(WidgetState.hovered)) {
|
|
return Colors.blue;
|
|
}
|
|
return Colors.green;
|
|
}
|
|
|
|
Color? _getTrackColor(Set<WidgetState> states) {
|
|
if (states.contains(WidgetState.hovered)) {
|
|
return Colors.black;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
Color? _getTrackBorderColor(Set<WidgetState> states) {
|
|
if (states.contains(WidgetState.hovered)) {
|
|
return Colors.yellow;
|
|
}
|
|
return null;
|
|
}
|