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
63160b3d
Commit
63160b3d
authored
Jan 21, 2017
by
Ian Hickson
Committed by
GitHub
Jan 21, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Scrolling Refactor (#7420)
parent
e52bda2c
Changes
24
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
24 changed files
with
3085 additions
and
93 deletions
+3085
-93
app.dart
packages/flutter/lib/src/material/app.dart
+19
-1
overscroll_indicator.dart
packages/flutter/lib/src/material/overscroll_indicator.dart
+2
-0
theme_data.dart
packages/flutter/lib/src/material/theme_data.dart
+1
-1
sliver.dart
packages/flutter/lib/src/rendering/sliver.dart
+72
-61
basic.dart
packages/flutter/lib/src/widgets/basic.dart
+10
-0
framework.dart
packages/flutter/lib/src/widgets/framework.dart
+9
-2
notification_listener.dart
packages/flutter/lib/src/widgets/notification_listener.dart
+1
-1
overscroll_indicator.dart
packages/flutter/lib/src/widgets/overscroll_indicator.dart
+466
-0
scroll_absolute.dart
packages/flutter/lib/src/widgets/scroll_absolute.dart
+688
-0
scroll_behavior.dart
packages/flutter/lib/src/widgets/scroll_behavior.dart
+2
-0
scroll_configuration.dart
packages/flutter/lib/src/widgets/scroll_configuration.dart
+2
-0
scroll_notification.dart
packages/flutter/lib/src/widgets/scroll_notification.dart
+213
-0
scroll_simulation.dart
packages/flutter/lib/src/widgets/scroll_simulation.dart
+146
-22
scrollable.dart
packages/flutter/lib/src/widgets/scrollable.dart
+643
-1
viewport.dart
packages/flutter/lib/src/widgets/viewport.dart
+99
-0
widgets.dart
packages/flutter/lib/widgets.dart
+4
-0
mock_canvas.dart
packages/flutter/test/rendering/mock_canvas.dart
+21
-2
slivers_test.dart
packages/flutter/test/rendering/slivers_test.dart
+7
-2
framework_test.dart
packages/flutter/test/widgets/framework_test.dart
+20
-0
overscroll_indicator_test.dart
packages/flutter/test/widgets/overscroll_indicator_test.dart
+248
-0
scrollable_custom_scroll_behavior_test.dart
.../test/widgets/scrollable_custom_scroll_behavior_test.dart
+106
-0
scrollable_test.dart
packages/flutter/test/widgets/scrollable_test.dart
+81
-0
slivers_protocol_test.dart
packages/flutter/test/widgets/slivers_protocol_test.dart
+113
-0
slivers_test.dart
packages/flutter/test/widgets/slivers_test.dart
+112
-0
No files found.
packages/flutter/lib/src/material/app.dart
View file @
63160b3d
...
@@ -3,6 +3,7 @@
...
@@ -3,6 +3,7 @@
// found in the LICENSE file.
// found in the LICENSE file.
import
'package:flutter/rendering.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/widgets.dart'
;
import
'package:flutter/widgets.dart'
;
import
'arc.dart'
;
import
'arc.dart'
;
...
@@ -212,6 +213,18 @@ class _ScrollLikeMountainViewDelegate extends ScrollConfigurationDelegate {
...
@@ -212,6 +213,18 @@ class _ScrollLikeMountainViewDelegate extends ScrollConfigurationDelegate {
bool
updateShouldNotify
(
ScrollConfigurationDelegate
old
)
=>
false
;
bool
updateShouldNotify
(
ScrollConfigurationDelegate
old
)
=>
false
;
}
}
class
_MaterialScrollBehavior
extends
ViewportScrollBehavior
{
@override
TargetPlatform
getPlatform
(
BuildContext
context
)
{
return
Theme
.
of
(
context
).
platform
;
}
@override
Color
getGlowColor
(
BuildContext
context
)
{
return
Theme
.
of
(
context
).
accentColor
;
}
}
class
_MaterialAppState
extends
State
<
MaterialApp
>
{
class
_MaterialAppState
extends
State
<
MaterialApp
>
{
HeroController
_heroController
;
HeroController
_heroController
;
...
@@ -288,9 +301,14 @@ class _MaterialAppState extends State<MaterialApp> {
...
@@ -288,9 +301,14 @@ class _MaterialAppState extends State<MaterialApp> {
return
true
;
return
true
;
});
});
re
turn
new
ScrollConfiguration
(
re
sult
=
new
ScrollConfiguration
(
delegate:
_getScrollDelegate
(
theme
.
platform
),
delegate:
_getScrollDelegate
(
theme
.
platform
),
child:
result
child:
result
);
);
return
new
ScrollConfiguration2
(
delegate:
new
_MaterialScrollBehavior
(),
child:
result
);
}
}
}
}
packages/flutter/lib/src/material/overscroll_indicator.dart
View file @
63160b3d
...
@@ -2,6 +2,8 @@
...
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// found in the LICENSE file.
// DELETE THIS FILE WHEN REMOVING LEGACY SCROLLING CODE
import
'dart:async'
show
Timer
;
import
'dart:async'
show
Timer
;
import
'dart:math'
as
math
;
import
'dart:math'
as
math
;
...
...
packages/flutter/lib/src/material/theme_data.dart
View file @
63160b3d
...
@@ -547,5 +547,5 @@ class ThemeData {
...
@@ -547,5 +547,5 @@ class ThemeData {
}
}
@override
@override
String
toString
()
=>
'
$runtimeType
(
$brightness
$primaryColor
etc...)'
;
String
toString
()
=>
'
$runtimeType
(
$
{ platform != defaultTargetPlatform ? "$platform " : ''}$
brightness
$primaryColor
etc...)'
;
}
}
packages/flutter/lib/src/rendering/sliver.dart
View file @
63160b3d
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/widgets/basic.dart
View file @
63160b3d
...
@@ -2703,6 +2703,16 @@ class WidgetToRenderBoxAdapter extends LeafRenderObjectWidget {
...
@@ -2703,6 +2703,16 @@ class WidgetToRenderBoxAdapter extends LeafRenderObjectWidget {
}
}
}
}
class
SliverToBoxAdapter
extends
SingleChildRenderObjectWidget
{
SliverToBoxAdapter
({
Key
key
,
Widget
child
,
})
:
super
(
key:
key
,
child:
child
);
@override
RenderSliverToBoxAdapter
createRenderObject
(
BuildContext
context
)
=>
new
RenderSliverToBoxAdapter
();
}
// EVENT HANDLING
// EVENT HANDLING
...
...
packages/flutter/lib/src/widgets/framework.dart
View file @
63160b3d
...
@@ -12,9 +12,9 @@ import 'package:flutter/rendering.dart';
...
@@ -12,9 +12,9 @@ import 'package:flutter/rendering.dart';
import
'package:flutter/foundation.dart'
;
import
'package:flutter/foundation.dart'
;
export
'dart:ui'
show
hashValues
,
hashList
;
export
'dart:ui'
show
hashValues
,
hashList
;
export
'package:flutter/foundation.dart'
show
FlutterError
;
export
'package:flutter/foundation.dart'
show
FlutterError
,
debugPrint
,
debugPrintStack
;
export
'package:flutter/foundation.dart'
show
VoidCallback
,
ValueChanged
,
ValueGetter
,
ValueSetter
;
export
'package:flutter/foundation.dart'
show
VoidCallback
,
ValueChanged
,
ValueGetter
,
ValueSetter
;
export
'package:flutter/rendering.dart'
show
RenderObject
,
RenderBox
,
debug
Print
;
export
'package:flutter/rendering.dart'
show
RenderObject
,
RenderBox
,
debug
DumpRenderTree
;
// KEYS
// KEYS
...
@@ -3864,6 +3864,13 @@ class MultiChildRenderObjectElement extends RenderObjectElement {
...
@@ -3864,6 +3864,13 @@ class MultiChildRenderObjectElement extends RenderObjectElement {
@override
@override
MultiChildRenderObjectWidget
get
widget
=>
super
.
widget
;
MultiChildRenderObjectWidget
get
widget
=>
super
.
widget
;
/// The current list of children of this element.
///
/// This list is filtered to hide elements that have been forgotten (using
/// [forgetChild]).
@protected
Iterable
<
Element
>
get
children
=>
_children
.
where
((
Element
child
)
=>
!
_forgottenChildren
.
contains
(
child
));
List
<
Element
>
_children
;
List
<
Element
>
_children
;
// We keep a set of forgotten children to avoid O(n^2) work walking _children
// We keep a set of forgotten children to avoid O(n^2) work walking _children
// repeatedly to remove children.
// repeatedly to remove children.
...
...
packages/flutter/lib/src/widgets/notification_listener.dart
View file @
63160b3d
...
@@ -122,7 +122,7 @@ class NotificationListener<T extends Notification> extends StatelessWidget {
...
@@ -122,7 +122,7 @@ class NotificationListener<T extends Notification> extends StatelessWidget {
/// Useful if, for instance, you're trying to align multiple descendants.
/// Useful if, for instance, you're trying to align multiple descendants.
///
///
/// In the widgets library, only the [SizeChangedLayoutNotifier] class and
/// In the widgets library, only the [SizeChangedLayoutNotifier] class and
/// [Scrollable] classes dispatch this notification (specifically, they dispatch
/// [Scrollable
2
] classes dispatch this notification (specifically, they dispatch
/// [SizeChangedLayoutNotification]s and [ScrollNotification]s respectively).
/// [SizeChangedLayoutNotification]s and [ScrollNotification]s respectively).
/// Transitions, in particular, do not. Changing one's layout in one's build
/// Transitions, in particular, do not. Changing one's layout in one's build
/// function does not cause this notification to be dispatched automatically. If
/// function does not cause this notification to be dispatched automatically. If
...
...
packages/flutter/lib/src/widgets/overscroll_indicator.dart
0 → 100644
View file @
63160b3d
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/widgets/scroll_absolute.dart
0 → 100644
View file @
63160b3d
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/widgets/scroll_behavior.dart
View file @
63160b3d
...
@@ -2,6 +2,8 @@
...
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// found in the LICENSE file.
// DELETE THIS FILE WHEN REMOVING LEGACY SCROLLING CODE
import
'dart:math'
as
math
;
import
'dart:math'
as
math
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/foundation.dart'
;
...
...
packages/flutter/lib/src/widgets/scroll_configuration.dart
View file @
63160b3d
...
@@ -2,6 +2,8 @@
...
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// found in the LICENSE file.
// DELETE THIS FILE WHEN REMOVING LEGACY SCROLLING CODE
import
'package:flutter/foundation.dart'
;
import
'package:flutter/foundation.dart'
;
import
'framework.dart'
;
import
'framework.dart'
;
...
...
packages/flutter/lib/src/widgets/scroll_notification.dart
0 → 100644
View file @
63160b3d
// Copyright 2016 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
'package:flutter/foundation.dart'
;
import
'package:flutter/gestures.dart'
;
import
'package:flutter/rendering.dart'
;
import
'framework.dart'
;
import
'basic.dart'
;
import
'notification_listener.dart'
;
import
'scrollable.dart'
show
Scrollable2
,
Scrollable2State
;
/// A description of a [Scrollable2]'s contents, useful for modelling the state
/// of the viewport, for example by a [Scrollbar].
///
/// The units used by the [extentBefore], [extentInside], and [extentAfter] are
/// not defined, but must be consistent. For example, they could be in pixels,
/// or in percentages, or in units of the [extentInside] (in the latter case,
/// [extentInside] would always be 1.0).
class
ScrollableMetrics
{
/// Create a description of the metrics of a [Scrollable2]'s contents.
///
/// The three arguments must be present, non-null, finite, and non-negative.
const
ScrollableMetrics
({
@required
this
.
extentBefore
,
@required
this
.
extentInside
,
@required
this
.
extentAfter
,
});
/// The quantity of content conceptually "above" the currently visible content
/// of the viewport in the scrollable. This is the content above the content
/// described by [extentInside].
///
/// The units are in general arbitrary, and decided by the [ScrollPosition]
/// that generated the [ScrollableMetrics]. They will be the same units as for
/// [extentInside] and [extentAfter].
final
double
extentBefore
;
/// The quantity of visible content. If [extentBefore] and [extentAfter] are
/// non-zero, then this is typically the height of the viewport. It could be
/// less if there is less content visible than the size of the viewport.
///
/// The units are in general arbitrary, and decided by the [ScrollPosition]
/// that generated the [ScrollableMetrics]. They will be the same units as for
/// [extentBefore] and [extentAfter].
final
double
extentInside
;
/// The quantity of content conceptually "below" the currently visible content
/// of the viewport in the scrollable. This is the content below the content
/// described by [extentInside].
///
/// The units are in general arbitrary, and decided by the [ScrollPosition]
/// that generated the [ScrollableMetrics]. They will be the same units as for
/// [extentBefore] and [extentInside].
final
double
extentAfter
;
@override
String
toString
()
{
return
'
$runtimeType
(
${extentBefore.toStringAsFixed(1)}
..[
${extentInside.toStringAsFixed(1)}
]..
${extentAfter.toStringAsFixed(1)}
})'
;
}
}
abstract
class
ScrollNotification2
extends
LayoutChangedNotification
{
/// Creates a notification about scrolling.
ScrollNotification2
({
@required
Scrollable2State
scrollable
,
})
:
axisDirection
=
scrollable
.
config
.
axisDirection
,
metrics
=
scrollable
.
position
.
getMetrics
(),
context
=
scrollable
.
context
;
/// The direction that positive scroll offsets indicate.
final
AxisDirection
axisDirection
;
Axis
get
axis
=>
axisDirectionToAxis
(
axisDirection
);
final
ScrollableMetrics
metrics
;
/// The build context of the [Scrollable2] that fired this notification.
///
/// This can be used to find the scrollable's render objects to determine the
/// size of the viewport, for instance.
// TODO(ianh): Maybe just fold those into the ScrollableMetrics?
final
BuildContext
context
;
/// The number of [Scrollable2] widgets that this notification has bubbled
/// through. Typically listeners only respond to notifications with a [depth]
/// of zero.
int
get
depth
=>
_depth
;
int
_depth
=
0
;
@override
bool
visitAncestor
(
Element
element
)
{
if
(
element
.
widget
is
Scrollable2
)
_depth
+=
1
;
return
super
.
visitAncestor
(
element
);
}
@override
void
debugFillDescription
(
List
<
String
>
description
)
{
super
.
debugFillDescription
(
description
);
description
.
add
(
'
$axisDirection
'
);
description
.
add
(
'metrics:
$metrics
'
);
description
.
add
(
'depth:
$depth
'
);
}
}
class
ScrollStartNotification
extends
ScrollNotification2
{
ScrollStartNotification
({
@required
Scrollable2State
scrollable
,
this
.
dragDetails
,
})
:
super
(
scrollable:
scrollable
);
final
DragStartDetails
dragDetails
;
@override
void
debugFillDescription
(
List
<
String
>
description
)
{
super
.
debugFillDescription
(
description
);
if
(
dragDetails
!=
null
)
description
.
add
(
'
$dragDetails
'
);
}
}
class
ScrollUpdateNotification
extends
ScrollNotification2
{
ScrollUpdateNotification
({
@required
Scrollable2State
scrollable
,
this
.
dragDetails
,
this
.
scrollDelta
,
})
:
super
(
scrollable:
scrollable
);
final
DragUpdateDetails
dragDetails
;
/// The distance by which the [Scrollable2] was scrolled, in logical pixels.
final
double
scrollDelta
;
@override
void
debugFillDescription
(
List
<
String
>
description
)
{
super
.
debugFillDescription
(
description
);
description
.
add
(
'scrollDelta:
$scrollDelta
'
);
if
(
dragDetails
!=
null
)
description
.
add
(
'
$dragDetails
'
);
}
}
class
OverscrollNotification
extends
ScrollNotification2
{
OverscrollNotification
({
@required
Scrollable2State
scrollable
,
this
.
dragDetails
,
@required
this
.
overscroll
,
this
.
velocity
:
0.0
,
})
:
super
(
scrollable:
scrollable
)
{
assert
(
overscroll
!=
null
);
assert
(
overscroll
.
isFinite
);
assert
(
overscroll
!=
0.0
);
assert
(
velocity
!=
null
);
}
final
DragUpdateDetails
dragDetails
;
/// The number of logical pixels that the [Scrollable2] avoided scrolling.
///
/// This will be negative for overscroll on the "start" side and positive for
/// overscroll on the "end" side.
final
double
overscroll
;
/// The velocity at which the [ScrollPosition] was changing when this
/// overscroll happened.
///
/// This will typically be 0.0 for touch-driven overscrolls, and positive
/// for overscrolls that happened from a [BallisticScrollActivity] or
/// [DrivenScrollActivity].
final
double
velocity
;
@override
void
debugFillDescription
(
List
<
String
>
description
)
{
super
.
debugFillDescription
(
description
);
description
.
add
(
'overscroll:
${overscroll.toStringAsFixed(1)}
'
);
description
.
add
(
'velocity:
${velocity.toStringAsFixed(1)}
'
);
if
(
dragDetails
!=
null
)
description
.
add
(
'
$dragDetails
'
);
}
}
class
ScrollEndNotification
extends
ScrollNotification2
{
ScrollEndNotification
({
@required
Scrollable2State
scrollable
,
this
.
dragDetails
,
})
:
super
(
scrollable:
scrollable
);
final
DragEndDetails
dragDetails
;
@override
void
debugFillDescription
(
List
<
String
>
description
)
{
super
.
debugFillDescription
(
description
);
if
(
dragDetails
!=
null
)
description
.
add
(
'
$dragDetails
'
);
}
}
class
UserScrollNotification
extends
ScrollNotification2
{
UserScrollNotification
({
@required
Scrollable2State
scrollable
,
this
.
direction
,
})
:
super
(
scrollable:
scrollable
);
final
ScrollDirection
direction
;
@override
void
debugFillDescription
(
List
<
String
>
description
)
{
super
.
debugFillDescription
(
description
);
description
.
add
(
'direction:
$direction
'
);
}
}
packages/flutter/lib/src/widgets/scroll_simulation.dart
View file @
63160b3d
...
@@ -7,17 +7,120 @@ import 'dart:math' as math;
...
@@ -7,17 +7,120 @@ import 'dart:math' as math;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/physics.dart'
;
import
'package:flutter/physics.dart'
;
final
SpringDescription
_kScrollSpring
=
new
SpringDescription
.
withDampingRatio
(
mass:
0.5
,
springConstant:
100.0
,
ratio:
1.1
);
/// An implementation of scroll physics that matches iOS.
final
double
_kDrag
=
0.025
;
///
/// See also:
///
/// * [ClampingScrollSimulation], which implements Android scroll physics.
class
BouncingScrollSimulation
extends
SimulationGroup
{
/// Creates a simulation group for scrolling on iOS, with the given
/// parameters.
///
/// The position and velocity arguments must use the same units as will be
/// expected from the [x] and [dx] methods respectively (typically logical
/// pixels and logical pixels per second respectively).
///
/// The leading and trailing extents must use the unit of length, the same
/// unit as used for the position argument and as expected from the [x]
/// method (typically logical pixels).
///
/// The units used with the provided [SpringDescription] must similarly be
/// consistent with the other arguments. A default set of constants is used
/// for the `spring` description if it is omitted; these defaults assume
/// that the unit of length is the logical pixel.
BouncingScrollSimulation
({
@required
double
position
,
@required
double
velocity
,
@required
double
leadingExtent
,
@required
double
trailingExtent
,
SpringDescription
spring
,
})
:
_leadingExtent
=
leadingExtent
,
_trailingExtent
=
trailingExtent
,
_spring
=
spring
??
_defaultScrollSpring
{
assert
(
position
!=
null
);
assert
(
velocity
!=
null
);
assert
(
_leadingExtent
!=
null
);
assert
(
_trailingExtent
!=
null
);
assert
(
_leadingExtent
<=
_trailingExtent
);
assert
(
_spring
!=
null
);
_chooseSimulation
(
position
,
velocity
,
0.0
);
}
// This class is based on Scroller.java from
final
double
_leadingExtent
;
// https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/widget
final
double
_trailingExtent
;
// The "See" comments refer to Scroller methods and values. Some simplifications
final
SpringDescription
_spring
;
// have been made.
class
_MountainViewSimulation
extends
Simulation
{
static
final
SpringDescription
_defaultScrollSpring
=
new
SpringDescription
.
withDampingRatio
(
_MountainViewSimulation
({
mass:
0.5
,
this
.
position
,
springConstant:
100.0
,
this
.
velocity
,
ratio:
1.1
,
);
bool
_isSpringing
=
false
;
Simulation
_currentSimulation
;
double
_offset
=
0.0
;
// This simulation can only step forward.
@override
bool
step
(
double
time
)
=>
_chooseSimulation
(
_currentSimulation
.
x
(
time
-
_offset
),
_currentSimulation
.
dx
(
time
-
_offset
),
time
,
);
@override
Simulation
get
currentSimulation
=>
_currentSimulation
;
@override
double
get
currentIntervalOffset
=>
_offset
;
bool
_chooseSimulation
(
double
position
,
double
velocity
,
double
intervalOffset
)
{
if
(!
_isSpringing
)
{
if
(
position
>
_trailingExtent
)
{
_isSpringing
=
true
;
_offset
=
intervalOffset
;
_currentSimulation
=
new
ScrollSpringSimulation
(
_spring
,
position
,
_trailingExtent
,
velocity
);
return
true
;
}
else
if
(
position
<
_leadingExtent
)
{
_isSpringing
=
true
;
_offset
=
intervalOffset
;
_currentSimulation
=
new
ScrollSpringSimulation
(
_spring
,
position
,
_leadingExtent
,
velocity
);
return
true
;
}
else
if
(
_currentSimulation
==
null
)
{
_currentSimulation
=
new
FrictionSimulation
(
0.135
,
position
,
velocity
*
0.91
);
return
true
;
}
}
return
false
;
}
@override
String
toString
()
{
return
'
$runtimeType
(leadingExtent:
$_leadingExtent
, trailingExtent:
$_trailingExtent
)'
;
}
}
/// An implementation of scroll physics that matches Android.
///
/// See also:
///
/// * [BouncingScrollSimulation], which implements iOS scroll physics.
//
// This class is based on Scroller.java from Android:
// https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/widget
//
// The "See..." comments below refer to Scroller methods and values. Some
// simplifications have been made.
class
ClampingScrollSimulation
extends
Simulation
{
/// Creates a scroll physics simulation that matches Android scrolling.
//
// TODO(ianh): The incoming `velocity` is used to determine the starting speed
// and duration, but does not represent the exact velocity of the simulation
// at t=0 as it should. This causes crazy scrolling irregularities when the
// scroll dimensions change during a fling.
ClampingScrollSimulation
({
@required
this
.
position
,
@required
this
.
velocity
,
this
.
friction
:
0.015
,
this
.
friction
:
0.015
,
})
{
})
{
_scaledFriction
=
friction
*
_decelerationForFriction
(
0.84
);
// See mPhysicalCoeff
_scaledFriction
=
friction
*
_decelerationForFriction
(
0.84
);
// See mPhysicalCoeff
...
@@ -33,7 +136,7 @@ class _MountainViewSimulation extends Simulation {
...
@@ -33,7 +136,7 @@ class _MountainViewSimulation extends Simulation {
double
_duration
;
double
_duration
;
double
_distance
;
double
_distance
;
// See DECELERATION_RATE
// See DECELERATION_RATE
.
static
final
double
_decelerationRate
=
math
.
log
(
0.78
)
/
math
.
log
(
0.9
);
static
final
double
_decelerationRate
=
math
.
log
(
0.78
)
/
math
.
log
(
0.9
);
// See computeDeceleration().
// See computeDeceleration().
...
@@ -41,24 +144,26 @@ class _MountainViewSimulation extends Simulation {
...
@@ -41,24 +144,26 @@ class _MountainViewSimulation extends Simulation {
return
friction
*
61774.04968
;
return
friction
*
61774.04968
;
}
}
// See getSplineDeceleration()
// See getSplineDeceleration()
.
double
_flingDeceleration
(
double
velocity
)
{
double
_flingDeceleration
(
double
velocity
)
{
return
math
.
log
(
0.35
*
velocity
.
abs
()
/
_scaledFriction
);
return
math
.
log
(
0.35
*
velocity
.
abs
()
/
_scaledFriction
);
}
}
// See getSplineFlingDuration(). Returns a value in seconds.
// See getSplineFlingDuration(). Returns a value in seconds.
double
_flingDuration
(
double
velocity
)
{
double
_flingDuration
(
double
velocity
)
{
return
math
.
exp
(
_flingDeceleration
(
velocity
)
/
(
_decelerationRate
-
1.0
));
return
math
.
exp
(
_flingDeceleration
(
velocity
)
/
(
_decelerationRate
-
1.0
));
}
}
// See getSplineFlingDistance()
// See getSplineFlingDistance()
.
double
_flingDistance
(
double
velocity
)
{
double
_flingDistance
(
double
velocity
)
{
final
double
rate
=
_decelerationRate
/
(
_decelerationRate
-
1.0
)
*
_flingDeceleration
(
velocity
);
final
double
rate
=
_decelerationRate
/
(
_decelerationRate
-
1.0
)
*
_flingDeceleration
(
velocity
);
return
_scaledFriction
*
math
.
exp
(
rate
);
return
_scaledFriction
*
math
.
exp
(
rate
);
}
}
// Based on a cubic curve fit to the computeScrollOffset() values produced
// Based on a cubic curve fit to the Scroller.computeScrollOffset() values
// for an initial velocity of 4000. The value of scroller.getDuration()
// produced for an initial velocity of 4000. The value of Scroller.getDuration()
// and scroller.getFinalY() were 686ms and 961 pixels respectively.
// and Scroller.getFinalY() were 686ms and 961 pixels respectively.
//
// Algebra courtesy of Wolfram Alpha.
// Algebra courtesy of Wolfram Alpha.
//
//
// f(x) = scrollOffset, x is time in millseconds
// f(x) = scrollOffset, x is time in millseconds
...
@@ -74,7 +179,7 @@ class _MountainViewSimulation extends Simulation {
...
@@ -74,7 +179,7 @@ class _MountainViewSimulation extends Simulation {
return
(
1.2
*
t
*
t
*
t
)
-
(
3.27
*
t
*
t
)
+
(
3.065
*
t
);
return
(
1.2
*
t
*
t
*
t
)
-
(
3.27
*
t
*
t
)
+
(
3.065
*
t
);
}
}
// The deriv
iate of the _fling
Penetration() function.
// The deriv
ative of the _flingDistance
Penetration() function.
double
_flingVelocityPenetration
(
double
t
)
{
double
_flingVelocityPenetration
(
double
t
)
{
return
(
3.63693
*
t
*
t
)
-
(
6.5424
*
t
)
+
3.06542
;
return
(
3.63693
*
t
*
t
)
-
(
6.5424
*
t
)
+
3.06542
;
}
}
...
@@ -88,7 +193,7 @@ class _MountainViewSimulation extends Simulation {
...
@@ -88,7 +193,7 @@ class _MountainViewSimulation extends Simulation {
@override
@override
double
dx
(
double
time
)
{
double
dx
(
double
time
)
{
final
double
t
=
(
time
/
_duration
).
clamp
(
0.0
,
1.0
);
final
double
t
=
(
time
/
_duration
).
clamp
(
0.0
,
1.0
);
return
velocity
*
_flingVelocityPenetration
(
t
)
;
return
_distance
*
_flingVelocityPenetration
(
t
)
*
velocity
.
sign
;
}
}
@override
@override
...
@@ -97,12 +202,29 @@ class _MountainViewSimulation extends Simulation {
...
@@ -97,12 +202,29 @@ class _MountainViewSimulation extends Simulation {
}
}
}
}
// DELETE EVERYTHING BELOW THIS LINE WHEN REMOVING LEGACY SCROLLING CODE
final
SpringDescription
_kScrollSpring
=
new
SpringDescription
.
withDampingRatio
(
mass:
0.5
,
springConstant:
100.0
,
ratio:
1.1
);
final
double
_kDrag
=
0.025
;
class
_CupertinoSimulation
extends
FrictionSimulation
{
class
_CupertinoSimulation
extends
FrictionSimulation
{
static
const
double
drag
=
0.135
;
static
const
double
drag
=
0.135
;
_CupertinoSimulation
({
double
position
,
double
velocity
})
_CupertinoSimulation
({
double
position
,
double
velocity
})
:
super
(
drag
,
position
,
velocity
*
0.91
);
:
super
(
drag
,
position
,
velocity
*
0.91
);
}
}
class
_MountainViewSimulation
extends
ClampingScrollSimulation
{
_MountainViewSimulation
({
double
position
,
double
velocity
,
double
friction:
0.015
,
})
:
super
(
position:
position
,
velocity:
velocity
,
friction:
friction
,
);
}
/// Composite simulation for scrollable interfaces.
/// Composite simulation for scrollable interfaces.
///
///
/// Simulates kinetic scrolling behavior between a leading and trailing
/// Simulates kinetic scrolling behavior between a leading and trailing
...
@@ -123,10 +245,10 @@ class ScrollSimulation extends SimulationGroup {
...
@@ -123,10 +245,10 @@ class ScrollSimulation extends SimulationGroup {
///
///
/// The final argument is the coefficient of friction, which is unitless.
/// The final argument is the coefficient of friction, which is unitless.
ScrollSimulation
({
ScrollSimulation
({
double
position
,
@required
double
position
,
double
velocity
,
@required
double
velocity
,
double
leadingExtent
,
@required
double
leadingExtent
,
double
trailingExtent
,
@required
double
trailingExtent
,
SpringDescription
spring
,
SpringDescription
spring
,
double
drag
,
double
drag
,
TargetPlatform
platform
,
TargetPlatform
platform
,
...
@@ -135,6 +257,8 @@ class ScrollSimulation extends SimulationGroup {
...
@@ -135,6 +257,8 @@ class ScrollSimulation extends SimulationGroup {
_spring
=
spring
??
_kScrollSpring
,
_spring
=
spring
??
_kScrollSpring
,
_drag
=
drag
??
_kDrag
,
_drag
=
drag
??
_kDrag
,
_platform
=
platform
{
_platform
=
platform
{
assert
(
position
!=
null
);
assert
(
velocity
!=
null
);
assert
(
_leadingExtent
!=
null
);
assert
(
_leadingExtent
!=
null
);
assert
(
_trailingExtent
!=
null
);
assert
(
_trailingExtent
!=
null
);
assert
(
_spring
!=
null
);
assert
(
_spring
!=
null
);
...
...
packages/flutter/lib/src/widgets/scrollable.dart
View file @
63160b3d
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/widgets/viewport.dart
0 → 100644
View file @
63160b3d
// 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
'package:flutter/foundation.dart'
;
import
'package:flutter/rendering.dart'
;
import
'framework.dart'
;
export
'package:flutter/rendering.dart'
show
AxisDirection
,
GrowthDirection
;
class
Viewport2
extends
MultiChildRenderObjectWidget
{
Viewport2
({
Key
key
,
this
.
axisDirection
:
AxisDirection
.
down
,
this
.
anchor
:
0.0
,
this
.
offset
,
this
.
center
,
List
<
Widget
>
children:
const
<
Widget
>[],
})
:
super
(
key:
key
,
children:
children
)
{
assert
(
center
==
null
||
children
.
where
((
Widget
child
)
=>
child
.
key
==
center
).
length
==
1
);
}
final
AxisDirection
axisDirection
;
final
double
anchor
;
final
ViewportOffset
offset
;
final
Key
center
;
@override
RenderViewport2
createRenderObject
(
BuildContext
context
)
{
return
new
RenderViewport2
(
axisDirection:
axisDirection
,
anchor:
anchor
,
offset:
offset
,
);
}
@override
void
updateRenderObject
(
BuildContext
context
,
RenderViewport2
renderObject
)
{
renderObject
.
axisDirection
=
axisDirection
;
renderObject
.
anchor
=
anchor
;
renderObject
.
offset
=
offset
;
}
@override
Viewport2Element
createElement
()
=>
new
Viewport2Element
(
this
);
@override
void
debugFillDescription
(
List
<
String
>
description
)
{
super
.
debugFillDescription
(
description
);
description
.
add
(
'
$axisDirection
'
);
description
.
add
(
'anchor:
$anchor
'
);
description
.
add
(
'offset:
$offset
'
);
if
(
center
!=
null
)
{
description
.
add
(
'center:
$center
'
);
}
else
if
(
children
.
isNotEmpty
&&
children
.
first
.
key
!=
null
)
{
description
.
add
(
'center:
${children.first.key}
(implicit)'
);
}
}
}
class
Viewport2Element
extends
MultiChildRenderObjectElement
{
/// Creates an element that uses the given widget as its configuration.
Viewport2Element
(
Viewport2
widget
)
:
super
(
widget
);
@override
Viewport2
get
widget
=>
super
.
widget
;
@override
RenderViewport2
get
renderObject
=>
super
.
renderObject
;
@override
void
mount
(
Element
parent
,
dynamic
newSlot
)
{
super
.
mount
(
parent
,
newSlot
);
updateCenter
();
}
@override
void
update
(
MultiChildRenderObjectWidget
newWidget
)
{
super
.
update
(
newWidget
);
updateCenter
();
}
@protected
void
updateCenter
()
{
// TODO(ianh): cache the keys to make this faster
if
(
widget
.
center
!=
null
)
{
renderObject
.
center
=
children
.
singleWhere
(
(
Element
element
)
=>
element
.
widget
.
key
==
widget
.
center
).
renderObject
;
}
else
if
(
children
.
isNotEmpty
)
{
renderObject
.
center
=
children
.
first
.
renderObject
;
}
else
{
renderObject
.
center
=
null
;
}
}
}
packages/flutter/lib/widgets.dart
View file @
63160b3d
...
@@ -36,6 +36,7 @@ export 'src/widgets/navigator.dart';
...
@@ -36,6 +36,7 @@ export 'src/widgets/navigator.dart';
export
'src/widgets/notification_listener.dart'
;
export
'src/widgets/notification_listener.dart'
;
export
'src/widgets/orientation_builder.dart'
;
export
'src/widgets/orientation_builder.dart'
;
export
'src/widgets/overlay.dart'
;
export
'src/widgets/overlay.dart'
;
export
'src/widgets/overscroll_indicator.dart'
;
export
'src/widgets/page_storage.dart'
;
export
'src/widgets/page_storage.dart'
;
export
'src/widgets/pageable_list.dart'
;
export
'src/widgets/pageable_list.dart'
;
export
'src/widgets/pages.dart'
;
export
'src/widgets/pages.dart'
;
...
@@ -43,8 +44,10 @@ export 'src/widgets/performance_overlay.dart';
...
@@ -43,8 +44,10 @@ export 'src/widgets/performance_overlay.dart';
export
'src/widgets/placeholder.dart'
;
export
'src/widgets/placeholder.dart'
;
export
'src/widgets/raw_keyboard_listener.dart'
;
export
'src/widgets/raw_keyboard_listener.dart'
;
export
'src/widgets/routes.dart'
;
export
'src/widgets/routes.dart'
;
export
'src/widgets/scroll_absolute.dart'
;
export
'src/widgets/scroll_behavior.dart'
;
export
'src/widgets/scroll_behavior.dart'
;
export
'src/widgets/scroll_configuration.dart'
;
export
'src/widgets/scroll_configuration.dart'
;
export
'src/widgets/scroll_notification.dart'
;
export
'src/widgets/scroll_simulation.dart'
;
export
'src/widgets/scroll_simulation.dart'
;
export
'src/widgets/scrollable.dart'
;
export
'src/widgets/scrollable.dart'
;
export
'src/widgets/scrollable_grid.dart'
;
export
'src/widgets/scrollable_grid.dart'
;
...
@@ -59,6 +62,7 @@ export 'src/widgets/ticker_provider.dart';
...
@@ -59,6 +62,7 @@ export 'src/widgets/ticker_provider.dart';
export
'src/widgets/title.dart'
;
export
'src/widgets/title.dart'
;
export
'src/widgets/transitions.dart'
;
export
'src/widgets/transitions.dart'
;
export
'src/widgets/unique_widget.dart'
;
export
'src/widgets/unique_widget.dart'
;
export
'src/widgets/viewport.dart'
;
export
'src/widgets/virtual_viewport.dart'
;
export
'src/widgets/virtual_viewport.dart'
;
export
'package:vector_math/vector_math_64.dart'
show
Matrix4
;
export
'package:vector_math/vector_math_64.dart'
show
Matrix4
;
packages/flutter/test/rendering/mock_canvas.dart
View file @
63160b3d
...
@@ -265,14 +265,14 @@ class _TestRecordingCanvas implements Canvas {
...
@@ -265,14 +265,14 @@ class _TestRecordingCanvas implements Canvas {
@override
@override
void
save
()
{
void
save
()
{
_saveCount
+=
1
;
_saveCount
+=
1
;
super
.
save
();
// ends up in noSuchMethod
_invocations
.
add
(
new
_MethodCall
(
#save
));
}
}
@override
@override
void
restore
()
{
void
restore
()
{
_saveCount
-=
1
;
_saveCount
-=
1
;
assert
(
_saveCount
>=
0
);
assert
(
_saveCount
>=
0
);
super
.
restore
();
// ends up in noSuchMethod
_invocations
.
add
(
new
_MethodCall
(
#restore
));
}
}
@override
@override
...
@@ -281,6 +281,25 @@ class _TestRecordingCanvas implements Canvas {
...
@@ -281,6 +281,25 @@ class _TestRecordingCanvas implements Canvas {
}
}
}
}
class
_MethodCall
implements
Invocation
{
_MethodCall
(
this
.
_name
);
final
Symbol
_name
;
@override
bool
get
isAccessor
=>
false
;
@override
bool
get
isGetter
=>
false
;
@override
bool
get
isMethod
=>
true
;
@override
bool
get
isSetter
=>
false
;
@override
Symbol
get
memberName
=>
_name
;
@override
Map
<
Symbol
,
dynamic
>
get
namedArguments
=>
<
Symbol
,
dynamic
>{};
@override
List
<
dynamic
>
get
positionalArguments
=>
<
dynamic
>[];
}
class
_TestRecordingPaintingContext
implements
PaintingContext
{
class
_TestRecordingPaintingContext
implements
PaintingContext
{
_TestRecordingPaintingContext
(
this
.
canvas
);
_TestRecordingPaintingContext
(
this
.
canvas
);
...
...
packages/flutter/test/rendering/slivers_test.dart
View file @
63160b3d
...
@@ -8,6 +8,13 @@ import 'package:test/test.dart';
...
@@ -8,6 +8,13 @@ import 'package:test/test.dart';
import
'rendering_tester.dart'
;
import
'rendering_tester.dart'
;
void
main
(
)
{
void
main
(
)
{
test
(
'RenderViewport2 basic test - no children'
,
()
{
RenderViewport2
root
=
new
RenderViewport2
();
layout
(
root
);
root
.
offset
=
new
ViewportOffset
.
fixed
(
900.0
);
pumpFrame
();
});
test
(
'RenderViewport2 basic test - down'
,
()
{
test
(
'RenderViewport2 basic test - down'
,
()
{
RenderBox
a
,
b
,
c
,
d
,
e
;
RenderBox
a
,
b
,
c
,
d
,
e
;
RenderViewport2
root
=
new
RenderViewport2
(
RenderViewport2
root
=
new
RenderViewport2
(
...
@@ -199,8 +206,6 @@ void main() {
...
@@ -199,8 +206,6 @@ void main() {
expect
(
e
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(-
300.0
,
0.0
));
expect
(
e
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(-
300.0
,
0.0
));
});
});
// TODO(ianh): test positioning when the children are too big to fit in the main axis
// TODO(ianh): test shrinkWrap
// TODO(ianh): test anchor
// TODO(ianh): test anchor
// TODO(ianh): test offset
// TODO(ianh): test offset
// TODO(ianh): test center
// TODO(ianh): test center
...
...
packages/flutter/test/widgets/framework_test.dart
View file @
63160b3d
...
@@ -98,6 +98,7 @@ void main() {
...
@@ -98,6 +98,7 @@ void main() {
expect
(
didReceiveCallback
,
isTrue
);
expect
(
didReceiveCallback
,
isTrue
);
});
});
testWidgets
(
'Defunct setState throws exception'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'Defunct setState throws exception'
,
(
WidgetTester
tester
)
async
{
StateSetter
setState
;
StateSetter
setState
;
...
@@ -143,4 +144,23 @@ void main() {
...
@@ -143,4 +144,23 @@ void main() {
expect
(
log
[
0
],
matches
(
'Deactivated'
));
expect
(
log
[
0
],
matches
(
'Deactivated'
));
expect
(
log
[
1
],
matches
(
'Discarding .+ from inactive elements list.'
));
expect
(
log
[
1
],
matches
(
'Discarding .+ from inactive elements list.'
));
});
});
testWidgets
(
'MultiChildRenderObjectElement.children'
,
(
WidgetTester
tester
)
async
{
GlobalKey
key0
,
key1
,
key2
;
await
tester
.
pumpWidget
(
new
Column
(
key:
key0
=
new
GlobalKey
(),
children:
<
Widget
>[
new
Container
(),
new
Container
(
key:
key1
=
new
GlobalKey
()),
new
Container
(
child:
new
Container
()),
new
Container
(
key:
key2
=
new
GlobalKey
()),
new
Container
(),
],
));
MultiChildRenderObjectElement
element
=
key0
.
currentContext
;
expect
(
element
.
children
.
map
((
Element
element
)
=>
element
.
widget
.
key
),
// ignore: INVALID_USE_OF_PROTECTED_MEMBER
<
Key
>[
null
,
key1
,
null
,
key2
,
null
],
);
});
}
}
packages/flutter/test/widgets/overscroll_indicator_test.dart
0 → 100644
View file @
63160b3d
// Copyright 2017 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:math'
as
math
;
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter/widgets.dart'
;
import
'package:flutter/rendering.dart'
;
import
'../rendering/mock_canvas.dart'
;
final
Matcher
doesNotOverscroll
=
isNot
(
paints
..
circle
());
Future
<
Null
>
slowDrag
(
WidgetTester
tester
,
Point
start
,
Offset
offset
)
async
{
TestGesture
gesture
=
await
tester
.
startGesture
(
start
);
for
(
int
index
=
0
;
index
<
10
;
index
+=
1
)
{
await
gesture
.
moveBy
(
offset
);
await
tester
.
pump
(
const
Duration
(
milliseconds:
20
));
}
await
gesture
.
up
();
}
void
main
(
)
{
testWidgets
(
'Overscroll indicator color'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
new
Scrollable2
(
children:
<
Widget
>[
new
SliverToBoxAdapter
(
child:
new
SizedBox
(
height:
2000.0
)),
],
),
);
RenderObject
painter
=
tester
.
renderObject
(
find
.
byType
(
CustomPaint
));
expect
(
painter
,
doesNotOverscroll
);
// the scroll gesture from tester.scroll happens in zero time, so nothing should appear:
await
tester
.
scroll
(
find
.
byType
(
Scrollable2
),
const
Offset
(
0.0
,
100.0
));
expect
(
painter
,
doesNotOverscroll
);
await
tester
.
pump
();
// allow the ticker to register itself
expect
(
painter
,
doesNotOverscroll
);
await
tester
.
pump
(
const
Duration
(
milliseconds:
100
));
// animate
expect
(
painter
,
doesNotOverscroll
);
TestGesture
gesture
=
await
tester
.
startGesture
(
const
Point
(
200.0
,
200.0
));
await
tester
.
pump
(
const
Duration
(
milliseconds:
100
));
// animate
expect
(
painter
,
doesNotOverscroll
);
await
gesture
.
up
();
expect
(
painter
,
doesNotOverscroll
);
await
slowDrag
(
tester
,
const
Point
(
200.0
,
200.0
),
const
Offset
(
0.0
,
5.0
));
expect
(
painter
,
paints
..
circle
(
color:
const
Color
(
0x0DFFFFFF
)));
await
tester
.
pumpUntilNoTransientCallbacks
(
const
Duration
(
seconds:
1
));
expect
(
painter
,
doesNotOverscroll
);
});
testWidgets
(
'Overscroll indicator changes side when you drag on the other side'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
new
Scrollable2
(
children:
<
Widget
>[
new
SliverToBoxAdapter
(
child:
new
SizedBox
(
height:
2000.0
)),
],
),
);
RenderObject
painter
=
tester
.
renderObject
(
find
.
byType
(
CustomPaint
));
await
slowDrag
(
tester
,
const
Point
(
400.0
,
200.0
),
const
Offset
(
0.0
,
10.0
));
expect
(
painter
,
paints
..
circle
(
x:
400.0
));
await
slowDrag
(
tester
,
const
Point
(
100.0
,
200.0
),
const
Offset
(
0.0
,
10.0
));
expect
(
painter
,
paints
..
something
((
Symbol
method
,
List
<
dynamic
>
arguments
)
{
if
(
method
!=
#drawCircle
)
return
false
;
final
Point
center
=
arguments
[
0
];
if
(
center
.
x
<
400.0
)
return
true
;
throw
'Dragging on left hand side did not overscroll on left hand side.'
;
}));
await
slowDrag
(
tester
,
const
Point
(
700.0
,
200.0
),
const
Offset
(
0.0
,
10.0
));
expect
(
painter
,
paints
..
something
((
Symbol
method
,
List
<
dynamic
>
arguments
)
{
if
(
method
!=
#drawCircle
)
return
false
;
final
Point
center
=
arguments
[
0
];
if
(
center
.
x
>
400.0
)
return
true
;
throw
'Dragging on right hand side did not overscroll on right hand side.'
;
}));
await
tester
.
pumpUntilNoTransientCallbacks
(
const
Duration
(
seconds:
1
));
expect
(
painter
,
doesNotOverscroll
);
});
testWidgets
(
'Overscroll indicator changes side when you shift sides'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
new
Scrollable2
(
children:
<
Widget
>[
new
SliverToBoxAdapter
(
child:
new
SizedBox
(
height:
2000.0
)),
],
),
);
RenderObject
painter
=
tester
.
renderObject
(
find
.
byType
(
CustomPaint
));
TestGesture
gesture
=
await
tester
.
startGesture
(
const
Point
(
300.0
,
200.0
));
await
gesture
.
moveBy
(
const
Offset
(
0.0
,
10.0
));
await
tester
.
pump
(
const
Duration
(
milliseconds:
20
));
double
oldX
=
0.0
;
for
(
int
index
=
0
;
index
<
10
;
index
+=
1
)
{
await
gesture
.
moveBy
(
const
Offset
(
50.0
,
50.0
));
await
tester
.
pump
(
const
Duration
(
milliseconds:
20
));
expect
(
painter
,
paints
..
something
((
Symbol
method
,
List
<
dynamic
>
arguments
)
{
if
(
method
!=
#drawCircle
)
return
false
;
final
Point
center
=
arguments
[
0
];
if
(
center
.
x
<=
oldX
)
throw
'Sliding to the right did not make the center of the radius slide to the right.'
;
oldX
=
center
.
x
;
return
true
;
}));
}
await
gesture
.
up
();
await
tester
.
pumpUntilNoTransientCallbacks
(
const
Duration
(
seconds:
1
));
expect
(
painter
,
doesNotOverscroll
);
});
group
(
'Flipping direction of scrollable doesn
\'
t change overscroll behavior'
,
()
{
testWidgets
(
'down'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
new
Scrollable2
(
axisDirection:
AxisDirection
.
down
,
children:
<
Widget
>[
new
SliverToBoxAdapter
(
child:
new
SizedBox
(
height:
20.0
)),
],
),
);
RenderObject
painter
=
tester
.
renderObject
(
find
.
byType
(
CustomPaint
));
await
slowDrag
(
tester
,
const
Point
(
200.0
,
200.0
),
const
Offset
(
0.0
,
5.0
));
expect
(
painter
,
paints
..
save
()..
circle
()..
restore
()..
save
()..
scale
(
y:
-
1.0
)..
restore
()..
restore
());
await
tester
.
pumpUntilNoTransientCallbacks
(
const
Duration
(
seconds:
1
));
expect
(
painter
,
doesNotOverscroll
);
});
testWidgets
(
'up'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
new
Scrollable2
(
axisDirection:
AxisDirection
.
up
,
children:
<
Widget
>[
new
SliverToBoxAdapter
(
child:
new
SizedBox
(
height:
20.0
)),
],
),
);
RenderObject
painter
=
tester
.
renderObject
(
find
.
byType
(
CustomPaint
));
await
slowDrag
(
tester
,
const
Point
(
200.0
,
200.0
),
const
Offset
(
0.0
,
5.0
));
expect
(
painter
,
paints
..
save
()..
scale
(
y:
-
1.0
)..
restore
()..
save
()..
circle
()..
restore
()..
restore
());
await
tester
.
pumpUntilNoTransientCallbacks
(
const
Duration
(
seconds:
1
));
expect
(
painter
,
doesNotOverscroll
);
});
});
testWidgets
(
'Overscroll in both directions'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
new
Scrollable2
(
axisDirection:
AxisDirection
.
down
,
children:
<
Widget
>[
new
SliverToBoxAdapter
(
child:
new
SizedBox
(
height:
20.0
)),
],
),
);
RenderObject
painter
=
tester
.
renderObject
(
find
.
byType
(
CustomPaint
));
await
slowDrag
(
tester
,
const
Point
(
200.0
,
200.0
),
const
Offset
(
0.0
,
5.0
));
expect
(
painter
,
paints
..
circle
());
expect
(
painter
,
isNot
(
paints
..
circle
()..
circle
()));
await
slowDrag
(
tester
,
const
Point
(
200.0
,
200.0
),
const
Offset
(
0.0
,
-
5.0
));
expect
(
painter
,
paints
..
circle
()..
circle
());
await
tester
.
pumpUntilNoTransientCallbacks
(
const
Duration
(
seconds:
1
));
expect
(
painter
,
doesNotOverscroll
);
});
testWidgets
(
'Overscroll horizontally'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
new
Scrollable2
(
axisDirection:
AxisDirection
.
right
,
children:
<
Widget
>[
new
SliverToBoxAdapter
(
child:
new
SizedBox
(
height:
20.0
)),
],
),
);
RenderObject
painter
=
tester
.
renderObject
(
find
.
byType
(
CustomPaint
));
await
slowDrag
(
tester
,
const
Point
(
200.0
,
200.0
),
const
Offset
(
5.0
,
0.0
));
expect
(
painter
,
paints
..
rotate
(
angle:
-
math
.
PI
/
2.0
)..
circle
()..
scale
(
y:
-
1.0
));
expect
(
painter
,
isNot
(
paints
..
circle
()..
circle
()));
await
slowDrag
(
tester
,
const
Point
(
200.0
,
200.0
),
const
Offset
(-
5.0
,
0.0
));
expect
(
painter
,
paints
..
rotate
(
angle:
-
math
.
PI
/
2.0
)..
circle
()
..
rotate
(
angle:
-
math
.
PI
/
2.0
)..
scale
(
y:
-
1.0
)..
circle
());
await
tester
.
pumpUntilNoTransientCallbacks
(
const
Duration
(
seconds:
1
));
expect
(
painter
,
doesNotOverscroll
);
});
testWidgets
(
'Changing settings'
,
(
WidgetTester
tester
)
async
{
RenderObject
painter
;
await
tester
.
pumpWidget
(
new
Scrollable2
(
axisDirection:
AxisDirection
.
left
,
scrollBehavior:
new
TestScrollBehavior1
(),
children:
<
Widget
>[
new
SliverToBoxAdapter
(
child:
new
SizedBox
(
height:
20.0
)),
],
),
);
painter
=
tester
.
renderObject
(
find
.
byType
(
CustomPaint
));
await
slowDrag
(
tester
,
const
Point
(
200.0
,
200.0
),
const
Offset
(
5.0
,
0.0
));
expect
(
painter
,
paints
..
scale
(
y:
-
1.0
)..
rotate
(
angle:
-
math
.
PI
/
2.0
)..
circle
(
color:
const
Color
(
0x0A00FF00
)));
expect
(
painter
,
isNot
(
paints
..
circle
()..
circle
()));
await
tester
.
pumpUntilNoTransientCallbacks
(
const
Duration
(
seconds:
1
));
await
tester
.
pumpWidget
(
new
Scrollable2
(
axisDirection:
AxisDirection
.
right
,
scrollBehavior:
new
TestScrollBehavior2
(),
children:
<
Widget
>[
new
SliverToBoxAdapter
(
child:
new
SizedBox
(
height:
20.0
)),
],
),
);
painter
=
tester
.
renderObject
(
find
.
byType
(
CustomPaint
));
await
slowDrag
(
tester
,
const
Point
(
200.0
,
200.0
),
const
Offset
(
5.0
,
0.0
));
expect
(
painter
,
paints
..
rotate
(
angle:
-
math
.
PI
/
2.0
)..
circle
(
color:
const
Color
(
0x0A0000FF
))..
scale
(
y:
-
1.0
));
expect
(
painter
,
isNot
(
paints
..
circle
()..
circle
()));
});
}
class
TestScrollBehavior1
extends
ViewportScrollBehavior
{
@override
Color
getGlowColor
(
BuildContext
context
)
{
return
const
Color
(
0xFF00FF00
);
}
}
class
TestScrollBehavior2
extends
ViewportScrollBehavior
{
@override
Color
getGlowColor
(
BuildContext
context
)
{
return
const
Color
(
0xFF0000FF
);
}
}
packages/flutter/test/widgets/scrollable_custom_scroll_behavior_test.dart
0 → 100644
View file @
63160b3d
// Copyright 2017 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
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/rendering.dart'
;
class
TestScrollPosition
extends
ScrollPosition
{
TestScrollPosition
(
this
.
extentMultiplier
,
Scrollable2State
state
,
Tolerance
scrollTolerances
,
ScrollPosition
oldPosition
,
)
:
_pixels
=
100.0
,
super
(
state
,
scrollTolerances
,
oldPosition
);
final
double
extentMultiplier
;
double
_min
,
_viewport
,
_max
,
_pixels
;
@override
double
get
pixels
=>
_pixels
;
@override
double
setPixels
(
double
value
)
{
double
oldPixels
=
_pixels
;
_pixels
=
value
;
dispatchNotification
(
activity
.
createScrollUpdateNotification
(
state
,
_pixels
-
oldPixels
));
return
0.0
;
}
@override
void
correctBy
(
double
correction
)
{
_pixels
+=
correction
;
}
@override
void
applyViewportDimension
(
double
viewportDimension
)
{
_viewport
=
viewportDimension
;
super
.
applyViewportDimension
(
viewportDimension
);
}
@override
bool
applyContentDimensions
(
double
minScrollExtent
,
double
maxScrollExtent
)
{
_min
=
minScrollExtent
;
_max
=
maxScrollExtent
;
return
super
.
applyContentDimensions
(
minScrollExtent
,
maxScrollExtent
);
}
@override
ScrollableMetrics
getMetrics
()
{
double
insideExtent
=
_viewport
;
double
beforeExtent
=
_pixels
-
_min
;
double
afterExtent
=
_max
-
_pixels
;
if
(
insideExtent
>
0.0
)
{
return
new
ScrollableMetrics
(
extentBefore:
extentMultiplier
*
beforeExtent
/
insideExtent
,
extentInside:
extentMultiplier
,
extentAfter:
extentMultiplier
*
afterExtent
/
insideExtent
,
);
}
else
{
return
new
ScrollableMetrics
(
extentBefore:
0.0
,
extentInside:
0.0
,
extentAfter:
0.0
,
);
}
}
}
class
TestScrollBehavior
extends
ScrollBehavior2
{
TestScrollBehavior
(
this
.
extentMultiplier
);
final
double
extentMultiplier
;
@override
Widget
wrap
(
BuildContext
context
,
Widget
child
,
AxisDirection
axisDirection
)
=>
child
;
@override
ScrollPosition
createScrollPosition
(
BuildContext
context
,
Scrollable2State
state
,
ScrollPosition
oldPosition
)
{
return
new
TestScrollPosition
(
extentMultiplier
,
state
,
ViewportScrollBehavior
.
defaultScrollTolerances
,
oldPosition
);
}
@override
bool
shouldNotify
(
TestScrollBehavior
oldDelegate
)
{
return
extentMultiplier
!=
oldDelegate
.
extentMultiplier
;
}
}
void
main
(
)
{
testWidgets
(
'Changing the scroll behavior dynamically'
,
(
WidgetTester
tester
)
async
{
GlobalKey
<
Scrollable2State
>
key
=
new
GlobalKey
<
Scrollable2State
>();
await
tester
.
pumpWidget
(
new
Scrollable2
(
key:
key
,
scrollBehavior:
new
TestScrollBehavior
(
1.0
),
children:
<
Widget
>[
new
SliverToBoxAdapter
(
child:
new
SizedBox
(
height:
2000.0
)),
],
));
expect
(
key
.
currentState
.
position
.
getMetrics
().
extentInside
,
1.0
);
await
tester
.
pumpWidget
(
new
Scrollable2
(
key:
key
,
scrollBehavior:
new
TestScrollBehavior
(
2.0
),
children:
<
Widget
>[
new
SliverToBoxAdapter
(
child:
new
SizedBox
(
height:
2000.0
)),
],
));
expect
(
key
.
currentState
.
position
.
getMetrics
().
extentInside
,
2.0
);
});
}
\ No newline at end of file
packages/flutter/test/widgets/scrollable_test.dart
0 → 100644
View file @
63160b3d
// Copyright 2017 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
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/rendering.dart'
;
Future
<
Null
>
pumpTest
(
WidgetTester
tester
,
TargetPlatform
platform
)
async
{
await
tester
.
pumpWidget
(
new
MaterialApp
(
theme:
new
ThemeData
(
platform:
platform
,
),
home:
new
Scrollable2
(
children:
<
Widget
>[
new
SliverToBoxAdapter
(
child:
new
SizedBox
(
height:
2000.0
)),
],
),
));
await
tester
.
pump
(
const
Duration
(
seconds:
5
));
// to let the theme animate
return
null
;
}
const
double
dragOffset
=
200.0
;
double
getScrollOffset
(
WidgetTester
tester
)
{
RenderViewport2
viewport
=
tester
.
renderObject
(
find
.
byType
(
Viewport2
));
return
viewport
.
offset
.
pixels
;
}
void
resetScrollOffset
(
WidgetTester
tester
)
{
RenderViewport2
viewport
=
tester
.
renderObject
(
find
.
byType
(
Viewport2
));
AbsoluteScrollPosition
position
=
viewport
.
offset
;
position
.
jumpTo
(
0.0
);
}
void
main
(
)
{
testWidgets
(
'Flings on different platforms'
,
(
WidgetTester
tester
)
async
{
await
pumpTest
(
tester
,
TargetPlatform
.
android
);
await
tester
.
fling
(
find
.
byType
(
Viewport2
),
const
Offset
(
0.0
,
-
dragOffset
),
1000.0
);
expect
(
getScrollOffset
(
tester
),
dragOffset
);
await
tester
.
pump
();
// trigger fling
expect
(
getScrollOffset
(
tester
),
dragOffset
);
await
tester
.
pump
(
const
Duration
(
seconds:
5
));
final
double
result1
=
getScrollOffset
(
tester
);
resetScrollOffset
(
tester
);
await
pumpTest
(
tester
,
TargetPlatform
.
iOS
);
await
tester
.
fling
(
find
.
byType
(
Viewport2
),
const
Offset
(
0.0
,
-
dragOffset
),
1000.0
);
expect
(
getScrollOffset
(
tester
),
dragOffset
);
await
tester
.
pump
();
// trigger fling
expect
(
getScrollOffset
(
tester
),
dragOffset
);
await
tester
.
pump
(
const
Duration
(
seconds:
5
));
final
double
result2
=
getScrollOffset
(
tester
);
expect
(
result1
,
lessThan
(
result2
));
// iOS (result2) is slipperier than Android (result1)
});
testWidgets
(
'Flings on different platforms'
,
(
WidgetTester
tester
)
async
{
await
pumpTest
(
tester
,
TargetPlatform
.
iOS
);
await
tester
.
fling
(
find
.
byType
(
Viewport2
),
const
Offset
(
0.0
,
-
dragOffset
),
1000.0
);
expect
(
getScrollOffset
(
tester
),
dragOffset
);
await
tester
.
pump
();
// trigger fling
expect
(
getScrollOffset
(
tester
),
dragOffset
);
await
tester
.
pump
(
const
Duration
(
seconds:
5
));
final
double
result1
=
getScrollOffset
(
tester
);
resetScrollOffset
(
tester
);
await
pumpTest
(
tester
,
TargetPlatform
.
android
);
await
tester
.
fling
(
find
.
byType
(
Viewport2
),
const
Offset
(
0.0
,
-
dragOffset
),
1000.0
);
expect
(
getScrollOffset
(
tester
),
dragOffset
);
await
tester
.
pump
();
// trigger fling
expect
(
getScrollOffset
(
tester
),
dragOffset
);
await
tester
.
pump
(
const
Duration
(
seconds:
5
));
final
double
result2
=
getScrollOffset
(
tester
);
expect
(
result1
,
greaterThan
(
result2
));
// iOS (result1) is slipperier than Android (result2)
});
}
\ No newline at end of file
packages/flutter/test/widgets/slivers_protocol_test.dart
0 → 100644
View file @
63160b3d
// Copyright 2016 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:math'
as
math
;
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/widgets.dart'
;
void
verifyPaintPosition
(
GlobalKey
key
,
Offset
ideal
)
{
RenderObject
target
=
key
.
currentContext
.
findRenderObject
();
expect
(
target
.
parent
,
new
isInstanceOf
<
RenderViewport2
>());
SliverPhysicalParentData
parentData
=
target
.
parentData
;
Offset
actual
=
parentData
.
paintOffset
;
expect
(
actual
,
ideal
);
}
void
main
(
)
{
testWidgets
(
'Sliver protocol'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
<
Scrollable2State
>
scrollableKey
=
new
GlobalKey
<
Scrollable2State
>();
GlobalKey
key1
,
key2
,
key3
,
key4
,
key5
;
await
tester
.
pumpWidget
(
new
Scrollable2
(
key:
scrollableKey
,
axisDirection:
AxisDirection
.
down
,
children:
<
Widget
>[
new
BigSliver
(
key:
key1
=
new
GlobalKey
()),
new
OverlappingSliver
(
key:
key2
=
new
GlobalKey
()),
new
OverlappingSliver
(
key:
key3
=
new
GlobalKey
()),
new
BigSliver
(
key:
key4
=
new
GlobalKey
()),
new
BigSliver
(
key:
key5
=
new
GlobalKey
()),
],
),
);
AbsoluteScrollPosition
position
=
scrollableKey
.
currentState
.
position
;
final
double
max
=
RenderBigSliver
.
height
*
3.0
+
(
RenderOverlappingSliver
.
totalHeight
)
*
2.0
-
600.0
;
// 600 is the height of the test viewport
assert
(
max
<
10000.0
);
expect
(
max
,
1450.0
);
expect
(
position
.
pixels
,
0.0
);
expect
(
position
.
minScrollExtent
,
0.0
);
expect
(
position
.
maxScrollExtent
,
max
);
position
.
animate
(
to:
10000.0
,
curve:
Curves
.
linear
,
duration:
const
Duration
(
minutes:
1
));
await
tester
.
pumpUntilNoTransientCallbacks
(
const
Duration
(
milliseconds:
10
));
expect
(
position
.
pixels
,
max
);
expect
(
position
.
minScrollExtent
,
0.0
);
expect
(
position
.
maxScrollExtent
,
max
);
verifyPaintPosition
(
key1
,
new
Offset
(
0.0
,
0.0
));
verifyPaintPosition
(
key2
,
new
Offset
(
0.0
,
0.0
));
verifyPaintPosition
(
key3
,
new
Offset
(
0.0
,
0.0
));
verifyPaintPosition
(
key4
,
new
Offset
(
0.0
,
0.0
));
verifyPaintPosition
(
key5
,
new
Offset
(
0.0
,
50.0
));
});
}
class
RenderBigSliver
extends
RenderSliver
{
static
const
double
height
=
550.0
;
double
get
paintExtent
=>
(
height
-
constraints
.
scrollOffset
).
clamp
(
0.0
,
constraints
.
remainingPaintExtent
);
@override
void
performLayout
()
{
geometry
=
new
SliverGeometry
(
scrollExtent:
height
,
paintExtent:
paintExtent
,
maxPaintExtent:
height
,
);
}
}
class
BigSliver
extends
LeafRenderObjectWidget
{
BigSliver
({
Key
key
})
:
super
(
key:
key
);
@override
RenderBigSliver
createRenderObject
(
BuildContext
context
)
{
return
new
RenderBigSliver
();
}
}
class
RenderOverlappingSliver
extends
RenderSliver
{
static
const
double
totalHeight
=
200.0
;
static
const
double
fixedHeight
=
100.0
;
double
get
paintExtent
{
return
math
.
min
(
math
.
max
(
fixedHeight
,
totalHeight
-
constraints
.
scrollOffset
,
),
constraints
.
remainingPaintExtent
,
);
}
double
get
layoutExtent
{
return
(
totalHeight
-
constraints
.
scrollOffset
).
clamp
(
0.0
,
constraints
.
remainingPaintExtent
);
}
@override
void
performLayout
()
{
geometry
=
new
SliverGeometry
(
scrollExtent:
totalHeight
,
paintExtent:
paintExtent
,
layoutExtent:
layoutExtent
,
maxPaintExtent:
totalHeight
,
);
}
}
class
OverlappingSliver
extends
LeafRenderObjectWidget
{
OverlappingSliver
({
Key
key
})
:
super
(
key:
key
);
@override
RenderOverlappingSliver
createRenderObject
(
BuildContext
context
)
{
return
new
RenderOverlappingSliver
();
}
}
packages/flutter/test/widgets/slivers_test.dart
0 → 100644
View file @
63160b3d
// Copyright 2016 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
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter/widgets.dart'
;
import
'package:flutter/rendering.dart'
;
Future
<
Null
>
test
(
WidgetTester
tester
,
double
offset
,
{
double
anchor:
0.0
})
{
return
tester
.
pumpWidget
(
new
Viewport2
(
anchor:
anchor
/
600.0
,
offset:
new
ViewportOffset
.
fixed
(
offset
),
children:
<
Widget
>[
new
SliverToBoxAdapter
(
child:
new
SizedBox
(
height:
400.0
)),
new
SliverToBoxAdapter
(
child:
new
SizedBox
(
height:
400.0
)),
new
SliverToBoxAdapter
(
child:
new
SizedBox
(
height:
400.0
)),
new
SliverToBoxAdapter
(
child:
new
SizedBox
(
height:
400.0
)),
new
SliverToBoxAdapter
(
child:
new
SizedBox
(
height:
400.0
)),
],
));
}
void
verify
(
WidgetTester
tester
,
List
<
Point
>
idealPositions
,
List
<
bool
>
idealVisibles
)
{
List
<
Point
>
actualPositions
=
tester
.
renderObjectList
/*<RenderBox>*/
(
find
.
byType
(
SizedBox
)).
map
/*<Point>*/
(
(
RenderBox
target
)
=>
target
.
localToGlobal
(
const
Point
(
0.0
,
0.0
))
).
toList
();
List
<
bool
>
actualVisibles
=
tester
.
renderObjectList
/*<RenderSliverToBoxAdapter>*/
(
find
.
byType
(
SliverToBoxAdapter
)).
map
/*<bool>*/
(
(
RenderSliverToBoxAdapter
target
)
=>
target
.
geometry
.
visible
).
toList
();
expect
(
actualPositions
,
equals
(
idealPositions
));
expect
(
actualVisibles
,
equals
(
idealVisibles
));
}
void
main
(
)
{
testWidgets
(
'Viewport2 basic test'
,
(
WidgetTester
tester
)
async
{
await
test
(
tester
,
0.0
);
expect
(
tester
.
renderObject
/*<RenderBox>*/
(
find
.
byType
(
Viewport2
)).
size
,
equals
(
const
Size
(
800.0
,
600.0
)));
verify
(
tester
,
<
Point
>[
const
Point
(
0.0
,
0.0
),
const
Point
(
0.0
,
400.0
),
const
Point
(
0.0
,
600.0
),
const
Point
(
0.0
,
600.0
),
const
Point
(
0.0
,
600.0
),
],
<
bool
>[
true
,
true
,
false
,
false
,
false
]);
await
test
(
tester
,
200.0
);
verify
(
tester
,
<
Point
>[
const
Point
(
0.0
,
-
200.0
),
const
Point
(
0.0
,
200.0
),
const
Point
(
0.0
,
600.0
),
const
Point
(
0.0
,
600.0
),
const
Point
(
0.0
,
600.0
),
],
<
bool
>[
true
,
true
,
false
,
false
,
false
]);
await
test
(
tester
,
600.0
);
verify
(
tester
,
<
Point
>[
const
Point
(
0.0
,
-
600.0
),
const
Point
(
0.0
,
-
200.0
),
const
Point
(
0.0
,
200.0
),
const
Point
(
0.0
,
600.0
),
const
Point
(
0.0
,
600.0
),
],
<
bool
>[
false
,
true
,
true
,
false
,
false
]);
await
test
(
tester
,
900.0
);
verify
(
tester
,
<
Point
>[
const
Point
(
0.0
,
-
900.0
),
const
Point
(
0.0
,
-
500.0
),
const
Point
(
0.0
,
-
100.0
),
const
Point
(
0.0
,
300.0
),
const
Point
(
0.0
,
600.0
),
],
<
bool
>[
false
,
false
,
true
,
true
,
false
]);
});
testWidgets
(
'Viewport2 anchor test'
,
(
WidgetTester
tester
)
async
{
await
test
(
tester
,
0.0
,
anchor:
100.0
);
expect
(
tester
.
renderObject
/*<RenderBox>*/
(
find
.
byType
(
Viewport2
)).
size
,
equals
(
const
Size
(
800.0
,
600.0
)));
verify
(
tester
,
<
Point
>[
const
Point
(
0.0
,
100.0
),
const
Point
(
0.0
,
500.0
),
const
Point
(
0.0
,
600.0
),
const
Point
(
0.0
,
600.0
),
const
Point
(
0.0
,
600.0
),
],
<
bool
>[
true
,
true
,
false
,
false
,
false
]);
await
test
(
tester
,
200.0
,
anchor:
100.0
);
verify
(
tester
,
<
Point
>[
const
Point
(
0.0
,
-
100.0
),
const
Point
(
0.0
,
300.0
),
const
Point
(
0.0
,
600.0
),
const
Point
(
0.0
,
600.0
),
const
Point
(
0.0
,
600.0
),
],
<
bool
>[
true
,
true
,
false
,
false
,
false
]);
await
test
(
tester
,
600.0
,
anchor:
100.0
);
verify
(
tester
,
<
Point
>[
const
Point
(
0.0
,
-
500.0
),
const
Point
(
0.0
,
-
100.0
),
const
Point
(
0.0
,
300.0
),
const
Point
(
0.0
,
600.0
),
const
Point
(
0.0
,
600.0
),
],
<
bool
>[
false
,
true
,
true
,
false
,
false
]);
await
test
(
tester
,
900.0
,
anchor:
100.0
);
verify
(
tester
,
<
Point
>[
const
Point
(
0.0
,
-
800.0
),
const
Point
(
0.0
,
-
400.0
),
const
Point
(
0.0
,
0.0
),
const
Point
(
0.0
,
400.0
),
const
Point
(
0.0
,
600.0
),
],
<
bool
>[
false
,
false
,
true
,
true
,
false
]);
});
}
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