Unverified Commit 281f1421 authored by Viren Khatri's avatar Viren Khatri Committed by GitHub

adds `trackRadius` to `ScrollbarPainter` and `RawScrollbar` (#98018)

parent 9369bd32
...@@ -86,6 +86,7 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter { ...@@ -86,6 +86,7 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter {
double mainAxisMargin = 0.0, double mainAxisMargin = 0.0,
double crossAxisMargin = 0.0, double crossAxisMargin = 0.0,
Radius? radius, Radius? radius,
Radius? trackRadius,
OutlinedBorder? shape, OutlinedBorder? shape,
double minLength = _kMinThumbExtent, double minLength = _kMinThumbExtent,
double? minOverscrollLength, double? minOverscrollLength,
...@@ -117,6 +118,7 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter { ...@@ -117,6 +118,7 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter {
_minLength = minLength, _minLength = minLength,
_trackColor = trackColor, _trackColor = trackColor,
_trackBorderColor = trackBorderColor, _trackBorderColor = trackBorderColor,
_trackRadius = trackRadius,
_scrollbarOrientation = scrollbarOrientation, _scrollbarOrientation = scrollbarOrientation,
_minOverscrollLength = minOverscrollLength ?? minLength, _minOverscrollLength = minOverscrollLength ?? minLength,
_ignorePointer = ignorePointer { _ignorePointer = ignorePointer {
...@@ -159,6 +161,19 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter { ...@@ -159,6 +161,19 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter {
notifyListeners(); notifyListeners();
} }
/// [Radius] of corners of the Scrollbar's track.
///
/// Scrollbar's track will be rectangular if [trackRadius] is null.
Radius? get trackRadius => _trackRadius;
Radius? _trackRadius;
set trackRadius(Radius? value) {
if (trackRadius == value)
return;
_trackRadius = value;
notifyListeners();
}
/// [TextDirection] of the [BuildContext] which dictates the side of the /// [TextDirection] of the [BuildContext] which dictates the side of the
/// screen the scrollbar appears in (the trailing side). Must be set prior to /// screen the scrollbar appears in (the trailing side). Must be set prior to
/// calling paint. /// calling paint.
...@@ -496,7 +511,11 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter { ...@@ -496,7 +511,11 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter {
// Paint if the opacity dictates visibility // Paint if the opacity dictates visibility
if (fadeoutOpacityAnimation.value != 0.0) { if (fadeoutOpacityAnimation.value != 0.0) {
// Track // Track
if (trackRadius == null) {
canvas.drawRect(_trackRect!, _paintTrack()); canvas.drawRect(_trackRect!, _paintTrack());
} else {
canvas.drawRRect(RRect.fromRectAndRadius(_trackRect!, trackRadius!), _paintTrack());
}
// Track Border // Track Border
canvas.drawLine(borderStart, borderEnd, _paintTrack(isBorder: true)); canvas.drawLine(borderStart, borderEnd, _paintTrack(isBorder: true));
if (radius != null) { if (radius != null) {
...@@ -741,6 +760,7 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter { ...@@ -741,6 +760,7 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter {
|| mainAxisMargin != oldDelegate.mainAxisMargin || mainAxisMargin != oldDelegate.mainAxisMargin
|| crossAxisMargin != oldDelegate.crossAxisMargin || crossAxisMargin != oldDelegate.crossAxisMargin
|| radius != oldDelegate.radius || radius != oldDelegate.radius
|| trackRadius != oldDelegate.trackRadius
|| shape != oldDelegate.shape || shape != oldDelegate.shape
|| padding != oldDelegate.padding || padding != oldDelegate.padding
|| minLength != oldDelegate.minLength || minLength != oldDelegate.minLength
...@@ -880,6 +900,7 @@ class RawScrollbar extends StatefulWidget { ...@@ -880,6 +900,7 @@ class RawScrollbar extends StatefulWidget {
this.minThumbLength = _kMinThumbExtent, this.minThumbLength = _kMinThumbExtent,
this.minOverscrollLength, this.minOverscrollLength,
this.trackVisibility, this.trackVisibility,
this.trackRadius,
this.trackColor, this.trackColor,
this.trackBorderColor, this.trackBorderColor,
this.fadeDuration = _kScrollbarFadeDuration, this.fadeDuration = _kScrollbarFadeDuration,
...@@ -1224,6 +1245,12 @@ class RawScrollbar extends StatefulWidget { ...@@ -1224,6 +1245,12 @@ class RawScrollbar extends StatefulWidget {
/// [MaterialState]s by using [ScrollbarThemeData.trackVisibility]. /// [MaterialState]s by using [ScrollbarThemeData.trackVisibility].
final bool? trackVisibility; final bool? trackVisibility;
/// The [Radius] of the scrollbar track's rounded rectangle corners.
///
/// Scrollbar's track will be rectangular if [trackRadius] is null, which is
/// the default behavior.
final Radius? trackRadius;
/// The color of the scrollbar track. /// The color of the scrollbar track.
/// ///
/// The scrollbar track will only be visible when [trackVisibility] and /// The scrollbar track will only be visible when [trackVisibility] and
...@@ -1380,6 +1407,7 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv ...@@ -1380,6 +1407,7 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
fadeoutOpacityAnimation: _fadeoutOpacityAnimation, fadeoutOpacityAnimation: _fadeoutOpacityAnimation,
thickness: widget.thickness ?? _kScrollbarThickness, thickness: widget.thickness ?? _kScrollbarThickness,
radius: widget.radius, radius: widget.radius,
trackRadius: widget.trackRadius,
scrollbarOrientation: widget.scrollbarOrientation, scrollbarOrientation: widget.scrollbarOrientation,
mainAxisMargin: widget.mainAxisMargin, mainAxisMargin: widget.mainAxisMargin,
shape: widget.shape, shape: widget.shape,
...@@ -1513,6 +1541,7 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv ...@@ -1513,6 +1541,7 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
void updateScrollbarPainter() { void updateScrollbarPainter() {
scrollbarPainter scrollbarPainter
..color = widget.thumbColor ?? const Color(0x66BCBCBC) ..color = widget.thumbColor ?? const Color(0x66BCBCBC)
..trackRadius = widget.trackRadius
..trackColor = _showTrack ? const Color(0x08000000) : const Color(0x00000000) ..trackColor = _showTrack ? const Color(0x08000000) : const Color(0x00000000)
..trackBorderColor = _showTrack ? const Color(0x1a000000) : const Color(0x00000000) ..trackBorderColor = _showTrack ? const Color(0x1a000000) : const Color(0x00000000)
..textDirection = Directionality.of(context) ..textDirection = Directionality.of(context)
......
...@@ -25,6 +25,7 @@ ScrollbarPainter _buildPainter({ ...@@ -25,6 +25,7 @@ ScrollbarPainter _buildPainter({
double mainAxisMargin = 0.0, double mainAxisMargin = 0.0,
double crossAxisMargin = 0.0, double crossAxisMargin = 0.0,
Radius? radius, Radius? radius,
Radius? trackRadius,
double minLength = _kMinThumbExtent, double minLength = _kMinThumbExtent,
double? minOverscrollLength, double? minOverscrollLength,
ScrollbarOrientation? scrollbarOrientation, ScrollbarOrientation? scrollbarOrientation,
...@@ -38,6 +39,7 @@ ScrollbarPainter _buildPainter({ ...@@ -38,6 +39,7 @@ ScrollbarPainter _buildPainter({
mainAxisMargin: mainAxisMargin, mainAxisMargin: mainAxisMargin,
crossAxisMargin: crossAxisMargin, crossAxisMargin: crossAxisMargin,
radius: radius, radius: radius,
trackRadius: trackRadius,
minLength: minLength, minLength: minLength,
minOverscrollLength: minOverscrollLength ?? minLength, minOverscrollLength: minOverscrollLength ?? minLength,
fadeoutOpacityAnimation: kAlwaysCompleteAnimation, fadeoutOpacityAnimation: kAlwaysCompleteAnimation,
...@@ -47,12 +49,18 @@ ScrollbarPainter _buildPainter({ ...@@ -47,12 +49,18 @@ ScrollbarPainter _buildPainter({
class _DrawRectOnceCanvas extends Fake implements Canvas { class _DrawRectOnceCanvas extends Fake implements Canvas {
List<Rect> rects = <Rect>[]; List<Rect> rects = <Rect>[];
List<RRect> rrects = <RRect>[];
@override @override
void drawRect(Rect rect, Paint paint) { void drawRect(Rect rect, Paint paint) {
rects.add(rect); rects.add(rect);
} }
@override
void drawRRect(ui.RRect rrect, ui.Paint paint) {
rrects.add(rrect);
}
@override @override
void drawLine(Offset p1, Offset p2, Paint paint) {} void drawLine(Offset p1, Offset p2, Paint paint) {}
} }
...@@ -62,9 +70,11 @@ void main() { ...@@ -62,9 +70,11 @@ void main() {
ScrollbarPainter painter; ScrollbarPainter painter;
Rect captureRect() => testCanvas.rects.removeLast(); Rect captureRect() => testCanvas.rects.removeLast();
RRect captureRRect() => testCanvas.rrects.removeLast();
tearDown(() { tearDown(() {
testCanvas.rects.clear(); testCanvas.rects.clear();
testCanvas.rrects.clear();
}); });
final ScrollMetrics defaultMetrics = FixedScrollMetrics( final ScrollMetrics defaultMetrics = FixedScrollMetrics(
...@@ -629,6 +639,37 @@ void main() { ...@@ -629,6 +639,37 @@ void main() {
}, },
); );
test('trackRadius and radius is respected', () {
const double minLen = 3.5;
const Size size = Size(600, 10);
final ScrollMetrics metrics = defaultMetrics.copyWith(
maxScrollExtent: 100000,
viewportDimension: size.height,
);
painter = _buildPainter(
trackRadius: const Radius.circular(2.0),
radius: const Radius.circular(3.0),
minLength: minLen,
minOverscrollLength: minLen,
scrollMetrics: metrics,
);
painter.paint(testCanvas, size);
final RRect thumbRRect = captureRRect(); // thumb
expect(thumbRRect.blRadius, const Radius.circular(3.0));
expect(thumbRRect.brRadius, const Radius.circular(3.0));
expect(thumbRRect.tlRadius, const Radius.circular(3.0));
expect(thumbRRect.trRadius, const Radius.circular(3.0));
final RRect trackRRect = captureRRect(); // track
expect(trackRRect.blRadius, const Radius.circular(2.0));
expect(trackRRect.brRadius, const Radius.circular(2.0));
expect(trackRRect.tlRadius, const Radius.circular(2.0));
expect(trackRRect.trRadius, const Radius.circular(2.0));
});
testWidgets('ScrollbarPainter asserts if no TextDirection has been provided', (WidgetTester tester) async { testWidgets('ScrollbarPainter asserts if no TextDirection has been provided', (WidgetTester tester) async {
final ScrollbarPainter painter = ScrollbarPainter( final ScrollbarPainter painter = ScrollbarPainter(
color: _kScrollbarColor, color: _kScrollbarColor,
...@@ -2206,6 +2247,7 @@ void main() { ...@@ -2206,6 +2247,7 @@ void main() {
double mainAxisMargin = 0.0, double mainAxisMargin = 0.0,
double crossAxisMargin = 0.0, double crossAxisMargin = 0.0,
Radius? radius, Radius? radius,
Radius? trackRadius,
OutlinedBorder? shape, OutlinedBorder? shape,
double minLength = _kMinThumbExtent, double minLength = _kMinThumbExtent,
double? minOverscrollLength, double? minOverscrollLength,
...@@ -2222,6 +2264,7 @@ void main() { ...@@ -2222,6 +2264,7 @@ void main() {
mainAxisMargin: mainAxisMargin, mainAxisMargin: mainAxisMargin,
crossAxisMargin: crossAxisMargin, crossAxisMargin: crossAxisMargin,
radius: radius, radius: radius,
trackRadius: trackRadius,
shape: shape, shape: shape,
minLength: minLength, minLength: minLength,
minOverscrollLength: minOverscrollLength, minOverscrollLength: minOverscrollLength,
...@@ -2240,6 +2283,7 @@ void main() { ...@@ -2240,6 +2283,7 @@ void main() {
expect(painter.shouldRepaint(createPainter(mainAxisMargin: 1.0)), true); expect(painter.shouldRepaint(createPainter(mainAxisMargin: 1.0)), true);
expect(painter.shouldRepaint(createPainter(crossAxisMargin: 1.0)), true); expect(painter.shouldRepaint(createPainter(crossAxisMargin: 1.0)), true);
expect(painter.shouldRepaint(createPainter(radius: const Radius.circular(1.0))), true); expect(painter.shouldRepaint(createPainter(radius: const Radius.circular(1.0))), true);
expect(painter.shouldRepaint(createPainter(trackRadius: const Radius.circular(1.0))), true);
expect(painter.shouldRepaint(createPainter(shape: const CircleBorder(side: BorderSide(width: 2.0)))), true); expect(painter.shouldRepaint(createPainter(shape: const CircleBorder(side: BorderSide(width: 2.0)))), true);
expect(painter.shouldRepaint(createPainter(minLength: _kMinThumbExtent + 1.0)), true); expect(painter.shouldRepaint(createPainter(minLength: _kMinThumbExtent + 1.0)), true);
expect(painter.shouldRepaint(createPainter(minOverscrollLength: 1.0)), true); expect(painter.shouldRepaint(createPainter(minOverscrollLength: 1.0)), true);
...@@ -2289,6 +2333,45 @@ void main() { ...@@ -2289,6 +2333,45 @@ void main() {
); );
}); });
testWidgets('trackRadius and radius properties of RawScrollbar can draw RoundedRectangularRect', (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,
trackRadius: const Radius.circular(1.0),
radius: const Radius.circular(2.0),
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
..rrect(
rrect: RRect.fromLTRBR(794.0, 0.0, 800.0, 600.0, const Radius.circular(1.0)),
color: const Color(0x08000000),
)
..rrect(
rrect: RRect.fromLTRBR(794.0, 0.0, 800.0, 90.0, const Radius.circular(2.0)),
color: const Color(0x66bcbcbc),
)
);
});
testWidgets('Scrollbar asserts that a visible track has a visible thumb', (WidgetTester tester) async { testWidgets('Scrollbar asserts that a visible track has a visible thumb', (WidgetTester tester) async {
final ScrollController scrollController = ScrollController(); final ScrollController scrollController = ScrollController();
Widget _buildApp() { Widget _buildApp() {
......
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