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
c1d42a2f
Commit
c1d42a2f
authored
Dec 08, 2015
by
Hans Muller
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Revised PageableList
parent
4f22f3ec
Changes
9
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
442 additions
and
196 deletions
+442
-196
pageable_list.dart
examples/widgets/pageable_list.dart
+2
-9
scroll_behavior.dart
packages/flutter/lib/src/animation/scroll_behavior.dart
+30
-42
drag.dart
packages/flutter/lib/src/gestures/drag.dart
+2
-1
homogeneous_viewport.dart
packages/flutter/lib/src/widgets/homogeneous_viewport.dart
+158
-51
pageable_list.dart
packages/flutter/lib/src/widgets/pageable_list.dart
+185
-0
scrollable.dart
packages/flutter/lib/src/widgets/scrollable.dart
+58
-86
widgets.dart
packages/flutter/lib/widgets.dart
+1
-0
pageable_list_test.dart
packages/unit/test/widget/pageable_list_test.dart
+0
-1
snap_scrolling_test.dart
packages/unit/test/widget/snap_scrolling_test.dart
+6
-6
No files found.
examples/widgets/pageable_list.dart
View file @
c1d42a2f
...
...
@@ -120,18 +120,11 @@ class PageableListAppState extends State<PageableListApp> {
}
Widget
_buildBody
(
BuildContext
context
)
{
Widget
list
=
new
PageableList
<
CardModel
>(
return
new
PageableList
<
CardModel
>(
items:
cardModels
,
itemsWrap:
itemsWrap
,
itemBuilder:
buildCard
,
scrollDirection:
scrollDirection
,
itemExtent:
(
scrollDirection
==
ScrollDirection
.
vertical
)
?
pageSize
.
height
:
pageSize
.
width
);
return
new
SizeObserver
(
onSizeChanged:
updatePageSize
,
child:
list
scrollDirection:
scrollDirection
);
}
...
...
packages/flutter/lib/src/animation/scroll_behavior.dart
View file @
c1d42a2f
...
...
@@ -3,20 +3,13 @@
// found in the LICENSE file.
import
'dart:math'
as
math
;
import
'dart:ui'
as
ui
;
import
'package:newton/newton.dart'
;
const
double
_kSecondsPerMillisecond
=
1000.0
;
const
double
_kScrollDrag
=
0.025
;
// TODO(abarth): These values won't work well if there's a scale transform.
final
Tolerance
_kDefaultScrollTolerance
=
new
Tolerance
(
velocity:
1.0
/
(
0.050
*
ui
.
window
.
devicePixelRatio
),
// logical pixels per second
distance:
1.0
/
ui
.
window
.
devicePixelRatio
// logical pixels
);
/// An interface for controlling the behavior of scrollable widgets
/// An interface for controlling the behavior of scrollable widgets.
abstract
class
ScrollBehavior
{
/// Called when a drag gesture ends. Returns a simulation that
/// propels the scrollOffset.
...
...
@@ -24,10 +17,10 @@ abstract class ScrollBehavior {
/// Called when a drag gesture ends and toSnapOffset is specified.
/// Returns an animation that ends at the snap offset.
Simulation
createSnapScrollSimulation
(
double
startOffset
,
double
endOffset
,
double
v
elocity
)
=>
null
;
Simulation
createSnapScrollSimulation
(
double
startOffset
,
double
endOffset
,
double
startVelocity
,
double
endV
elocity
)
=>
null
;
/// Return the scroll offset to use when the user attempts to scroll
/// from the given offset by the given delta
/// from the given offset by the given delta
.
double
applyCurve
(
double
scrollOffset
,
double
scrollDelta
);
/// Whether this scroll behavior currently permits scrolling
...
...
@@ -39,11 +32,11 @@ abstract class ExtentScrollBehavior extends ScrollBehavior {
ExtentScrollBehavior
({
double
contentExtent:
0.0
,
double
containerExtent:
0.0
})
:
_contentExtent
=
contentExtent
,
_containerExtent
=
containerExtent
;
/// The linear extent of the content inside the scrollable widget
/// The linear extent of the content inside the scrollable widget
.
double
get
contentExtent
=>
_contentExtent
;
double
_contentExtent
;
/// The linear extent of the exterior of the scrollable widget
/// The linear extent of the exterior of the scrollable widget
.
double
get
containerExtent
=>
_containerExtent
;
double
_containerExtent
;
...
...
@@ -64,14 +57,14 @@ abstract class ExtentScrollBehavior extends ScrollBehavior {
return
scrollOffset
.
clamp
(
minScrollOffset
,
maxScrollOffset
);
}
/// The minimum value the scroll offset can obtain
/// The minimum value the scroll offset can obtain
.
double
get
minScrollOffset
;
/// The maximum value the scroll offset can ob
atin
/// The maximum value the scroll offset can ob
tain.
double
get
maxScrollOffset
;
}
/// A scroll behavior that prevents the user from exeeding scroll bounds
/// A scroll behavior that prevents the user from exeeding scroll bounds
.
class
BoundedBehavior
extends
ExtentScrollBehavior
{
BoundedBehavior
({
double
contentExtent:
0.0
,
double
containerExtent:
0.0
})
:
super
(
contentExtent:
contentExtent
,
containerExtent:
containerExtent
);
...
...
@@ -84,7 +77,18 @@ class BoundedBehavior extends ExtentScrollBehavior {
}
}
/// A scroll behavior that does not prevent the user from exeeding scroll bounds
Simulation
_createFlingScrollSimulation
(
double
position
,
double
velocity
,
double
minScrollOffset
,
double
maxScrollOffset
)
{
final
double
startVelocity
=
velocity
*
_kSecondsPerMillisecond
;
final
SpringDescription
spring
=
new
SpringDescription
.
withDampingRatio
(
mass:
1.0
,
springConstant:
170.0
,
ratio:
1.1
);
return
new
ScrollSimulation
(
position
,
startVelocity
,
minScrollOffset
,
maxScrollOffset
,
spring
,
_kScrollDrag
);
}
Simulation
_createSnapScrollSimulation
(
double
startOffset
,
double
endOffset
,
double
startVelocity
,
double
endVelocity
)
{
final
double
velocity
=
startVelocity
*
_kSecondsPerMillisecond
;
return
new
FrictionSimulation
.
through
(
startOffset
,
endOffset
,
velocity
,
endVelocity
);
}
/// A scroll behavior that does not prevent the user from exeeding scroll bounds.
class
UnboundedBehavior
extends
ExtentScrollBehavior
{
UnboundedBehavior
({
double
contentExtent:
0.0
,
double
containerExtent:
0.0
})
:
super
(
contentExtent:
contentExtent
,
containerExtent:
containerExtent
);
...
...
@@ -96,8 +100,8 @@ class UnboundedBehavior extends ExtentScrollBehavior {
);
}
Simulation
createSnapScrollSimulation
(
double
startOffset
,
double
endOffset
,
double
v
elocity
)
{
return
_createSnapScrollSimulation
(
startOffset
,
endOffset
,
v
elocity
);
Simulation
createSnapScrollSimulation
(
double
startOffset
,
double
endOffset
,
double
startVelocity
,
double
endV
elocity
)
{
return
_createSnapScrollSimulation
(
startOffset
,
endOffset
,
startVelocity
,
endV
elocity
);
}
double
get
minScrollOffset
=>
double
.
NEGATIVE_INFINITY
;
...
...
@@ -108,33 +112,17 @@ class UnboundedBehavior extends ExtentScrollBehavior {
}
}
Simulation
_createFlingScrollSimulation
(
double
position
,
double
velocity
,
double
minScrollOffset
,
double
maxScrollOffset
,
Tolerance
tolerance
)
{
double
startVelocity
=
velocity
*
_kSecondsPerMillisecond
;
SpringDescription
spring
=
new
SpringDescription
.
withDampingRatio
(
mass:
1.0
,
springConstant:
170.0
,
ratio:
1.1
);
ScrollSimulation
simulation
=
new
ScrollSimulation
(
position
,
startVelocity
,
minScrollOffset
,
maxScrollOffset
,
spring
,
_kScrollDrag
)
..
tolerance
=
tolerance
??
_kDefaultScrollTolerance
;
return
simulation
;
}
Simulation
_createSnapScrollSimulation
(
double
startOffset
,
double
endOffset
,
double
velocity
)
{
double
startVelocity
=
velocity
*
_kSecondsPerMillisecond
;
double
endVelocity
=
velocity
.
sign
*
_kDefaultScrollTolerance
.
velocity
;
return
new
FrictionSimulation
.
through
(
startOffset
,
endOffset
,
startVelocity
,
endVelocity
);
}
/// A scroll behavior that lets the user scroll beyond the scroll bounds with some resistance
/// A scroll behavior that lets the user scroll beyond the scroll bounds with some resistance.
class
OverscrollBehavior
extends
BoundedBehavior
{
OverscrollBehavior
({
double
contentExtent:
0.0
,
double
containerExtent:
0.0
})
:
super
(
contentExtent:
contentExtent
,
containerExtent:
containerExtent
);
Simulation
createFlingScrollSimulation
(
double
position
,
double
velocity
,
{
Tolerance
tolerance
}
)
{
return
_createFlingScrollSimulation
(
position
,
velocity
,
minScrollOffset
,
maxScrollOffset
,
tolerance
);
Simulation
createFlingScrollSimulation
(
double
position
,
double
velocity
)
{
return
_createFlingScrollSimulation
(
position
,
velocity
,
minScrollOffset
,
maxScrollOffset
);
}
Simulation
createSnapScrollSimulation
(
double
startOffset
,
double
endOffset
,
double
v
elocity
)
{
return
_createSnapScrollSimulation
(
startOffset
,
endOffset
,
v
elocity
);
Simulation
createSnapScrollSimulation
(
double
startOffset
,
double
endOffset
,
double
startVelocity
,
double
endV
elocity
)
{
return
_createSnapScrollSimulation
(
startOffset
,
endOffset
,
startVelocity
,
endV
elocity
);
}
double
applyCurve
(
double
scrollOffset
,
double
scrollDelta
)
{
...
...
@@ -154,13 +142,13 @@ class OverscrollBehavior extends BoundedBehavior {
}
}
/// A scroll behavior that lets the user scroll beyond the scroll bounds only when the bounds are disjoint
/// A scroll behavior that lets the user scroll beyond the scroll bounds only when the bounds are disjoint
.
class
OverscrollWhenScrollableBehavior
extends
OverscrollBehavior
{
bool
get
isScrollable
=>
contentExtent
>
containerExtent
;
Simulation
createFlingScrollSimulation
(
double
position
,
double
velocity
,
{
Tolerance
tolerance
}
)
{
Simulation
createFlingScrollSimulation
(
double
position
,
double
velocity
)
{
if
(
isScrollable
||
position
<
minScrollOffset
||
position
>
maxScrollOffset
)
return
super
.
createFlingScrollSimulation
(
position
,
velocity
,
tolerance:
tolerance
);
return
super
.
createFlingScrollSimulation
(
position
,
velocity
);
return
null
;
}
...
...
packages/flutter/lib/src/gestures/drag.dart
View file @
c1d42a2f
...
...
@@ -105,7 +105,8 @@ abstract class _DragGestureRecognizer<T extends dynamic> extends OneSequenceGest
Offset
velocity
=
tracker
.
getVelocity
();
if
(
velocity
!=
null
&&
_isFlingGesture
(
velocity
))
onEnd
(
velocity
);
onEnd
(
Offset
.
zero
);
else
onEnd
(
Offset
.
zero
);
}
_velocityTrackers
.
clear
();
}
...
...
packages/flutter/lib/src/widgets/homogeneous_viewport.dart
View file @
c1d42a2f
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/widgets/pageable_list.dart
0 → 100644
View file @
c1d42a2f
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:async'
;
import
'dart:math'
as
math
;
import
'package:flutter/animation.dart'
;
import
'package:flutter/gestures.dart'
;
import
'package:flutter/rendering.dart'
;
import
'basic.dart'
;
import
'framework.dart'
;
import
'homogeneous_viewport.dart'
;
import
'scrollable.dart'
;
enum
ItemsSnapAlignment
{
item
,
adjacentItem
}
typedef
void
PageChangedCallback
(
int
newPage
);
class
PageableList
<
T
>
extends
Scrollable
{
PageableList
({
Key
key
,
initialScrollOffset
,
ScrollDirection
scrollDirection:
ScrollDirection
.
vertical
,
ScrollListener
onScrollStart
,
ScrollListener
onScroll
,
ScrollListener
onScrollEnd
,
SnapOffsetCallback
snapOffsetCallback
,
double
snapAlignmentOffset:
0.0
,
this
.
items
,
this
.
itemBuilder
,
this
.
itemsWrap
:
false
,
this
.
itemsSnapAlignment
:
ItemsSnapAlignment
.
adjacentItem
,
this
.
onPageChanged
,
this
.
scrollableListPainter
,
this
.
duration
:
const
Duration
(
milliseconds:
200
),
this
.
curve
:
Curves
.
ease
})
:
super
(
key:
key
,
initialScrollOffset:
initialScrollOffset
,
scrollDirection:
scrollDirection
,
onScrollStart:
onScrollStart
,
onScroll:
onScroll
,
onScrollEnd:
onScrollEnd
,
snapOffsetCallback:
snapOffsetCallback
,
snapAlignmentOffset:
snapAlignmentOffset
);
final
List
<
T
>
items
;
final
ItemBuilder
<
T
>
itemBuilder
;
final
ItemsSnapAlignment
itemsSnapAlignment
;
final
bool
itemsWrap
;
final
PageChangedCallback
onPageChanged
;
final
ScrollableListPainter
scrollableListPainter
;
final
Duration
duration
;
final
Curve
curve
;
PageableListState
<
T
,
PageableList
<
T
>>
createState
()
=>
new
PageableListState
<
T
,
PageableList
<
T
>>();
}
class
PageableListState
<
T
,
Config
extends
PageableList
<
T
>>
extends
ScrollableState
<
Config
>
{
int
get
itemCount
=>
config
.
items
?.
length
??
0
;
int
_previousItemCount
;
double
pixelToScrollOffset
(
double
value
)
{
final
RenderBox
box
=
context
.
findRenderObject
();
if
(
box
==
null
||
!
box
.
hasSize
)
return
0.0
;
final
double
pixelScrollExtent
=
config
.
scrollDirection
==
ScrollDirection
.
vertical
?
box
.
size
.
height
:
box
.
size
.
width
;
return
pixelScrollExtent
==
0.0
?
0.0
:
value
/
pixelScrollExtent
;
}
void
didUpdateConfig
(
Config
oldConfig
)
{
super
.
didUpdateConfig
(
oldConfig
);
bool
scrollBehaviorUpdateNeeded
=
config
.
scrollDirection
!=
oldConfig
.
scrollDirection
;
if
(
config
.
itemsWrap
!=
oldConfig
.
itemsWrap
)
scrollBehaviorUpdateNeeded
=
true
;
if
(
itemCount
!=
_previousItemCount
)
{
_previousItemCount
=
itemCount
;
scrollBehaviorUpdateNeeded
=
true
;
}
if
(
scrollBehaviorUpdateNeeded
)
_updateScrollBehavior
();
}
void
_updateScrollBehavior
()
{
// if you don't call this from build(), you must call it from setState().
if
(
config
.
scrollableListPainter
!=
null
)
config
.
scrollableListPainter
.
contentExtent
=
itemCount
.
toDouble
();
scrollTo
(
scrollBehavior
.
updateExtents
(
contentExtent:
itemCount
.
toDouble
(),
containerExtent:
1.0
,
scrollOffset:
scrollOffset
));
}
void
dispatchOnScrollStart
()
{
super
.
dispatchOnScrollStart
();
config
.
scrollableListPainter
?.
scrollStarted
();
}
void
dispatchOnScroll
()
{
super
.
dispatchOnScroll
();
if
(
config
.
scrollableListPainter
!=
null
)
config
.
scrollableListPainter
.
scrollOffset
=
scrollOffset
;
}
void
dispatchOnScrollEnd
()
{
super
.
dispatchOnScrollEnd
();
config
.
scrollableListPainter
?.
scrollEnded
();
}
Widget
buildContent
(
BuildContext
context
)
{
if
(
itemCount
!=
_previousItemCount
)
{
_previousItemCount
=
itemCount
;
_updateScrollBehavior
();
}
return
new
HomogeneousPageViewport
(
builder:
buildItems
,
itemsWrap:
config
.
itemsWrap
,
itemCount:
itemCount
,
direction:
config
.
scrollDirection
,
startOffset:
scrollOffset
,
overlayPainter:
config
.
scrollableListPainter
);
}
ScrollBehavior
createScrollBehavior
()
{
return
config
.
itemsWrap
?
new
UnboundedBehavior
()
:
new
OverscrollBehavior
();
}
ExtentScrollBehavior
get
scrollBehavior
=>
super
.
scrollBehavior
;
bool
get
snapScrollOffsetChanges
=>
config
.
itemsSnapAlignment
==
ItemsSnapAlignment
.
item
;
double
snapScrollOffset
(
double
newScrollOffset
)
{
double
previousItemOffset
=
newScrollOffset
.
floorToDouble
();
double
nextItemOffset
=
newScrollOffset
.
ceilToDouble
();
return
(
newScrollOffset
-
previousItemOffset
<
0.5
?
previousItemOffset
:
nextItemOffset
)
.
clamp
(
scrollBehavior
.
minScrollOffset
,
scrollBehavior
.
maxScrollOffset
);
}
Future
_flingToAdjacentItem
(
Offset
velocity
)
{
double
scrollVelocity
=
scrollDirectionVelocity
(
velocity
);
double
newScrollOffset
=
snapScrollOffset
(
scrollOffset
+
scrollVelocity
.
sign
)
.
clamp
(
snapScrollOffset
(
scrollOffset
-
0.5
),
snapScrollOffset
(
scrollOffset
+
0.5
));
return
scrollTo
(
newScrollOffset
,
duration:
config
.
duration
,
curve:
config
.
curve
)
.
then
(
_notifyPageChanged
);
}
Future
fling
(
Offset
velocity
)
{
switch
(
config
.
itemsSnapAlignment
)
{
case
ItemsSnapAlignment
.
adjacentItem
:
return
_flingToAdjacentItem
(
velocity
);
default
:
return
super
.
fling
(
velocity
).
then
(
_notifyPageChanged
);
}
}
Future
settleScrollOffset
()
{
return
scrollTo
(
snapScrollOffset
(
scrollOffset
),
duration:
config
.
duration
,
curve:
config
.
curve
)
.
then
(
_notifyPageChanged
);
}
List
<
Widget
>
buildItems
(
BuildContext
context
,
int
start
,
int
count
)
{
List
<
Widget
>
result
=
new
List
<
Widget
>();
int
begin
=
config
.
itemsWrap
?
start
:
math
.
max
(
0
,
start
);
int
end
=
config
.
itemsWrap
?
begin
+
count
:
math
.
min
(
begin
+
count
,
config
.
items
.
length
);
for
(
int
i
=
begin
;
i
<
end
;
++
i
)
result
.
add
(
config
.
itemBuilder
(
context
,
config
.
items
[
i
%
itemCount
],
i
));
assert
(
result
.
every
((
Widget
item
)
=>
item
.
key
!=
null
));
return
result
;
}
void
_notifyPageChanged
(
_
)
{
if
(
config
.
onPageChanged
!=
null
)
config
.
onPageChanged
(
itemCount
==
0
?
0
:
scrollOffset
.
floor
()
%
itemCount
);
}
}
packages/flutter/lib/src/widgets/scrollable.dart
View file @
c1d42a2f
...
...
@@ -24,6 +24,11 @@ const double _kMillisecondsPerSecond = 1000.0;
const
double
_kMinFlingVelocity
=
-
kMaxFlingVelocity
*
_kMillisecondsPerSecond
;
const
double
_kMaxFlingVelocity
=
kMaxFlingVelocity
*
_kMillisecondsPerSecond
;
final
Tolerance
kPixelScrollTolerance
=
new
Tolerance
(
velocity:
1.0
/
(
0.050
*
ui
.
window
.
devicePixelRatio
),
// logical pixels per second
distance:
1.0
/
ui
.
window
.
devicePixelRatio
// logical pixels
);
typedef
void
ScrollListener
(
double
scrollOffset
);
typedef
double
SnapOffsetCallback
(
double
scrollOffset
);
...
...
@@ -122,6 +127,18 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
return
new
Offset
(
0.0
,
scrollOffset
);
}
/// Convert a position or velocity measured in terms of pixels to a scrollOffset.
/// Scrollable gesture handlers convert their incoming values with this method.
/// Subclasses that define scrollOffset in units other than pixels must
/// override this method.
double
pixelToScrollOffset
(
double
pixelValue
)
=>
pixelValue
;
double
scrollDirectionVelocity
(
Offset
scrollVelocity
)
{
return
config
.
scrollDirection
==
ScrollDirection
.
horizontal
?
-
scrollVelocity
.
dx
:
-
scrollVelocity
.
dy
;
}
ScrollBehavior
_scrollBehavior
;
ScrollBehavior
createScrollBehavior
();
ScrollBehavior
get
scrollBehavior
{
...
...
@@ -180,11 +197,32 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
}
Simulation
_createFlingSimulation
(
double
velocity
)
{
return
scrollBehavior
.
createFlingScrollSimulation
(
scrollOffset
,
velocity
);
/*
// Assume that we're rendering at atleast 15 FPS. Stop when we're
// scrolling less than one logical pixel per frame. We're essentially
// normalizing by the devicePixelRatio so that the threshold has the
// same effect independent of the device's pixel density.
double endVelocity = pixelToScrollOffset(15.0 * ui.window.devicePixelRatio);
// Similar to endVelocity. Stop scrolling when we're this close to
// destiniation scroll offset.
double endDistance = pixelToScrollOffset(0.5 * ui.window.devicePixelRatio);
*/
final
double
endVelocity
=
pixelToScrollOffset
(
kPixelScrollTolerance
.
velocity
);
final
double
endDistance
=
pixelToScrollOffset
(
kPixelScrollTolerance
.
distance
);
return
scrollBehavior
.
createFlingScrollSimulation
(
scrollOffset
,
velocity
)
..
tolerance
=
new
Tolerance
(
velocity:
endVelocity
.
abs
(),
distance:
endDistance
);
}
double
snapScrollOffset
(
double
value
)
{
return
config
.
snapOffsetCallback
==
null
?
value
:
config
.
snapOffsetCallback
(
value
);
}
bool
get
snapScrollOffsetChanges
=>
config
.
snapOffsetCallback
!=
null
;
Simulation
_createSnapSimulation
(
double
velocity
)
{
if
(
velocity
==
null
||
config
.
snapOffsetCallback
==
null
||
!
_scrollOffsetIsInBounds
(
scrollOffset
))
if
(
!
snapScrollOffsetChanges
||
velocity
==
0.0
||
!
_scrollOffsetIsInBounds
(
scrollOffset
))
return
null
;
Simulation
simulation
=
_createFlingSimulation
(
velocity
);
...
...
@@ -195,14 +233,15 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
if
(
endScrollOffset
.
isNaN
)
return
null
;
double
snappedScrollOffset
=
config
.
snapOffsetCallback
(
endScrollOffset
+
config
.
snapAlignmentOffset
);
double
snappedScrollOffset
=
snapScrollOffset
(
endScrollOffset
+
config
.
snapAlignmentOffset
);
double
alignedScrollOffset
=
snappedScrollOffset
-
config
.
snapAlignmentOffset
;
if
(!
_scrollOffsetIsInBounds
(
alignedScrollOffset
))
return
null
;
double
snapVelocity
=
velocity
.
abs
()
*
(
alignedScrollOffset
-
scrollOffset
).
sign
;
double
endVelocity
=
pixelToScrollOffset
(
kPixelScrollTolerance
.
velocity
*
velocity
.
sign
);
Simulation
toSnapSimulation
=
scrollBehavior
.
createSnapScrollSimulation
(
scrollOffset
,
alignedScrollOffset
,
snapVelocity
);
scrollBehavior
.
createSnapScrollSimulation
(
scrollOffset
,
alignedScrollOffset
,
snapVelocity
,
endVelocity
);
if
(
toSnapSimulation
==
null
)
return
null
;
...
...
@@ -211,10 +250,10 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
return
new
ClampedSimulation
(
toSnapSimulation
,
xMin:
offsetMin
,
xMax:
offsetMax
);
}
Future
_startToEndAnimation
({
double
velocity
})
{
Future
_startToEndAnimation
(
Offset
scrollVelocity
)
{
double
velocity
=
scrollDirectionVelocity
(
scrollVelocity
);
_animation
.
stop
();
Simulation
simulation
=
_createSnapSimulation
(
velocity
)
??
_createFlingSimulation
(
velocity
??
0.0
);
Simulation
simulation
=
_createSnapSimulation
(
velocity
)
??
_createFlingSimulation
(
velocity
);
if
(
simulation
==
null
)
return
new
Future
.
value
();
return
_animation
.
animateWith
(
simulation
);
...
...
@@ -254,16 +293,16 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
return
scrollTo
(
newScrollOffset
,
duration:
duration
,
curve:
curve
);
}
Future
fling
(
Offset
v
elocity
)
{
if
(
v
elocity
!=
Offset
.
zero
)
return
_startToEndAnimation
(
velocity:
_scrollVelocity
(
velocity
)
);
Future
fling
(
Offset
scrollV
elocity
)
{
if
(
scrollV
elocity
!=
Offset
.
zero
)
return
_startToEndAnimation
(
scrollVelocity
);
if
(!
_animation
.
isAnimating
)
return
settleScrollOffset
();
return
new
Future
.
value
();
}
Future
settleScrollOffset
()
{
return
_startToEndAnimation
();
return
_startToEndAnimation
(
Offset
.
zero
);
}
void
dispatchOnScrollStart
()
{
...
...
@@ -282,13 +321,6 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
config
.
onScrollEnd
(
_scrollOffset
);
}
double
_scrollVelocity
(
ui
.
Offset
velocity
)
{
double
scrollVelocity
=
config
.
scrollDirection
==
ScrollDirection
.
horizontal
?
-
velocity
.
dx
:
-
velocity
.
dy
;
return
scrollVelocity
.
clamp
(
_kMinFlingVelocity
,
_kMaxFlingVelocity
)
/
_kMillisecondsPerSecond
;
}
void
_handlePointerDown
(
_
)
{
_animation
.
stop
();
}
...
...
@@ -300,11 +332,16 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
void
_handleDragUpdate
(
double
delta
)
{
// We negate the delta here because a positive scroll offset moves the
// the content up (or to the left) rather than down (or the right).
scrollBy
(
-
delta
);
scrollBy
(
pixelToScrollOffset
(-
delta
)
);
}
Future
_handleDragEnd
(
Offset
velocity
)
{
return
fling
(
velocity
).
then
((
_
)
{
double
_toScrollVelocity
(
double
velocity
)
{
return
pixelToScrollOffset
(
velocity
.
clamp
(
_kMinFlingVelocity
,
_kMaxFlingVelocity
)
/
_kMillisecondsPerSecond
);
}
Future
_handleDragEnd
(
Offset
pixelScrollVelocity
)
{
final
Offset
scrollVelocity
=
new
Offset
(
_toScrollVelocity
(
pixelScrollVelocity
.
dx
),
_toScrollVelocity
(
pixelScrollVelocity
.
dy
));
return
fling
(
scrollVelocity
).
then
((
_
)
{
dispatchOnScrollEnd
();
});
}
...
...
@@ -690,71 +727,6 @@ class ScrollableListState<T, Config extends ScrollableList<T>> extends Scrollabl
}
}
typedef
void
PageChangedCallback
(
int
newPage
);
class
PageableList
<
T
>
extends
ScrollableList
<
T
>
{
PageableList
({
Key
key
,
int
initialPage
,
ScrollDirection
scrollDirection:
ScrollDirection
.
horizontal
,
ScrollListener
onScroll
,
List
<
T
>
items
,
ItemBuilder
<
T
>
itemBuilder
,
bool
itemsWrap:
false
,
double
itemExtent
,
this
.
onPageChanged
,
EdgeDims
padding
,
this
.
duration
:
const
Duration
(
milliseconds:
200
),
this
.
curve
:
Curves
.
ease
})
:
super
(
key:
key
,
initialScrollOffset:
initialPage
==
null
?
null
:
initialPage
*
itemExtent
,
scrollDirection:
scrollDirection
,
onScroll:
onScroll
,
items:
items
,
itemBuilder:
itemBuilder
,
itemsWrap:
itemsWrap
,
itemExtent:
itemExtent
,
padding:
padding
);
final
Duration
duration
;
final
Curve
curve
;
final
PageChangedCallback
onPageChanged
;
PageableListState
<
T
>
createState
()
=>
new
PageableListState
<
T
>();
}
class
PageableListState
<
T
>
extends
ScrollableListState
<
T
,
PageableList
<
T
>>
{
double
_snapScrollOffset
(
double
newScrollOffset
)
{
double
scaledScrollOffset
=
newScrollOffset
/
config
.
itemExtent
;
double
previousScrollOffset
=
scaledScrollOffset
.
floor
()
*
config
.
itemExtent
;
double
nextScrollOffset
=
scaledScrollOffset
.
ceil
()
*
config
.
itemExtent
;
double
delta
=
newScrollOffset
-
previousScrollOffset
;
return
(
delta
<
config
.
itemExtent
/
2.0
?
previousScrollOffset
:
nextScrollOffset
)
.
clamp
(
scrollBehavior
.
minScrollOffset
,
scrollBehavior
.
maxScrollOffset
);
}
Future
fling
(
ui
.
Offset
velocity
)
{
double
scrollVelocity
=
_scrollVelocity
(
velocity
);
double
newScrollOffset
=
_snapScrollOffset
(
scrollOffset
+
scrollVelocity
.
sign
*
config
.
itemExtent
)
.
clamp
(
_snapScrollOffset
(
scrollOffset
-
config
.
itemExtent
/
2.0
),
_snapScrollOffset
(
scrollOffset
+
config
.
itemExtent
/
2.0
));
return
scrollTo
(
newScrollOffset
,
duration:
config
.
duration
,
curve:
config
.
curve
).
then
(
_notifyPageChanged
);
}
int
get
currentPage
=>
(
scrollOffset
/
config
.
itemExtent
).
floor
()
%
itemCount
;
void
_notifyPageChanged
(
_
)
{
if
(
config
.
onPageChanged
!=
null
)
config
.
onPageChanged
(
currentPage
);
}
Future
settleScrollOffset
()
{
return
scrollTo
(
_snapScrollOffset
(
scrollOffset
),
duration:
config
.
duration
,
curve:
config
.
curve
).
then
(
_notifyPageChanged
);
}
}
/// A general scrollable list for a large number of children that might not all
/// have the same height. Prefer [ScrollableWidgetList] when all the children
/// have the same height because it can use that property to be more efficient.
...
...
packages/flutter/lib/widgets.dart
View file @
c1d42a2f
...
...
@@ -28,6 +28,7 @@ export 'src/widgets/notification_listener.dart';
export
'src/widgets/overlay.dart'
;
export
'src/widgets/page_storage.dart'
;
export
'src/widgets/pages.dart'
;
export
'src/widgets/pageable_list.dart'
;
export
'src/widgets/placeholder.dart'
;
export
'src/widgets/routes.dart'
;
export
'src/widgets/scrollable.dart'
;
...
...
packages/unit/test/widget/pageable_list_test.dart
View file @
c1d42a2f
...
...
@@ -27,7 +27,6 @@ Widget buildFrame() {
items:
pages
,
itemBuilder:
buildPage
,
itemsWrap:
itemsWrap
,
itemExtent:
pageSize
.
width
,
scrollDirection:
ScrollDirection
.
horizontal
,
onPageChanged:
(
int
page
)
{
currentPage
=
page
;
}
);
...
...
packages/unit/test/widget/snap_scrolling_test.dart
View file @
c1d42a2f
...
...
@@ -57,7 +57,7 @@ Future fling(double velocity) {
}
void
main
(
)
{
test
(
'ScrollableList snap scrolling, fling(-
800
)'
,
()
{
test
(
'ScrollableList snap scrolling, fling(-
0.8
)'
,
()
{
testWidgets
((
WidgetTester
tester
)
{
tester
.
pumpWidget
(
buildFrame
());
...
...
@@ -67,7 +67,7 @@ void main() {
Duration
dt
=
const
Duration
(
seconds:
2
);
fling
(-
800.0
);
fling
(-
0.8
);
tester
.
pump
();
// Start the scheduler at 0.0
tester
.
pump
(
dt
);
expect
(
scrollOffset
,
closeTo
(
200.0
,
1.0
));
...
...
@@ -76,7 +76,7 @@ void main() {
tester
.
pump
();
expect
(
scrollOffset
,
0.0
);
fling
(-
2
000
.0
);
fling
(-
2.0
);
tester
.
pump
();
tester
.
pump
(
dt
);
expect
(
scrollOffset
,
closeTo
(
400.0
,
1.0
));
...
...
@@ -85,7 +85,7 @@ void main() {
tester
.
pump
();
expect
(
scrollOffset
,
400.0
);
fling
(
800.0
);
fling
(
0.8
);
tester
.
pump
();
tester
.
pump
(
dt
);
expect
(
scrollOffset
,
closeTo
(
0.0
,
1.0
));
...
...
@@ -94,7 +94,7 @@ void main() {
tester
.
pump
();
expect
(
scrollOffset
,
800.0
);
fling
(
2
000
.0
);
fling
(
2.0
);
tester
.
pump
();
tester
.
pump
(
dt
);
expect
(
scrollOffset
,
closeTo
(
200.0
,
1.0
));
...
...
@@ -104,7 +104,7 @@ void main() {
expect
(
scrollOffset
,
800.0
);
bool
completed
=
false
;
fling
(
2
000
.0
).
then
((
_
)
{
fling
(
2.0
).
then
((
_
)
{
completed
=
true
;
expect
(
scrollOffset
,
closeTo
(
200.0
,
1.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