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
6154b3b4
Unverified
Commit
6154b3b4
authored
Oct 24, 2022
by
xubaolin
Committed by
GitHub
Oct 24, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improve Scrollbar drag behavior (#112434)
parent
14a73606
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
97 additions
and
14 deletions
+97
-14
scrollbar.dart
packages/flutter/lib/src/widgets/scrollbar.dart
+26
-14
scrollbar_test.dart
packages/flutter/test/widgets/scrollbar_test.dart
+71
-0
No files found.
packages/flutter/lib/src/widgets/scrollbar.dart
View file @
6154b3b4
...
@@ -686,6 +686,17 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter {
...
@@ -686,6 +686,17 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter {
return
scrollableExtent
*
thumbOffsetLocal
/
thumbMovableExtent
;
return
scrollableExtent
*
thumbOffsetLocal
/
thumbMovableExtent
;
}
}
/// The thumb's corresponding scroll offset in the track.
double
getThumbScrollOffset
()
{
final
double
scrollableExtent
=
_lastMetrics
!.
maxScrollExtent
-
_lastMetrics
!.
minScrollExtent
;
final
double
fractionPast
=
(
scrollableExtent
>
0
)
?
clampDouble
(
_lastMetrics
!.
pixels
/
scrollableExtent
,
0.0
,
1.0
)
:
0
;
return
fractionPast
*
(
_traversableTrackExtent
-
_thumbExtent
);
}
// Converts between a scroll position and the corresponding position in the
// Converts between a scroll position and the corresponding position in the
// thumb track.
// thumb track.
double
_getScrollToTrack
(
ScrollMetrics
metrics
,
double
thumbExtent
)
{
double
_getScrollToTrack
(
ScrollMetrics
metrics
,
double
thumbExtent
)
{
...
@@ -1446,7 +1457,8 @@ class RawScrollbar extends StatefulWidget {
...
@@ -1446,7 +1457,8 @@ class RawScrollbar extends StatefulWidget {
/// Provides defaults gestures for dragging the scrollbar thumb and tapping on the
/// Provides defaults gestures for dragging the scrollbar thumb and tapping on the
/// scrollbar track.
/// scrollbar track.
class
RawScrollbarState
<
T
extends
RawScrollbar
>
extends
State
<
T
>
with
TickerProviderStateMixin
<
T
>
{
class
RawScrollbarState
<
T
extends
RawScrollbar
>
extends
State
<
T
>
with
TickerProviderStateMixin
<
T
>
{
Offset
?
_dragScrollbarAxisOffset
;
Offset
?
_startDragScrollbarAxisOffset
;
double
?
_startDragThumbOffset
;
ScrollController
?
_currentController
;
ScrollController
?
_currentController
;
Timer
?
_fadeoutTimer
;
Timer
?
_fadeoutTimer
;
late
AnimationController
_fadeoutAnimationController
;
late
AnimationController
_fadeoutAnimationController
;
...
@@ -1454,7 +1466,6 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
...
@@ -1454,7 +1466,6 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
final
GlobalKey
_scrollbarPainterKey
=
GlobalKey
();
final
GlobalKey
_scrollbarPainterKey
=
GlobalKey
();
bool
_hoverIsActive
=
false
;
bool
_hoverIsActive
=
false
;
/// Used to paint the scrollbar.
/// Used to paint the scrollbar.
///
///
/// Can be customized by subclasses to change scrollbar behavior by overriding
/// Can be customized by subclasses to change scrollbar behavior by overriding
...
@@ -1688,30 +1699,30 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
...
@@ -1688,30 +1699,30 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
void
_updateScrollPosition
(
Offset
updatedOffset
)
{
void
_updateScrollPosition
(
Offset
updatedOffset
)
{
assert
(
_currentController
!=
null
);
assert
(
_currentController
!=
null
);
assert
(
_dragScrollbarAxisOffset
!=
null
);
assert
(
_startDragScrollbarAxisOffset
!=
null
);
assert
(
_startDragThumbOffset
!=
null
);
final
ScrollPosition
position
=
_currentController
!.
position
;
final
ScrollPosition
position
=
_currentController
!.
position
;
late
double
primaryDelta
;
late
double
primaryDelta
;
switch
(
position
.
axisDirection
)
{
switch
(
position
.
axisDirection
)
{
case
AxisDirection
.
up
:
case
AxisDirection
.
up
:
primaryDelta
=
_
d
ragScrollbarAxisOffset
!.
dy
-
updatedOffset
.
dy
;
primaryDelta
=
_
startD
ragScrollbarAxisOffset
!.
dy
-
updatedOffset
.
dy
;
break
;
break
;
case
AxisDirection
.
right
:
case
AxisDirection
.
right
:
primaryDelta
=
updatedOffset
.
dx
-
_
d
ragScrollbarAxisOffset
!.
dx
;
primaryDelta
=
updatedOffset
.
dx
-
_
startD
ragScrollbarAxisOffset
!.
dx
;
break
;
break
;
case
AxisDirection
.
down
:
case
AxisDirection
.
down
:
primaryDelta
=
updatedOffset
.
dy
-
_
d
ragScrollbarAxisOffset
!.
dy
;
primaryDelta
=
updatedOffset
.
dy
-
_
startD
ragScrollbarAxisOffset
!.
dy
;
break
;
break
;
case
AxisDirection
.
left
:
case
AxisDirection
.
left
:
primaryDelta
=
_
d
ragScrollbarAxisOffset
!.
dx
-
updatedOffset
.
dx
;
primaryDelta
=
_
startD
ragScrollbarAxisOffset
!.
dx
-
updatedOffset
.
dx
;
break
;
break
;
}
}
// Convert primaryDelta, the amount that the scrollbar moved since the last
// Convert primaryDelta, the amount that the scrollbar moved since the last
// time
_updateScrollPosition was call
ed, into the coordinate space of the scroll
// time
when drag start
ed, into the coordinate space of the scroll
// position, and jump to that position.
// position, and jump to that position.
final
double
scrollOffsetLocal
=
scrollbarPainter
.
getTrackToScroll
(
primaryDelta
);
final
double
scrollOffsetGlobal
=
scrollbarPainter
.
getTrackToScroll
(
primaryDelta
+
_startDragThumbOffset
!);
final
double
scrollOffsetGlobal
=
scrollOffsetLocal
+
position
.
pixels
;
if
(
scrollOffsetGlobal
!=
position
.
pixels
)
{
if
(
scrollOffsetGlobal
!=
position
.
pixels
)
{
// Ensure we don't drag into overscroll if the physics do not allow it.
// Ensure we don't drag into overscroll if the physics do not allow it.
final
double
physicsAdjustment
=
position
.
physics
.
applyBoundaryConditions
(
position
,
scrollOffsetGlobal
);
final
double
physicsAdjustment
=
position
.
physics
.
applyBoundaryConditions
(
position
,
scrollOffsetGlobal
);
...
@@ -1784,7 +1795,8 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
...
@@ -1784,7 +1795,8 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
}
}
_fadeoutTimer
?.
cancel
();
_fadeoutTimer
?.
cancel
();
_fadeoutAnimationController
.
forward
();
_fadeoutAnimationController
.
forward
();
_dragScrollbarAxisOffset
=
localPosition
;
_startDragScrollbarAxisOffset
=
localPosition
;
_startDragThumbOffset
=
scrollbarPainter
.
getThumbScrollOffset
();
}
}
/// Handler called when a currently active long press gesture moves.
/// Handler called when a currently active long press gesture moves.
...
@@ -1803,7 +1815,6 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
...
@@ -1803,7 +1815,6 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
return
;
return
;
}
}
_updateScrollPosition
(
localPosition
);
_updateScrollPosition
(
localPosition
);
_dragScrollbarAxisOffset
=
localPosition
;
}
}
/// Handler called when a long press has ended.
/// Handler called when a long press has ended.
...
@@ -1816,7 +1827,8 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
...
@@ -1816,7 +1827,8 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
return
;
return
;
}
}
_maybeStartFadeoutTimer
();
_maybeStartFadeoutTimer
();
_dragScrollbarAxisOffset
=
null
;
_startDragScrollbarAxisOffset
=
null
;
_startDragThumbOffset
=
null
;
_currentController
=
null
;
_currentController
=
null
;
}
}
...
@@ -1958,7 +1970,7 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
...
@@ -1958,7 +1970,7 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
scrollbarPainter
.
update
(
metrics
,
metrics
.
axisDirection
);
scrollbarPainter
.
update
(
metrics
,
metrics
.
axisDirection
);
}
}
}
else
if
(
notification
is
ScrollEndNotification
)
{
}
else
if
(
notification
is
ScrollEndNotification
)
{
if
(
_
d
ragScrollbarAxisOffset
==
null
)
{
if
(
_
startD
ragScrollbarAxisOffset
==
null
)
{
_maybeStartFadeoutTimer
();
_maybeStartFadeoutTimer
();
}
}
}
}
...
...
packages/flutter/test/widgets/scrollbar_test.dart
View file @
6154b3b4
...
@@ -2717,4 +2717,75 @@ void main() {
...
@@ -2717,4 +2717,75 @@ void main() {
expect
(
scrollController
.
offset
,
0.0
);
expect
(
scrollController
.
offset
,
0.0
);
});
});
testWidgets
(
'The thumb should follow the pointer when the scroll metrics changed during dragging'
,
(
WidgetTester
tester
)
async
{
// Regressing test for https://github.com/flutter/flutter/issues/112072
final
ScrollController
scrollController
=
ScrollController
();
await
tester
.
pumpWidget
(
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
MediaQuery
(
data:
const
MediaQueryData
(),
child:
PrimaryScrollController
(
controller:
scrollController
,
child:
RawScrollbar
(
isAlwaysShown:
true
,
controller:
scrollController
,
child:
CustomScrollView
(
controller:
scrollController
,
// cacheExtent: double.maxFinite,
slivers:
<
Widget
>[
SliverList
(
delegate:
SliverChildBuilderDelegate
(
(
BuildContext
context
,
int
index
)
{
final
double
height
;
if
(
index
<
10
)
{
height
=
100
;
}
else
{
height
=
500
;
}
return
SizedBox
(
height:
height
,
child:
Text
(
'
$index
'
),
);
},
childCount:
100
,
),
),
],
),
),
),
),
),
);
await
tester
.
pumpAndSettle
();
expect
(
scrollController
.
offset
,
0.0
);
// Drag the thumb down to scroll down.
const
double
scrollAmount
=
100
;
final
TestGesture
dragScrollbarGesture
=
await
tester
.
startGesture
(
const
Offset
(
797.0
,
5.0
));
await
tester
.
pumpAndSettle
();
await
dragScrollbarGesture
.
moveBy
(
const
Offset
(
0.0
,
scrollAmount
));
await
tester
.
pumpAndSettle
();
await
dragScrollbarGesture
.
moveBy
(
const
Offset
(
0.0
,
scrollAmount
));
await
tester
.
pumpAndSettle
();
await
dragScrollbarGesture
.
up
();
await
tester
.
pumpAndSettle
();
// The view has scrolled more than it would have by a swipe gesture of the
// same distance.
expect
(
scrollController
.
offset
,
greaterThan
((
100.0
*
10
+
500.0
*
90
)
/
3
));
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
,
200.0
,
800.0
,
218.0
),
color:
const
Color
(
0x66BCBCBC
),
),
);
});
}
}
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