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
fc83640c
Commit
fc83640c
authored
Sep 21, 2016
by
Hans Muller
Committed by
GitHub
Sep 21, 2016
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ClampOverscrolls clamps Scrollable, not its Viewport (#5909)
parent
035afc2c
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
180 additions
and
78 deletions
+180
-78
smoke_test.dart
examples/flutter_gallery/test/smoke_test.dart
+1
-1
overscroll_indicator.dart
packages/flutter/lib/src/material/overscroll_indicator.dart
+2
-2
clamp_overscrolls.dart
packages/flutter/lib/src/widgets/clamp_overscrolls.dart
+4
-26
lazy_block.dart
packages/flutter/lib/src/widgets/lazy_block.dart
+3
-8
scrollable.dart
packages/flutter/lib/src/widgets/scrollable.dart
+53
-17
scrollable_grid.dart
packages/flutter/lib/src/widgets/scrollable_grid.dart
+3
-8
scrollable_list.dart
packages/flutter/lib/src/widgets/scrollable_list.dart
+6
-15
date_picker_test.dart
packages/flutter/test/material/date_picker_test.dart
+1
-1
clamp_overscrolls_test.dart
packages/flutter/test/widget/clamp_overscrolls_test.dart
+76
-0
scrollable_list_hit_testing_test.dart
...flutter/test/widget/scrollable_list_hit_testing_test.dart
+31
-0
No files found.
examples/flutter_gallery/test/smoke_test.dart
View file @
fc83640c
...
@@ -82,7 +82,7 @@ void main() {
...
@@ -82,7 +82,7 @@ void main() {
await
tester
.
scroll
(
findGalleryItemByRouteName
(
tester
,
routeName
),
new
Offset
(
0.0
,
scrollDeltas
[
i
]));
await
tester
.
scroll
(
findGalleryItemByRouteName
(
tester
,
routeName
),
new
Offset
(
0.0
,
scrollDeltas
[
i
]));
await
tester
.
pump
();
// start the scroll
await
tester
.
pump
();
// start the scroll
await
tester
.
pump
(
const
Duration
(
milliseconds:
500
));
// wait for overscroll to timeout, if necessary
await
tester
.
pump
(
const
Duration
(
milliseconds:
500
));
// wait for overscroll to timeout, if necessary
await
tester
.
pump
(
const
Duration
(
milliseconds:
2000
));
// wait for overscroll to fade away, if necessary
await
tester
.
pump
(
const
Duration
(
seconds:
3
));
// wait for overscroll to fade away, if necessary
tester
.
binding
.
debugAssertNoTransientCallbacks
(
'A transient callback was still active after leaving route
$routeName
'
);
tester
.
binding
.
debugAssertNoTransientCallbacks
(
'A transient callback was still active after leaving route
$routeName
'
);
}
}
...
...
packages/flutter/lib/src/material/overscroll_indicator.dart
View file @
fc83640c
...
@@ -151,7 +151,7 @@ class _OverscrollIndicatorState extends State<OverscrollIndicator> {
...
@@ -151,7 +151,7 @@ class _OverscrollIndicatorState extends State<OverscrollIndicator> {
return
;
return
;
final
ExtentScrollBehavior
scrollBehavior
=
scrollable
.
scrollBehavior
;
final
ExtentScrollBehavior
scrollBehavior
=
scrollable
.
scrollBehavior
;
_scrollDirection
=
scrollable
.
config
.
scrollDirection
;
_scrollDirection
=
scrollable
.
config
.
scrollDirection
;
_scrollOffset
=
scrollable
.
s
crollOffset
;
_scrollOffset
=
scrollable
.
virtualS
crollOffset
;
_minScrollOffset
=
scrollBehavior
.
minScrollOffset
;
_minScrollOffset
=
scrollBehavior
.
minScrollOffset
;
_maxScrollOffset
=
scrollBehavior
.
maxScrollOffset
;
_maxScrollOffset
=
scrollBehavior
.
maxScrollOffset
;
}
}
...
@@ -166,7 +166,7 @@ class _OverscrollIndicatorState extends State<OverscrollIndicator> {
...
@@ -166,7 +166,7 @@ class _OverscrollIndicatorState extends State<OverscrollIndicator> {
if
(!
_scrollUnderway
)
// The hide timer has run.
if
(!
_scrollUnderway
)
// The hide timer has run.
return
;
return
;
final
double
value
=
scrollable
.
s
crollOffset
;
final
double
value
=
scrollable
.
virtualS
crollOffset
;
if
(
_isOverscroll
(
value
))
{
if
(
_isOverscroll
(
value
))
{
_refreshHideTimer
();
_refreshHideTimer
();
// Hide the indicator as soon as user starts scrolling in the reverse direction of overscroll.
// Hide the indicator as soon as user starts scrolling in the reverse direction of overscroll.
...
...
packages/flutter/lib/src/widgets/clamp_overscrolls.dart
View file @
fc83640c
...
@@ -83,9 +83,10 @@ class ClampOverscrolls extends InheritedWidget {
...
@@ -83,9 +83,10 @@ class ClampOverscrolls extends InheritedWidget {
/// constraints are applied.
/// constraints are applied.
final
ScrollableEdge
edge
;
final
ScrollableEdge
edge
;
/// Return the [scrollable]'s scrollOffset clamped according to [edge].
/// Return the [newScrollOffset] clamped according to [edge] and [scrollable]'s
double
clampScrollOffset
(
ScrollableState
scrollable
)
{
/// scroll behavior. The value of [newScrollOffset] defaults to `scrollable.scrollOffset`.
final
double
scrollOffset
=
scrollable
.
scrollOffset
;
double
clampScrollOffset
(
ScrollableState
scrollable
,
[
double
newScrollOffset
])
{
final
double
scrollOffset
=
newScrollOffset
??
scrollable
.
scrollOffset
;
final
double
minScrollOffset
=
scrollable
.
scrollBehavior
.
minScrollOffset
;
final
double
minScrollOffset
=
scrollable
.
scrollBehavior
.
minScrollOffset
;
final
double
maxScrollOffset
=
scrollable
.
scrollBehavior
.
maxScrollOffset
;
final
double
maxScrollOffset
=
scrollable
.
scrollBehavior
.
maxScrollOffset
;
switch
(
edge
)
{
switch
(
edge
)
{
...
@@ -106,29 +107,6 @@ class ClampOverscrolls extends InheritedWidget {
...
@@ -106,29 +107,6 @@ class ClampOverscrolls extends InheritedWidget {
return
context
.
inheritFromWidgetOfExactType
(
ClampOverscrolls
);
return
context
.
inheritFromWidgetOfExactType
(
ClampOverscrolls
);
}
}
/// Clamps the new viewport's scroll offset according to the value of
/// `ClampOverscrolls.of(context).edge`.
///
/// The clamped overscroll edge is reset to [ScrollableEdge.none] for the viewport's
/// descendants.
///
/// This utility function is typically used by [Scrollable.builder] callbacks.
static
Widget
buildViewport
(
BuildContext
context
,
ScrollableState
state
,
ViewportBuilder
builder
)
{
// TODO(ianh): minScrollOffset and maxScrollOffset are typically determined
// by the container and content size. But we don't know those until we
// layout the viewport, which happens after build phase. We need to rethink
// this.
final
ClampOverscrolls
clampOverscrolls
=
ClampOverscrolls
.
of
(
context
);
if
(
clampOverscrolls
==
null
)
return
builder
(
context
,
state
,
state
.
scrollOffset
);
final
double
clampedScrollOffset
=
clampOverscrolls
.
clampScrollOffset
(
state
);
Widget
viewport
=
builder
(
context
,
state
,
clampedScrollOffset
);
if
(
clampOverscrolls
.
edge
!=
ScrollableEdge
.
none
)
viewport
=
new
ClampOverscrolls
(
edge:
ScrollableEdge
.
none
,
child:
viewport
);
return
viewport
;
}
@override
@override
bool
updateShouldNotify
(
ClampOverscrolls
old
)
=>
edge
!=
old
.
edge
;
bool
updateShouldNotify
(
ClampOverscrolls
old
)
=>
edge
!=
old
.
edge
;
...
...
packages/flutter/lib/src/widgets/lazy_block.dart
View file @
fc83640c
...
@@ -8,7 +8,6 @@ import 'package:flutter/rendering.dart';
...
@@ -8,7 +8,6 @@ import 'package:flutter/rendering.dart';
import
'package:meta/meta.dart'
;
import
'package:meta/meta.dart'
;
import
'basic.dart'
;
import
'basic.dart'
;
import
'clamp_overscrolls.dart'
;
import
'framework.dart'
;
import
'framework.dart'
;
import
'scroll_configuration.dart'
;
import
'scroll_configuration.dart'
;
import
'scrollable.dart'
;
import
'scrollable.dart'
;
...
@@ -259,9 +258,9 @@ class LazyBlock extends StatelessWidget {
...
@@ -259,9 +258,9 @@ class LazyBlock extends StatelessWidget {
/// See [LazyBlockDelegate] for details.
/// See [LazyBlockDelegate] for details.
final
LazyBlockDelegate
delegate
;
final
LazyBlockDelegate
delegate
;
Widget
_buildViewport
(
BuildContext
context
,
ScrollableState
state
,
double
scrollOffset
)
{
Widget
_buildViewport
(
BuildContext
context
,
ScrollableState
state
)
{
return
new
LazyBlockViewport
(
return
new
LazyBlockViewport
(
startOffset:
scrollOffset
,
startOffset:
s
tate
.
s
crollOffset
,
mainAxis:
scrollDirection
,
mainAxis:
scrollDirection
,
padding:
padding
,
padding:
padding
,
onExtentsChanged:
(
int
firstIndex
,
int
lastIndex
,
double
firstStartOffset
,
double
lastEndOffset
,
double
minScrollOffset
,
double
containerExtent
)
{
onExtentsChanged:
(
int
firstIndex
,
int
lastIndex
,
double
firstStartOffset
,
double
lastEndOffset
,
double
minScrollOffset
,
double
containerExtent
)
{
...
@@ -278,10 +277,6 @@ class LazyBlock extends StatelessWidget {
...
@@ -278,10 +277,6 @@ class LazyBlock extends StatelessWidget {
);
);
}
}
Widget
_buildContent
(
BuildContext
context
,
ScrollableState
state
)
{
return
ClampOverscrolls
.
buildViewport
(
context
,
state
,
_buildViewport
);
}
@override
@override
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
final
Widget
result
=
new
Scrollable
(
final
Widget
result
=
new
Scrollable
(
...
@@ -292,7 +287,7 @@ class LazyBlock extends StatelessWidget {
...
@@ -292,7 +287,7 @@ class LazyBlock extends StatelessWidget {
onScroll:
onScroll
,
onScroll:
onScroll
,
onScrollEnd:
onScrollEnd
,
onScrollEnd:
onScrollEnd
,
snapOffsetCallback:
snapOffsetCallback
,
snapOffsetCallback:
snapOffsetCallback
,
builder:
_build
Conten
t
builder:
_build
Viewpor
t
);
);
return
ScrollConfiguration
.
wrap
(
context
,
result
);
return
ScrollConfiguration
.
wrap
(
context
,
result
);
}
}
...
...
packages/flutter/lib/src/widgets/scrollable.dart
View file @
fc83640c
...
@@ -270,12 +270,14 @@ class ScrollableState<T extends Scrollable> extends State<T> {
...
@@ -270,12 +270,14 @@ class ScrollableState<T extends Scrollable> extends State<T> {
..
addListener
(
_handleAnimationChanged
)
..
addListener
(
_handleAnimationChanged
)
..
addStatusListener
(
_handleAnimationStatusChanged
);
..
addStatusListener
(
_handleAnimationStatusChanged
);
_scrollOffset
=
PageStorage
.
of
(
context
)?.
readState
(
context
)
??
config
.
initialScrollOffset
??
0.0
;
_scrollOffset
=
PageStorage
.
of
(
context
)?.
readState
(
context
)
??
config
.
initialScrollOffset
??
0.0
;
_virtualScrollOffset
=
_scrollOffset
;
}
}
Simulation
_simulation
;
// if we're flinging, then this is the animation with which we're doing it
Simulation
_simulation
;
// if we're flinging, then this is the animation with which we're doing it
AnimationController
_controller
;
AnimationController
_controller
;
double
_contentExtent
;
double
_contentExtent
;
double
_containerExtent
;
double
_containerExtent
;
bool
_scrollUnderway
=
false
;
@override
@override
void
dispose
()
{
void
dispose
()
{
...
@@ -300,9 +302,31 @@ class ScrollableState<T extends Scrollable> extends State<T> {
...
@@ -300,9 +302,31 @@ class ScrollableState<T extends Scrollable> extends State<T> {
/// The scroll offset is applied to the child widget along the scroll
/// The scroll offset is applied to the child widget along the scroll
/// direction before painting. A positive scroll offset indicates that
/// direction before painting. A positive scroll offset indicates that
/// more content in the preferred reading direction is visible.
/// more content in the preferred reading direction is visible.
///
/// The scroll offset's value may be above or below the limits defined
/// by the [scrollBehavior]. This is called "overscrolling" and it can be
/// prevented with the [ClampOverscrolls] widget.
///
/// See also:
///
/// * [virtualScrollOffset]
/// * [initialScrollOffset]
/// * [onScrollStart]
/// * [onScroll]
/// * [onScrollEnd]
/// * [ScrollNotification]
double
get
scrollOffset
=>
_scrollOffset
;
double
get
scrollOffset
=>
_scrollOffset
;
double
_scrollOffset
;
double
_scrollOffset
;
/// The current scroll offset, irrespective of the constraints defined
/// by any [ClampOverscrolls] widget ancestors.
///
/// See also:
///
/// * [scrollOffset]
double
get
virtualScrollOffset
=>
_virtualScrollOffset
;
double
_virtualScrollOffset
;
/// Convert a position or velocity measured in terms of pixels to a scrollOffset.
/// Convert a position or velocity measured in terms of pixels to a scrollOffset.
/// Scrollable gesture handlers convert their incoming values with this method.
/// Scrollable gesture handlers convert their incoming values with this method.
/// Subclasses that define scrollOffset in units other than pixels must
/// Subclasses that define scrollOffset in units other than pixels must
...
@@ -387,7 +411,7 @@ class ScrollableState<T extends Scrollable> extends State<T> {
...
@@ -387,7 +411,7 @@ class ScrollableState<T extends Scrollable> extends State<T> {
bool
_scrollOffsetIsInBounds
(
double
scrollOffset
)
{
bool
_scrollOffsetIsInBounds
(
double
scrollOffset
)
{
if
(
scrollBehavior
is
!
ExtentScrollBehavior
)
if
(
scrollBehavior
is
!
ExtentScrollBehavior
)
return
false
;
return
false
;
ExtentScrollBehavior
behavior
=
scrollBehavior
;
final
ExtentScrollBehavior
behavior
=
scrollBehavior
;
return
scrollOffset
>=
behavior
.
minScrollOffset
&&
scrollOffset
<
behavior
.
maxScrollOffset
;
return
scrollOffset
>=
behavior
.
minScrollOffset
&&
scrollOffset
<
behavior
.
maxScrollOffset
;
}
}
...
@@ -398,16 +422,23 @@ class ScrollableState<T extends Scrollable> extends State<T> {
...
@@ -398,16 +422,23 @@ class ScrollableState<T extends Scrollable> extends State<T> {
void
_handleAnimationStatusChanged
(
AnimationStatus
status
)
{
void
_handleAnimationStatusChanged
(
AnimationStatus
status
)
{
// this is not called when stop() is called on the controller
// this is not called when stop() is called on the controller
setState
(()
{
setState
(()
{
if
(!
_controller
.
isAnimating
)
if
(!
_controller
.
isAnimating
)
{
_simulation
=
null
;
_simulation
=
null
;
_scrollUnderway
=
false
;
}
});
});
}
}
void
_setScrollOffset
(
double
newScrollOffset
,
{
DragUpdateDetails
details
})
{
void
_setScrollOffset
(
double
newScrollOffset
,
{
DragUpdateDetails
details
})
{
if
(
_scrollOffset
==
newScrollOffset
)
if
(
_scrollOffset
==
newScrollOffset
)
return
;
return
;
final
ClampOverscrolls
clampOverscrolls
=
ClampOverscrolls
.
of
(
context
);
final
double
clampedScrollOffset
=
clampOverscrolls
?.
clampScrollOffset
(
this
,
newScrollOffset
)
??
newScrollOffset
;
setState
(()
{
setState
(()
{
_scrollOffset
=
newScrollOffset
;
_virtualScrollOffset
=
newScrollOffset
;
_scrollUnderway
=
_scrollOffset
!=
clampedScrollOffset
;
_scrollOffset
=
clampedScrollOffset
;
});
});
PageStorage
.
of
(
context
)?.
writeState
(
context
,
_scrollOffset
);
PageStorage
.
of
(
context
)?.
writeState
(
context
,
_scrollOffset
);
_startScroll
();
_startScroll
();
...
@@ -429,7 +460,7 @@ class ScrollableState<T extends Scrollable> extends State<T> {
...
@@ -429,7 +460,7 @@ class ScrollableState<T extends Scrollable> extends State<T> {
Curve
curve:
Curves
.
ease
,
Curve
curve:
Curves
.
ease
,
DragUpdateDetails
details
DragUpdateDetails
details
})
{
})
{
double
newScrollOffset
=
scrollBehavior
.
applyCurve
(
_s
crollOffset
,
scrollDelta
);
double
newScrollOffset
=
scrollBehavior
.
applyCurve
(
virtualS
crollOffset
,
scrollDelta
);
return
scrollTo
(
newScrollOffset
,
duration:
duration
,
curve:
curve
,
details:
details
);
return
scrollTo
(
newScrollOffset
,
duration:
duration
,
curve:
curve
,
details:
details
);
}
}
...
@@ -461,7 +492,7 @@ class ScrollableState<T extends Scrollable> extends State<T> {
...
@@ -461,7 +492,7 @@ class ScrollableState<T extends Scrollable> extends State<T> {
Future
<
Null
>
_animateTo
(
double
newScrollOffset
,
Duration
duration
,
Curve
curve
)
{
Future
<
Null
>
_animateTo
(
double
newScrollOffset
,
Duration
duration
,
Curve
curve
)
{
_stop
();
_stop
();
_controller
.
value
=
s
crollOffset
;
_controller
.
value
=
virtualS
crollOffset
;
_startScroll
();
_startScroll
();
return
_controller
.
animateTo
(
newScrollOffset
,
duration:
duration
,
curve:
curve
).
then
((
Null
_
)
{
return
_controller
.
animateTo
(
newScrollOffset
,
duration:
duration
,
curve:
curve
).
then
((
Null
_
)
{
_endScroll
();
_endScroll
();
...
@@ -526,7 +557,8 @@ class ScrollableState<T extends Scrollable> extends State<T> {
...
@@ -526,7 +557,8 @@ class ScrollableState<T extends Scrollable> extends State<T> {
// If a scroll animation isn't underway already and we're overscrolled or we're
// If a scroll animation isn't underway already and we're overscrolled or we're
// going to have to snap the scroll offset, then animate the scroll offset to its
// going to have to snap the scroll offset, then animate the scroll offset to its
// final value.
// final value.
if
(!
_controller
.
isAnimating
&&
(
shouldSnapScrollOffset
||
!
_scrollOffsetIsInBounds
(
scrollOffset
)))
if
(!
_controller
.
isAnimating
&&
(
shouldSnapScrollOffset
||
!
_scrollOffsetIsInBounds
(
scrollOffset
)))
return
settleScrollOffset
();
return
settleScrollOffset
();
return
new
Future
<
Null
>.
value
();
return
new
Future
<
Null
>.
value
();
...
@@ -573,14 +605,14 @@ class ScrollableState<T extends Scrollable> extends State<T> {
...
@@ -573,14 +605,14 @@ class ScrollableState<T extends Scrollable> extends State<T> {
if
(
endScrollOffset
.
isNaN
)
if
(
endScrollOffset
.
isNaN
)
return
null
;
return
null
;
final
double
snappedScrollOffset
=
snapScrollOffset
(
endScrollOffset
);
// Calls the config.snapOffsetCallback callback
final
double
snappedScrollOffset
=
snapScrollOffset
(
endScrollOffset
);
if
(!
_scrollOffsetIsInBounds
(
snappedScrollOffset
))
if
(!
_scrollOffsetIsInBounds
(
snappedScrollOffset
))
return
null
;
return
null
;
final
double
snapVelocity
=
scrollVelocity
.
abs
()
*
(
snappedScrollOffset
-
scrollOffset
).
sign
;
final
double
snapVelocity
=
scrollVelocity
.
abs
()
*
(
snappedScrollOffset
-
scrollOffset
).
sign
;
final
double
endVelocity
=
pixelOffsetToScrollOffset
(
kPixelScrollTolerance
.
velocity
).
abs
()
*
(
scrollVelocity
<
0.0
?
-
1.0
:
1.0
);
final
double
endVelocity
=
pixelOffsetToScrollOffset
(
kPixelScrollTolerance
.
velocity
).
abs
()
*
(
scrollVelocity
<
0.0
?
-
1.0
:
1.0
);
Simulation
toSnapSimulation
=
scrollBehavior
.
createSnapScrollSimulation
(
Simulation
toSnapSimulation
=
scrollBehavior
.
createSnapScrollSimulation
(
s
crollOffset
,
snappedScrollOffset
,
snapVelocity
,
endVelocity
virtualS
crollOffset
,
snappedScrollOffset
,
snapVelocity
,
endVelocity
);
);
if
(
toSnapSimulation
==
null
)
if
(
toSnapSimulation
==
null
)
return
null
;
return
null
;
...
@@ -591,7 +623,7 @@ class ScrollableState<T extends Scrollable> extends State<T> {
...
@@ -591,7 +623,7 @@ class ScrollableState<T extends Scrollable> extends State<T> {
}
}
Simulation
_createFlingSimulation
(
double
scrollVelocity
)
{
Simulation
_createFlingSimulation
(
double
scrollVelocity
)
{
final
Simulation
simulation
=
scrollBehavior
.
createScrollSimulation
(
s
crollOffset
,
scrollVelocity
);
final
Simulation
simulation
=
scrollBehavior
.
createScrollSimulation
(
virtualS
crollOffset
,
scrollVelocity
);
if
(
simulation
!=
null
)
{
if
(
simulation
!=
null
)
{
final
double
endVelocity
=
pixelOffsetToScrollOffset
(
kPixelScrollTolerance
.
velocity
).
abs
();
final
double
endVelocity
=
pixelOffsetToScrollOffset
(
kPixelScrollTolerance
.
velocity
).
abs
();
final
double
endDistance
=
pixelOffsetToScrollOffset
(
kPixelScrollTolerance
.
distance
).
abs
();
final
double
endDistance
=
pixelOffsetToScrollOffset
(
kPixelScrollTolerance
.
distance
).
abs
();
...
@@ -672,6 +704,14 @@ class ScrollableState<T extends Scrollable> extends State<T> {
...
@@ -672,6 +704,14 @@ class ScrollableState<T extends Scrollable> extends State<T> {
_numberOfInProgressScrolls
-=
1
;
_numberOfInProgressScrolls
-=
1
;
if
(
_numberOfInProgressScrolls
==
0
)
{
if
(
_numberOfInProgressScrolls
==
0
)
{
_simulation
=
null
;
_simulation
=
null
;
if
(
_scrollUnderway
&&
mounted
)
{
// If the scroll hasn't already stopped because we've hit a clamped
// edge or the controller stopped animating, then rebuild the Scrollable
// with the IgnorePointer widget turned off.
setState
(()
{
_scrollUnderway
=
false
;
});
}
dispatchOnScrollEnd
();
dispatchOnScrollEnd
();
if
(
mounted
)
{
if
(
mounted
)
{
new
ScrollNotification
(
new
ScrollNotification
(
...
@@ -701,7 +741,7 @@ class ScrollableState<T extends Scrollable> extends State<T> {
...
@@ -701,7 +741,7 @@ class ScrollableState<T extends Scrollable> extends State<T> {
gestures:
buildGestureDetectors
(),
gestures:
buildGestureDetectors
(),
behavior:
HitTestBehavior
.
opaque
,
behavior:
HitTestBehavior
.
opaque
,
child:
new
IgnorePointer
(
child:
new
IgnorePointer
(
ignoring:
_
controller
.
isAnimating
,
ignoring:
_
scrollUnderway
,
child:
buildContent
(
context
)
child:
buildContent
(
context
)
)
)
);
);
...
@@ -940,9 +980,9 @@ class ScrollableViewport extends StatelessWidget {
...
@@ -940,9 +980,9 @@ class ScrollableViewport extends StatelessWidget {
/// The widget that will be scrolled. It will become the child of a Scrollable.
/// The widget that will be scrolled. It will become the child of a Scrollable.
final
Widget
child
;
final
Widget
child
;
Widget
_buildViewport
(
BuildContext
context
,
ScrollableState
state
,
double
scrollOffset
)
{
Widget
_buildViewport
(
BuildContext
context
,
ScrollableState
state
)
{
return
new
Viewport
(
return
new
Viewport
(
paintOffset:
state
.
scrollOffsetToPixelDelta
(
scrollOffset
),
paintOffset:
state
.
scrollOffsetToPixelDelta
(
s
tate
.
s
crollOffset
),
mainAxis:
scrollDirection
,
mainAxis:
scrollDirection
,
anchor:
scrollAnchor
,
anchor:
scrollAnchor
,
onPaintOffsetUpdateNeeded:
(
ViewportDimensions
dimensions
)
{
onPaintOffsetUpdateNeeded:
(
ViewportDimensions
dimensions
)
{
...
@@ -955,10 +995,6 @@ class ScrollableViewport extends StatelessWidget {
...
@@ -955,10 +995,6 @@ class ScrollableViewport extends StatelessWidget {
);
);
}
}
Widget
_buildContent
(
BuildContext
context
,
ScrollableState
state
)
{
return
ClampOverscrolls
.
buildViewport
(
context
,
state
,
_buildViewport
);
}
@override
@override
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
final
Widget
result
=
new
Scrollable
(
final
Widget
result
=
new
Scrollable
(
...
@@ -970,7 +1006,7 @@ class ScrollableViewport extends StatelessWidget {
...
@@ -970,7 +1006,7 @@ class ScrollableViewport extends StatelessWidget {
onScroll:
onScroll
,
onScroll:
onScroll
,
onScrollEnd:
onScrollEnd
,
onScrollEnd:
onScrollEnd
,
snapOffsetCallback:
snapOffsetCallback
,
snapOffsetCallback:
snapOffsetCallback
,
builder:
_build
Conten
t
builder:
_build
Viewpor
t
);
);
return
ScrollConfiguration
.
wrap
(
context
,
result
);
return
ScrollConfiguration
.
wrap
(
context
,
result
);
}
}
...
...
packages/flutter/lib/src/widgets/scrollable_grid.dart
View file @
fc83640c
...
@@ -8,7 +8,6 @@ import 'package:collection/collection.dart' show lowerBound;
...
@@ -8,7 +8,6 @@ import 'package:collection/collection.dart' show lowerBound;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:meta/meta.dart'
;
import
'package:meta/meta.dart'
;
import
'clamp_overscrolls.dart'
;
import
'framework.dart'
;
import
'framework.dart'
;
import
'scroll_configuration.dart'
;
import
'scroll_configuration.dart'
;
import
'scrollable.dart'
;
import
'scrollable.dart'
;
...
@@ -81,19 +80,15 @@ class ScrollableGrid extends StatelessWidget {
...
@@ -81,19 +80,15 @@ class ScrollableGrid extends StatelessWidget {
/// The children that will be placed in the grid.
/// The children that will be placed in the grid.
final
Iterable
<
Widget
>
children
;
final
Iterable
<
Widget
>
children
;
Widget
_buildViewport
(
BuildContext
context
,
ScrollableState
state
,
double
scrollOffset
)
{
Widget
_buildViewport
(
BuildContext
context
,
ScrollableState
state
)
{
return
new
GridViewport
(
return
new
GridViewport
(
scrollOffset:
scrollOffset
,
scrollOffset:
s
tate
.
s
crollOffset
,
delegate:
delegate
,
delegate:
delegate
,
onExtentsChanged:
state
.
handleExtentsChanged
,
onExtentsChanged:
state
.
handleExtentsChanged
,
children:
children
children:
children
);
);
}
}
Widget
_buildContent
(
BuildContext
context
,
ScrollableState
state
)
{
return
ClampOverscrolls
.
buildViewport
(
context
,
state
,
_buildViewport
);
}
@override
@override
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
final
Widget
result
=
new
Scrollable
(
final
Widget
result
=
new
Scrollable
(
...
@@ -107,7 +102,7 @@ class ScrollableGrid extends StatelessWidget {
...
@@ -107,7 +102,7 @@ class ScrollableGrid extends StatelessWidget {
onScroll:
onScroll
,
onScroll:
onScroll
,
onScrollEnd:
onScrollEnd
,
onScrollEnd:
onScrollEnd
,
snapOffsetCallback:
snapOffsetCallback
,
snapOffsetCallback:
snapOffsetCallback
,
builder:
_build
Content
builder:
_build
Viewport
,
);
);
return
ScrollConfiguration
.
wrap
(
context
,
result
);
return
ScrollConfiguration
.
wrap
(
context
,
result
);
}
}
...
...
packages/flutter/lib/src/widgets/scrollable_list.dart
View file @
fc83640c
...
@@ -7,7 +7,6 @@ import 'dart:math' as math;
...
@@ -7,7 +7,6 @@ import 'dart:math' as math;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:meta/meta.dart'
;
import
'package:meta/meta.dart'
;
import
'clamp_overscrolls.dart'
;
import
'framework.dart'
;
import
'framework.dart'
;
import
'scroll_configuration.dart'
;
import
'scroll_configuration.dart'
;
import
'scrollable.dart'
;
import
'scrollable.dart'
;
...
@@ -126,12 +125,12 @@ class ScrollableList extends StatelessWidget {
...
@@ -126,12 +125,12 @@ class ScrollableList extends StatelessWidget {
/// The children, some of which might be materialized.
/// The children, some of which might be materialized.
final
Iterable
<
Widget
>
children
;
final
Iterable
<
Widget
>
children
;
Widget
_buildViewport
(
BuildContext
context
,
ScrollableState
state
,
double
scrollOffset
)
{
Widget
_buildViewport
(
BuildContext
context
,
ScrollableState
state
)
{
return
new
ListViewport
(
return
new
ListViewport
(
onExtentsChanged:
(
double
contentExtent
,
double
containerExtent
)
{
onExtentsChanged:
(
double
contentExtent
,
double
containerExtent
)
{
state
.
handleExtentsChanged
(
itemsWrap
?
double
.
INFINITY
:
contentExtent
,
containerExtent
);
state
.
handleExtentsChanged
(
itemsWrap
?
double
.
INFINITY
:
contentExtent
,
containerExtent
);
},
},
scrollOffset:
scrollOffset
,
scrollOffset:
s
tate
.
s
crollOffset
,
mainAxis:
scrollDirection
,
mainAxis:
scrollDirection
,
anchor:
scrollAnchor
,
anchor:
scrollAnchor
,
itemExtent:
itemExtent
,
itemExtent:
itemExtent
,
...
@@ -141,10 +140,6 @@ class ScrollableList extends StatelessWidget {
...
@@ -141,10 +140,6 @@ class ScrollableList extends StatelessWidget {
);
);
}
}
Widget
_buildContent
(
BuildContext
context
,
ScrollableState
state
)
{
return
ClampOverscrolls
.
buildViewport
(
context
,
state
,
_buildViewport
);
}
@override
@override
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
final
Widget
result
=
new
Scrollable
(
final
Widget
result
=
new
Scrollable
(
...
@@ -156,7 +151,7 @@ class ScrollableList extends StatelessWidget {
...
@@ -156,7 +151,7 @@ class ScrollableList extends StatelessWidget {
onScroll:
onScroll
,
onScroll:
onScroll
,
onScrollEnd:
onScrollEnd
,
onScrollEnd:
onScrollEnd
,
snapOffsetCallback:
snapOffsetCallback
,
snapOffsetCallback:
snapOffsetCallback
,
builder:
_build
Conten
t
builder:
_build
Viewpor
t
);
);
return
ScrollConfiguration
.
wrap
(
context
,
result
);
return
ScrollConfiguration
.
wrap
(
context
,
result
);
}
}
...
@@ -529,10 +524,10 @@ class ScrollableLazyList extends StatelessWidget {
...
@@ -529,10 +524,10 @@ class ScrollableLazyList extends StatelessWidget {
/// The amount of space by which to inset the children inside the viewport.
/// The amount of space by which to inset the children inside the viewport.
final
EdgeInsets
padding
;
final
EdgeInsets
padding
;
Widget
_buildViewport
(
BuildContext
context
,
ScrollableState
state
,
double
scrollOffset
)
{
Widget
_buildViewport
(
BuildContext
context
,
ScrollableState
state
)
{
return
new
LazyListViewport
(
return
new
LazyListViewport
(
onExtentsChanged:
state
.
handleExtentsChanged
,
onExtentsChanged:
state
.
handleExtentsChanged
,
scrollOffset:
scrollOffset
,
scrollOffset:
s
tate
.
s
crollOffset
,
mainAxis:
scrollDirection
,
mainAxis:
scrollDirection
,
anchor:
scrollAnchor
,
anchor:
scrollAnchor
,
itemExtent:
itemExtent
,
itemExtent:
itemExtent
,
...
@@ -542,10 +537,6 @@ class ScrollableLazyList extends StatelessWidget {
...
@@ -542,10 +537,6 @@ class ScrollableLazyList extends StatelessWidget {
);
);
}
}
Widget
_buildContent
(
BuildContext
context
,
ScrollableState
state
)
{
return
ClampOverscrolls
.
buildViewport
(
context
,
state
,
_buildViewport
);
}
@override
@override
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
final
Widget
result
=
new
Scrollable
(
final
Widget
result
=
new
Scrollable
(
...
@@ -557,7 +548,7 @@ class ScrollableLazyList extends StatelessWidget {
...
@@ -557,7 +548,7 @@ class ScrollableLazyList extends StatelessWidget {
onScroll:
onScroll
,
onScroll:
onScroll
,
onScrollEnd:
onScrollEnd
,
onScrollEnd:
onScrollEnd
,
snapOffsetCallback:
snapOffsetCallback
,
snapOffsetCallback:
snapOffsetCallback
,
builder:
_build
Conten
t
builder:
_build
Viewpor
t
);
);
return
ScrollConfiguration
.
wrap
(
context
,
result
);
return
ScrollConfiguration
.
wrap
(
context
,
result
);
}
}
...
...
packages/flutter/test/material/date_picker_test.dart
View file @
fc83640c
...
@@ -6,7 +6,7 @@ import 'package:flutter/material.dart';
...
@@ -6,7 +6,7 @@ import 'package:flutter/material.dart';
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
void
main
(
)
{
void
main
(
)
{
testWidgets
(
'tap-select a
n
day'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'tap-select a day'
,
(
WidgetTester
tester
)
async
{
Key
_datePickerKey
=
new
UniqueKey
();
Key
_datePickerKey
=
new
UniqueKey
();
DateTime
_selectedDate
=
new
DateTime
(
2016
,
DateTime
.
JULY
,
26
);
DateTime
_selectedDate
=
new
DateTime
(
2016
,
DateTime
.
JULY
,
26
);
...
...
packages/flutter/test/widget/clamp_overscrolls_test.dart
View file @
fc83640c
...
@@ -45,6 +45,9 @@ void main() {
...
@@ -45,6 +45,9 @@ void main() {
return
new
Future
<
Point
>.
value
(
widgetOrigin
);
return
new
Future
<
Point
>.
value
(
widgetOrigin
);
}
}
// Each of the blocks below test overscrolling the top and bottom
// with a value for ClampOverscrolls.edge.
await
tester
.
pumpWidget
(
buildFrame
(
ScrollableEdge
.
none
));
await
tester
.
pumpWidget
(
buildFrame
(
ScrollableEdge
.
none
));
Point
origin
=
await
locationAfterScroll
(
'top'
,
const
Offset
(
0.0
,
400.0
));
Point
origin
=
await
locationAfterScroll
(
'top'
,
const
Offset
(
0.0
,
400.0
));
expect
(
origin
.
y
,
greaterThan
(
0.0
));
expect
(
origin
.
y
,
greaterThan
(
0.0
));
...
@@ -70,4 +73,77 @@ void main() {
...
@@ -70,4 +73,77 @@ void main() {
origin
=
await
locationAfterScroll
(
'bottom'
,
const
Offset
(
0.0
,
-
400.0
));
origin
=
await
locationAfterScroll
(
'bottom'
,
const
Offset
(
0.0
,
-
400.0
));
expect
(
origin
.
y
,
equals
(
500.0
));
expect
(
origin
.
y
,
equals
(
500.0
));
});
});
testWidgets
(
'ClampOverscrolls affects scrollOffset not virtualScrollOffset'
,
(
WidgetTester
tester
)
async
{
// ClampOverscrolls.edge == ScrollableEdge.none
await
tester
.
pumpWidget
(
buildFrame
(
ScrollableEdge
.
none
));
StatefulElement
statefulElement
=
tester
.
element
(
find
.
byType
(
Scrollable
));
ScrollableState
scrollable
=
statefulElement
.
state
;
await
tester
.
scrollAt
(
tester
.
getTopLeft
(
find
.
text
(
'top'
)),
const
Offset
(
0.0
,
400.0
));
await
tester
.
pump
();
expect
(
scrollable
.
scrollOffset
,
lessThan
(
0.0
));
expect
(
scrollable
.
virtualScrollOffset
,
equals
(
scrollable
.
scrollOffset
));
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
// Allow overscroll to settle
await
tester
.
scrollAt
(
tester
.
getTopLeft
(
find
.
text
(
'bottom'
)),
const
Offset
(
0.0
,
-
400.0
));
await
tester
.
pump
();
expect
(
scrollable
.
scrollOffset
,
greaterThan
(
0.0
));
expect
(
scrollable
.
virtualScrollOffset
,
equals
(
scrollable
.
scrollOffset
));
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
// Allow overscroll to settle
// ClampOverscrolls.edge == ScrollableEdge.both
await
tester
.
pumpWidget
(
buildFrame
(
ScrollableEdge
.
both
));
statefulElement
=
tester
.
element
(
find
.
byType
(
Scrollable
));
scrollable
=
statefulElement
.
state
;
await
tester
.
scrollAt
(
tester
.
getTopLeft
(
find
.
text
(
'top'
)),
const
Offset
(
0.0
,
400.0
));
await
tester
.
pump
();
expect
(
scrollable
.
scrollOffset
,
equals
(
0.0
));
expect
(
scrollable
.
virtualScrollOffset
,
lessThan
(
0.0
));
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
// Allow overscroll to settle
await
tester
.
scrollAt
(
tester
.
getTopLeft
(
find
.
text
(
'bottom'
)),
const
Offset
(
0.0
,
-
400.0
));
await
tester
.
pump
();
expect
(
scrollable
.
scrollOffset
,
equals
(
50.0
));
expect
(
scrollable
.
virtualScrollOffset
,
greaterThan
(
50.0
));
// ClampOverscrolls.edge == ScrollableEdge.leading
await
tester
.
pumpWidget
(
buildFrame
(
ScrollableEdge
.
leading
));
statefulElement
=
tester
.
element
(
find
.
byType
(
Scrollable
));
scrollable
=
statefulElement
.
state
;
await
tester
.
scrollAt
(
tester
.
getTopLeft
(
find
.
text
(
'top'
)),
const
Offset
(
0.0
,
400.0
));
await
tester
.
pump
();
expect
(
scrollable
.
scrollOffset
,
equals
(
0.0
));
expect
(
scrollable
.
virtualScrollOffset
,
lessThan
(
0.0
));
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
// Allow overscroll to settle
await
tester
.
scrollAt
(
tester
.
getTopLeft
(
find
.
text
(
'bottom'
)),
const
Offset
(
0.0
,
-
400.0
));
await
tester
.
pump
();
expect
(
scrollable
.
scrollOffset
,
greaterThan
(
0.0
));
expect
(
scrollable
.
virtualScrollOffset
,
equals
(
scrollable
.
scrollOffset
));
// ClampOverscrolls.edge == ScrollableEdge.trailing
await
tester
.
pumpWidget
(
buildFrame
(
ScrollableEdge
.
trailing
));
statefulElement
=
tester
.
element
(
find
.
byType
(
Scrollable
));
scrollable
=
statefulElement
.
state
;
await
tester
.
scrollAt
(
tester
.
getTopLeft
(
find
.
text
(
'top'
)),
const
Offset
(
0.0
,
400.0
));
await
tester
.
pump
();
expect
(
scrollable
.
scrollOffset
,
lessThan
(
0.0
));
expect
(
scrollable
.
virtualScrollOffset
,
equals
(
scrollable
.
scrollOffset
));
expect
(
scrollable
.
virtualScrollOffset
,
equals
(
scrollable
.
scrollOffset
));
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
// Allow overscroll to settle
await
tester
.
scrollAt
(
tester
.
getTopLeft
(
find
.
text
(
'bottom'
)),
const
Offset
(
0.0
,
-
400.0
));
await
tester
.
pump
();
expect
(
scrollable
.
scrollOffset
,
equals
(
50.0
));
expect
(
scrollable
.
virtualScrollOffset
,
greaterThan
(
50.0
));
});
}
}
packages/flutter/test/widget/scrollable_list_hit_testing_test.dart
View file @
fc83640c
...
@@ -151,4 +151,35 @@ void main() {
...
@@ -151,4 +151,35 @@ void main() {
await
tester
.
tapAt
(
new
Point
(
800.0
-
16.0
,
200.0
));
await
tester
.
tapAt
(
new
Point
(
800.0
-
16.0
,
200.0
));
expect
(
tapped
,
equals
(<
int
>[
5
,
4
,
4
]));
expect
(
tapped
,
equals
(<
int
>[
5
,
4
,
4
]));
});
});
testWidgets
(
'Tap immediately following clamped overscroll'
,
(
WidgetTester
tester
)
async
{
// Regression test for https://github.com/flutter/flutter/issues/5709
GlobalKey
<
ScrollableState
>
scrollableKey
=
new
GlobalKey
<
ScrollableState
>();
List
<
int
>
tapped
=
<
int
>[];
await
tester
.
pumpWidget
(
new
ClampOverscrolls
(
edge:
ScrollableEdge
.
both
,
child:
new
ScrollableList
(
scrollableKey:
scrollableKey
,
itemExtent:
200.0
,
children:
items
.
map
((
int
item
)
{
return
new
Container
(
child:
new
GestureDetector
(
onTap:
()
{
tapped
.
add
(
item
);
},
child:
new
Text
(
'
$item
'
)
)
);
})
)
)
);
await
tester
.
fling
(
find
.
text
(
'0'
),
const
Offset
(
0.0
,
400.0
),
1000.0
);
expect
(
scrollableKey
.
currentState
.
scrollOffset
,
equals
(
0.0
));
expect
(
scrollableKey
.
currentState
.
virtualScrollOffset
,
lessThan
(
0.0
));
await
tester
.
tapAt
(
new
Point
(
200.0
,
100.0
));
expect
(
tapped
,
equals
(<
int
>[
0
]));
});
}
}
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