Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
bb278d1d
Unverified
Commit
bb278d1d
authored
Aug 26, 2021
by
Mohammad Ghalayini
Committed by
GitHub
Aug 26, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[new feature] Add support for a RawScrollbar.shape (#85652)
parent
f5dd3d9d
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
209 additions
and
3 deletions
+209
-3
scrollbar.dart
packages/flutter/lib/src/widgets/scrollbar.dart
+74
-3
scrollbar_test.dart
packages/flutter/test/widgets/scrollbar_test.dart
+135
-0
No files found.
packages/flutter/lib/src/widgets/scrollbar.dart
View file @
bb278d1d
...
...
@@ -85,10 +85,12 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter {
double
mainAxisMargin
=
0.0
,
double
crossAxisMargin
=
0.0
,
Radius
?
radius
,
OutlinedBorder
?
shape
,
double
minLength
=
_kMinThumbExtent
,
double
?
minOverscrollLength
,
ScrollbarOrientation
?
scrollbarOrientation
,
})
:
assert
(
color
!=
null
),
assert
(
radius
==
null
||
shape
==
null
),
assert
(
thickness
!=
null
),
assert
(
fadeoutOpacityAnimation
!=
null
),
assert
(
mainAxisMargin
!=
null
),
...
...
@@ -103,6 +105,7 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter {
_textDirection
=
textDirection
,
_thickness
=
thickness
,
_radius
=
radius
,
_shape
=
shape
,
_padding
=
padding
,
_mainAxisMargin
=
mainAxisMargin
,
_crossAxisMargin
=
crossAxisMargin
,
...
...
@@ -217,6 +220,7 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter {
Radius
?
get
radius
=>
_radius
;
Radius
?
_radius
;
set
radius
(
Radius
?
value
)
{
assert
(
shape
==
null
||
value
==
null
);
if
(
radius
==
value
)
return
;
...
...
@@ -224,6 +228,26 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter {
notifyListeners
();
}
/// The [OutlinedBorder] of the scrollbar's thumb.
///
/// Only one of [radius] and [shape] may be specified. For a rounded rectangle,
/// it's simplest to just specify [radius]. By default, the scrollbar thumb's
/// shape is a simple rectangle.
///
/// If [shape] is specified, the thumb will take the shape of the passed
/// [OutlinedBorder] and fill itself with [color] (or grey if it
/// is unspecified).
///
OutlinedBorder
?
get
shape
=>
_shape
;
OutlinedBorder
?
_shape
;
set
shape
(
OutlinedBorder
?
value
){
assert
(
radius
==
null
||
value
==
null
);
if
(
shape
==
value
)
return
;
_shape
=
value
;
notifyListeners
();
}
/// The amount of space by which to inset the scrollbar's start and end, as
/// well as its side to the nearest edge, in logical pixels.
///
...
...
@@ -447,10 +471,20 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter {
);
_thumbRect
=
Offset
(
x
,
y
)
&
thumbSize
;
if
(
radius
==
null
)
canvas
.
drawRect
(
_thumbRect
!,
_paintThumb
);
else
if
(
radius
!=
null
)
{
canvas
.
drawRRect
(
RRect
.
fromRectAndRadius
(
_thumbRect
!,
radius
!),
_paintThumb
);
return
;
}
if
(
shape
==
null
)
{
canvas
.
drawRect
(
_thumbRect
!,
_paintThumb
);
return
;
}
final
Path
outerPath
=
shape
!.
getOuterPath
(
_thumbRect
!);
canvas
.
drawPath
(
outerPath
,
_paintThumb
);
shape
!.
paint
(
canvas
,
_thumbRect
!);
}
double
_thumbExtent
()
{
...
...
@@ -776,6 +810,7 @@ class RawScrollbar extends StatefulWidget {
required
this
.
child
,
this
.
controller
,
this
.
isAlwaysShown
,
this
.
shape
,
this
.
radius
,
this
.
thickness
,
this
.
thumbColor
,
...
...
@@ -795,6 +830,7 @@ class RawScrollbar extends StatefulWidget {
assert
(
minOverscrollLength
==
null
||
minOverscrollLength
<=
minThumbLength
),
assert
(
minOverscrollLength
==
null
||
minOverscrollLength
>=
0
),
assert
(
fadeDuration
!=
null
),
assert
(
radius
==
null
||
shape
==
null
),
assert
(
timeToFade
!=
null
),
assert
(
pressDuration
!=
null
),
assert
(
mainAxisMargin
!=
null
),
...
...
@@ -944,6 +980,39 @@ class RawScrollbar extends StatefulWidget {
/// {@endtemplate}
final
bool
?
isAlwaysShown
;
/// The [OutlinedBorder] of the scrollbar's thumb.
///
/// Only one of [radius] and [shape] may be specified. For a rounded rectangle,
/// it's simplest to just specify [radius]. By default, the scrollbar thumb's
/// shape is a simple rectangle.
///
/// If [shape] is specified, the thumb will take the shape of the passed
/// [OutlinedBorder] and fill itself with [thumbColor] (or grey if it
/// is unspecified).
///
/// Here is an example of using a [StadiumBorder] for drawing the [shape] of the
/// thumb in a [RawScrollbar]:
///
/// {@tool dartpad --template=stateless_widget_material}
/// ```dart
/// Widget build(BuildContext context) {
/// return Scaffold(
/// body: RawScrollbar(
/// child: ListView(
/// children: List<Text>.generate(100, (int index) => Text((index * index).toString())),
/// physics: const BouncingScrollPhysics(),
/// ),
/// shape: const StadiumBorder(side: BorderSide(color: Colors.brown, width: 3.0)),
/// thickness: 15.0,
/// thumbColor: Colors.blue,
/// isAlwaysShown: true,
/// ),
/// );
/// }
/// ```
/// {@end-tool}
final
OutlinedBorder
?
shape
;
/// The [Radius] of the scrollbar thumb's rounded rectangle corners.
///
/// Scrollbar will be rectangular if [radius] is null, which is the default
...
...
@@ -1124,6 +1193,7 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
fadeoutOpacityAnimation:
_fadeoutOpacityAnimation
,
scrollbarOrientation:
widget
.
scrollbarOrientation
,
mainAxisMargin:
widget
.
mainAxisMargin
,
shape:
widget
.
shape
,
crossAxisMargin:
widget
.
crossAxisMargin
);
}
...
...
@@ -1253,6 +1323,7 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
..
padding
=
MediaQuery
.
of
(
context
).
padding
..
scrollbarOrientation
=
widget
.
scrollbarOrientation
..
mainAxisMargin
=
widget
.
mainAxisMargin
..
shape
=
widget
.
shape
..
crossAxisMargin
=
widget
.
crossAxisMargin
..
minLength
=
widget
.
minThumbLength
..
minOverscrollLength
=
widget
.
minOverscrollLength
??
widget
.
minThumbLength
;
...
...
packages/flutter/test/widgets/scrollbar_test.dart
View file @
bb278d1d
...
...
@@ -1445,6 +1445,7 @@ void main() {
),
);
});
testWidgets
(
'ScrollbarPainter asserts if scrollbarOrientation is used with wrong axisDirection'
,
(
WidgetTester
tester
)
async
{
final
ScrollbarPainter
painter
=
ScrollbarPainter
(
color:
_kScrollbarColor
,
...
...
@@ -1492,6 +1493,44 @@ void main() {
..
rect
(
rect:
const
Rect
.
fromLTRB
(
794.0
,
10.0
,
800.0
,
358.0
))
);
});
testWidgets
(
'shape property of RawScrollbar can draw a BeveledRectangleBorder'
,
(
WidgetTester
tester
)
async
{
final
ScrollController
scrollController
=
ScrollController
();
await
tester
.
pumpWidget
(
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
MediaQuery
(
data:
const
MediaQueryData
(),
child:
RawScrollbar
(
shape:
const
BeveledRectangleBorder
(
borderRadius:
BorderRadius
.
all
(
Radius
.
circular
(
8.0
))
),
controller:
scrollController
,
isAlwaysShown:
true
,
child:
SingleChildScrollView
(
controller:
scrollController
,
child:
const
SizedBox
(
height:
1000.0
),
),
),
)));
await
tester
.
pumpAndSettle
();
expect
(
find
.
byType
(
RawScrollbar
),
paints
..
rect
(
rect:
const
Rect
.
fromLTRB
(
794.0
,
0.0
,
800.0
,
600.0
))
..
path
(
includes:
const
<
Offset
>[
Offset
(
797.0
,
0.0
),
Offset
(
797.0
,
18.0
),
],
excludes:
const
<
Offset
>[
Offset
(
796.0
,
0.0
),
Offset
(
798.0
,
0.0
),
],
),
);
});
testWidgets
(
'minThumbLength property of RawScrollbar is respected'
,
(
WidgetTester
tester
)
async
{
final
ScrollController
scrollController
=
ScrollController
();
await
tester
.
pumpWidget
(
...
...
@@ -1518,6 +1557,42 @@ void main() {
..
rect
(
rect:
const
Rect
.
fromLTRB
(
794.0
,
0.0
,
800.0
,
21.0
)));
// thumb
});
testWidgets
(
'shape property of RawScrollbar can draw a CircleBorder'
,
(
WidgetTester
tester
)
async
{
final
ScrollController
scrollController
=
ScrollController
();
await
tester
.
pumpWidget
(
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
MediaQuery
(
data:
const
MediaQueryData
(),
child:
RawScrollbar
(
shape:
const
CircleBorder
(
side:
BorderSide
(
width:
2.0
)),
thickness:
36.0
,
controller:
scrollController
,
isAlwaysShown:
true
,
child:
SingleChildScrollView
(
controller:
scrollController
,
child:
const
SizedBox
(
height:
1000.0
,
width:
1000
),
),
),
)));
await
tester
.
pumpAndSettle
();
expect
(
find
.
byType
(
RawScrollbar
),
paints
..
path
(
includes:
const
<
Offset
>[
Offset
(
782.0
,
180.0
),
Offset
(
782.0
,
180.0
-
18.0
),
Offset
(
782.0
+
18.0
,
180
),
Offset
(
782.0
,
180.0
+
18.0
),
Offset
(
782.0
-
18.0
,
180
),
],
)
..
circle
(
x:
782.0
,
y:
180.0
,
radius:
17.0
,
strokeWidth:
2.0
)
);
});
testWidgets
(
'crossAxisMargin property of RawScrollbar is respected'
,
(
WidgetTester
tester
)
async
{
final
ScrollController
scrollController
=
ScrollController
();
await
tester
.
pumpWidget
(
...
...
@@ -1543,6 +1618,40 @@ void main() {
..
rect
(
rect:
const
Rect
.
fromLTRB
(
764.0
,
0.0
,
770.0
,
360.0
)));
});
testWidgets
(
'shape property of RawScrollbar can draw a RoundedRectangleBorder'
,
(
WidgetTester
tester
)
async
{
final
ScrollController
scrollController
=
ScrollController
();
await
tester
.
pumpWidget
(
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
MediaQuery
(
data:
const
MediaQueryData
(),
child:
RawScrollbar
(
thickness:
20
,
shape:
const
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
only
(
topLeft:
Radius
.
circular
(
8
))),
controller:
scrollController
,
isAlwaysShown:
true
,
child:
SingleChildScrollView
(
controller:
scrollController
,
child:
const
SizedBox
(
height:
1000.0
,
width:
1000.0
),
),
),
)));
await
tester
.
pumpAndSettle
();
expect
(
find
.
byType
(
RawScrollbar
),
paints
..
rect
(
rect:
const
Rect
.
fromLTRB
(
780.0
,
0.0
,
800.0
,
600.0
))
..
path
(
includes:
const
<
Offset
>[
Offset
(
800.0
,
0.0
),
],
excludes:
const
<
Offset
>[
Offset
(
780.0
,
0.0
),
],
),
);
});
testWidgets
(
'minOverscrollLength property of RawScrollbar is respected'
,
(
WidgetTester
tester
)
async
{
final
ScrollController
scrollController
=
ScrollController
();
await
tester
.
pumpWidget
(
...
...
@@ -1575,6 +1684,32 @@ void main() {
..
rect
(
rect:
const
Rect
.
fromLTRB
(
794.0
,
0.0
,
800.0
,
8.0
)));
});
testWidgets
(
'not passing any shape or radius to RawScrollbar will draw the usual rectangular thumb'
,
(
WidgetTester
tester
)
async
{
final
ScrollController
scrollController
=
ScrollController
();
await
tester
.
pumpWidget
(
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
MediaQuery
(
data:
const
MediaQueryData
(),
child:
RawScrollbar
(
controller:
scrollController
,
isAlwaysShown:
true
,
child:
SingleChildScrollView
(
controller:
scrollController
,
child:
const
SizedBox
(
height:
1000.0
),
),
),
)));
await
tester
.
pumpAndSettle
();
expect
(
find
.
byType
(
RawScrollbar
),
paints
..
rect
(
rect:
const
Rect
.
fromLTRB
(
794.0
,
0.0
,
800.0
,
600.0
))
..
rect
(
rect:
const
Rect
.
fromLTRB
(
794.0
,
0.0
,
800.0
,
360.0
))
);
});
testWidgets
(
'The bar can show or hide when the viewport size change'
,
(
WidgetTester
tester
)
async
{
final
ScrollController
scrollController
=
ScrollController
();
Widget
buildFrame
(
double
height
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment