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
001a14b3
Commit
001a14b3
authored
Mar 06, 2016
by
Adam Barth
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2432 from abarth/scroll_events
Flinging continuously should have one scroll start/end pair
parents
66859545
688da091
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
67 additions
and
25 deletions
+67
-25
scrollable.dart
packages/flutter/lib/src/widgets/scrollable.dart
+26
-25
scroll_events_test.dart
packages/flutter/test/widget/scroll_events_test.dart
+41
-0
No files found.
packages/flutter/lib/src/widgets/scrollable.dart
View file @
001a14b3
...
@@ -327,15 +327,9 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
...
@@ -327,15 +327,9 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
});
});
PageStorage
.
of
(
context
)?.
writeState
(
context
,
_scrollOffset
);
PageStorage
.
of
(
context
)?.
writeState
(
context
,
_scrollOffset
);
new
ScrollNotification
(
this
,
_scrollOffset
).
dispatch
(
context
);
new
ScrollNotification
(
this
,
_scrollOffset
).
dispatch
(
context
);
final
needsScrollStart
=
!
_isBetweenOnScrollStartAndOnScrollEnd
;
_startScroll
();
if
(
needsScrollStart
)
{
dispatchOnScrollStart
();
assert
(
_isBetweenOnScrollStartAndOnScrollEnd
);
}
dispatchOnScroll
();
dispatchOnScroll
();
assert
(
_isBetweenOnScrollStartAndOnScrollEnd
);
_endScroll
();
if
(
needsScrollStart
)
dispatchOnScrollEnd
();
}
}
/// Scroll this widget by the given scroll delta.
/// Scroll this widget by the given scroll delta.
...
@@ -372,8 +366,8 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
...
@@ -372,8 +366,8 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
Future
_animateTo
(
double
newScrollOffset
,
Duration
duration
,
Curve
curve
)
{
Future
_animateTo
(
double
newScrollOffset
,
Duration
duration
,
Curve
curve
)
{
_controller
.
stop
();
_controller
.
stop
();
_controller
.
value
=
scrollOffset
;
_controller
.
value
=
scrollOffset
;
_
dispatchOnScrollStartIfNeeded
();
_
startScroll
();
return
_controller
.
animateTo
(
newScrollOffset
,
duration:
duration
,
curve:
curve
).
then
(
_
dispatchOnScrollEndIfNeeded
);
return
_controller
.
animateTo
(
newScrollOffset
,
duration:
duration
,
curve:
curve
).
then
(
_
endScroll
);
}
}
/// Fling the scroll offset with the given velocity.
/// Fling the scroll offset with the given velocity.
...
@@ -401,8 +395,8 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
...
@@ -401,8 +395,8 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
Simulation
simulation
=
_createSnapSimulation
(
scrollVelocity
)
??
_createFlingSimulation
(
scrollVelocity
);
Simulation
simulation
=
_createSnapSimulation
(
scrollVelocity
)
??
_createFlingSimulation
(
scrollVelocity
);
if
(
simulation
==
null
)
if
(
simulation
==
null
)
return
new
Future
.
value
();
return
new
Future
.
value
();
_
dispatchOnScrollStartIfNeeded
();
_
startScroll
();
return
_controller
.
animateWith
(
simulation
).
then
(
_
dispatchOnScrollEndIfNeeded
);
return
_controller
.
animateWith
(
simulation
).
then
(
_
endScroll
);
}
}
/// Whether this scrollable should attempt to snap scroll offsets.
/// Whether this scrollable should attempt to snap scroll offsets.
...
@@ -453,14 +447,21 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
...
@@ -453,14 +447,21 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
return
simulation
;
return
simulation
;
}
}
// When we start an scroll animation, we stop any previous scroll animation.
bool
_isBetweenOnScrollStartAndOnScrollEnd
=
false
;
// However, the code that would deliver the onScrollEnd callback is watching
// for animations to end using a Future that resolves at the end of the
// microtask. That causes animations to "overlap" between the time we start a
// new animation and the end of the microtask. By the time the microtask is
// over and we check whether to deliver an onScrollEnd callback, we will have
// started the new animation (having skipped the onScrollStart) and therefore
// we won't deliver the onScrollEnd until the second animation is finished.
int
_numberOfInProgressScrolls
=
0
;
/// Calls the onScroll callback.
/// Calls the onScroll callback.
///
///
/// Subclasses can override this function to hook the scroll callback.
/// Subclasses can override this function to hook the scroll callback.
void
dispatchOnScroll
()
{
void
dispatchOnScroll
()
{
assert
(
_
isBetweenOnScrollStartAndOnScrollEnd
);
assert
(
_
numberOfInProgressScrolls
>
0
);
if
(
config
.
onScroll
!=
null
)
if
(
config
.
onScroll
!=
null
)
config
.
onScroll
(
_scrollOffset
);
config
.
onScroll
(
_scrollOffset
);
}
}
...
@@ -470,11 +471,12 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
...
@@ -470,11 +471,12 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
}
}
void
_handleDragStart
(
_
)
{
void
_handleDragStart
(
_
)
{
_
dispatchOnScrollStartIfNeeded
();
_
startScroll
();
}
}
void
_dispatchOnScrollStartIfNeeded
()
{
void
_startScroll
()
{
if
(!
_isBetweenOnScrollStartAndOnScrollEnd
)
_numberOfInProgressScrolls
+=
1
;
if
(
_numberOfInProgressScrolls
==
1
)
dispatchOnScrollStart
();
dispatchOnScrollStart
();
}
}
...
@@ -482,8 +484,7 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
...
@@ -482,8 +484,7 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
///
///
/// Subclasses can override this function to hook the scroll start callback.
/// Subclasses can override this function to hook the scroll start callback.
void
dispatchOnScrollStart
()
{
void
dispatchOnScrollStart
()
{
assert
(!
_isBetweenOnScrollStartAndOnScrollEnd
);
assert
(
_numberOfInProgressScrolls
==
1
);
_isBetweenOnScrollStartAndOnScrollEnd
=
true
;
if
(
config
.
onScrollStart
!=
null
)
if
(
config
.
onScrollStart
!=
null
)
config
.
onScrollStart
(
_scrollOffset
);
config
.
onScrollStart
(
_scrollOffset
);
}
}
...
@@ -495,11 +496,12 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
...
@@ -495,11 +496,12 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
Future
_handleDragEnd
(
Velocity
velocity
)
{
Future
_handleDragEnd
(
Velocity
velocity
)
{
double
scrollVelocity
=
pixelDeltaToScrollOffset
(
velocity
.
pixelsPerSecond
)
/
Duration
.
MILLISECONDS_PER_SECOND
;
double
scrollVelocity
=
pixelDeltaToScrollOffset
(
velocity
.
pixelsPerSecond
)
/
Duration
.
MILLISECONDS_PER_SECOND
;
// The gesture velocity properties are pixels/second, config min,max limits are pixels/ms
// The gesture velocity properties are pixels/second, config min,max limits are pixels/ms
return
fling
(
scrollVelocity
.
clamp
(-
kMaxFlingVelocity
,
kMaxFlingVelocity
)).
then
(
_
dispatchOnScrollEndIfNeeded
);
return
fling
(
scrollVelocity
.
clamp
(-
kMaxFlingVelocity
,
kMaxFlingVelocity
)).
then
(
_
endScroll
);
}
}
void
_dispatchOnScrollEndIfNeeded
(
_
)
{
void
_endScroll
([
_
])
{
if
(
_isBetweenOnScrollStartAndOnScrollEnd
)
_numberOfInProgressScrolls
-=
1
;
if
(
_numberOfInProgressScrolls
==
0
)
dispatchOnScrollEnd
();
dispatchOnScrollEnd
();
}
}
...
@@ -507,8 +509,7 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
...
@@ -507,8 +509,7 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
///
///
/// Subclasses can override this function to hook the scroll end callback.
/// Subclasses can override this function to hook the scroll end callback.
void
dispatchOnScrollEnd
()
{
void
dispatchOnScrollEnd
()
{
assert
(
_isBetweenOnScrollStartAndOnScrollEnd
);
assert
(
_numberOfInProgressScrolls
==
0
);
_isBetweenOnScrollStartAndOnScrollEnd
=
false
;
if
(
config
.
onScrollEnd
!=
null
)
if
(
config
.
onScrollEnd
!=
null
)
config
.
onScrollEnd
(
_scrollOffset
);
config
.
onScrollEnd
(
_scrollOffset
);
}
}
...
...
packages/flutter/test/widget/scroll_events_test.dart
View file @
001a14b3
...
@@ -95,4 +95,45 @@ void main() {
...
@@ -95,4 +95,45 @@ void main() {
expect
(
log
,
equals
([
'scrollstart'
,
'scroll'
,
'scroll'
,
'scrollend'
]));
expect
(
log
,
equals
([
'scrollstart'
,
'scroll'
,
'scroll'
,
'scrollend'
]));
});
});
});
});
test
(
'Scroll during animation'
,
()
{
testWidgets
((
WidgetTester
tester
)
{
GlobalKey
<
ScrollableState
>
scrollKey
=
new
GlobalKey
<
ScrollableState
>();
List
<
String
>
log
=
<
String
>[];
tester
.
pumpWidget
(
_buildScroller
(
key:
scrollKey
,
log:
log
));
expect
(
log
,
equals
([]));
scrollKey
.
currentState
.
scrollTo
(
100.0
,
duration:
const
Duration
(
seconds:
1
));
expect
(
log
,
equals
([
'scrollstart'
]));
tester
.
pump
(
const
Duration
(
milliseconds:
100
));
expect
(
log
,
equals
([
'scrollstart'
]));
tester
.
pump
(
const
Duration
(
milliseconds:
100
));
expect
(
log
,
equals
([
'scrollstart'
,
'scroll'
]));
scrollKey
.
currentState
.
scrollTo
(
100.0
,
duration:
const
Duration
(
seconds:
1
));
expect
(
log
,
equals
([
'scrollstart'
,
'scroll'
]));
tester
.
pump
(
const
Duration
(
milliseconds:
100
));
expect
(
log
,
equals
([
'scrollstart'
,
'scroll'
]));
tester
.
pump
(
const
Duration
(
milliseconds:
1500
));
expect
(
log
,
equals
([
'scrollstart'
,
'scroll'
,
'scroll'
,
'scrollend'
]));
});
});
test
(
'fling, fling generates one start/end pair'
,
()
{
testWidgets
((
WidgetTester
tester
)
{
GlobalKey
<
ScrollableState
>
scrollKey
=
new
GlobalKey
<
ScrollableState
>();
List
<
String
>
log
=
<
String
>[];
tester
.
pumpWidget
(
_buildScroller
(
key:
scrollKey
,
log:
log
));
expect
(
log
,
equals
([]));
tester
.
flingFrom
(
new
Point
(
100.0
,
100.0
),
new
Offset
(-
50.0
,
-
50.0
),
500.0
);
tester
.
pump
(
new
Duration
(
seconds:
1
));
log
.
removeWhere
((
String
value
)
=>
value
==
'scroll'
);
expect
(
log
,
equals
([
'scrollstart'
]));
tester
.
flingFrom
(
new
Point
(
100.0
,
100.0
),
new
Offset
(-
50.0
,
-
50.0
),
500.0
);
tester
.
pump
(
new
Duration
(
seconds:
1
));
tester
.
pump
(
new
Duration
(
seconds:
1
));
log
.
removeWhere
((
String
value
)
=>
value
==
'scroll'
);
expect
(
log
,
equals
([
'scrollstart'
,
'scrollend'
]));
});
});
}
}
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