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
26ccbd9f
Unverified
Commit
26ccbd9f
authored
Dec 17, 2020
by
Kate Lovett
Committed by
GitHub
Dec 17, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update Scrollbar behavior for mobile devices (#72531)
parent
ff8203dc
Changes
4
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
346 additions
and
87 deletions
+346
-87
scrollbar.dart
packages/flutter/lib/src/material/scrollbar.dart
+49
-13
scrollbar.dart
packages/flutter/lib/src/widgets/scrollbar.dart
+30
-9
scrollbar_paint_test.dart
packages/flutter/test/material/scrollbar_paint_test.dart
+54
-11
scrollbar_test.dart
packages/flutter/test/material/scrollbar_test.dart
+213
-54
No files found.
packages/flutter/lib/src/material/scrollbar.dart
View file @
26ccbd9f
...
...
@@ -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 d
esign scrollbar.
/// A
Material D
esign scrollbar.
///
/// To add a scrollbar t
humb to a [ScrollView], simply
wrap the scroll view
/// To add a scrollbar t
o 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
();
...
...
packages/flutter/lib/src/widgets/scrollbar.dart
View file @
26ccbd9f
...
...
@@ -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
,
),
),
);
...
...
packages/flutter/test/material/scrollbar_paint_test.dart
View file @
26ccbd9f
...
...
@@ -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
{
...
...
packages/flutter/test/material/scrollbar_test.dart
View file @
26ccbd9f
This diff is collapsed.
Click to expand it.
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