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
5928d221
Commit
5928d221
authored
Feb 02, 2017
by
Ian Hickson
Committed by
GitHub
Feb 02, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ShrinkWrap Viewport (#7790)
parent
2bbc0283
Changes
28
Hide whitespace changes
Inline
Side-by-side
Showing
28 changed files
with
1255 additions
and
560 deletions
+1255
-560
list_demo.dart
examples/flutter_gallery/lib/demo/list_demo.dart
+2
-1
about.dart
packages/flutter/lib/src/material/about.dart
+2
-2
dialog.dart
packages/flutter/lib/src/material/dialog.dart
+2
-2
popup_menu.dart
packages/flutter/lib/src/material/popup_menu.dart
+7
-7
stepper.dart
packages/flutter/lib/src/material/stepper.dart
+3
-2
two_level_list.dart
packages/flutter/lib/src/material/two_level_list.dart
+2
-6
box.dart
packages/flutter/lib/src/rendering/box.dart
+29
-7
sliver.dart
packages/flutter/lib/src/rendering/sliver.dart
+676
-373
scroll_view.dart
packages/flutter/lib/src/widgets/scroll_view.dart
+88
-64
scrollable.dart
packages/flutter/lib/src/widgets/scrollable.dart
+0
-58
single_child_scroll_view.dart
...ges/flutter/lib/src/widgets/single_child_scroll_view.dart
+14
-1
viewport.dart
packages/flutter/lib/src/widgets/viewport.dart
+36
-0
stepper_test.dart
packages/flutter/test/material/stepper_test.dart
+6
-5
rendering_tester.dart
packages/flutter/test/rendering/rendering_tester.dart
+3
-0
slivers_test.dart
packages/flutter/test/rendering/slivers_test.dart
+286
-2
block_test.dart
packages/flutter/test/widgets/block_test.dart
+3
-1
overscroll_indicator_test.dart
packages/flutter/test/widgets/overscroll_indicator_test.dart
+10
-9
scroll_grid_test.dart
packages/flutter/test/widgets/scroll_grid_test.dart
+3
-0
scrollable_custom_scroll_behavior_test.dart
.../test/widgets/scrollable_custom_scroll_behavior_test.dart
+4
-2
scrollable_test.dart
packages/flutter/test/widgets/scrollable_test.dart
+3
-1
sliver_fill_remaining_test.dart
...ages/flutter/test/widgets/sliver_fill_remaining_test.dart
+5
-3
slivers_appbar_floating_test.dart
...es/flutter/test/widgets/slivers_appbar_floating_test.dart
+6
-4
slivers_appbar_pinned_test.dart
...ages/flutter/test/widgets/slivers_appbar_pinned_test.dart
+6
-4
slivers_appbar_scrolling_test.dart
...s/flutter/test/widgets/slivers_appbar_scrolling_test.dart
+5
-3
slivers_evil_test.dart
packages/flutter/test/widgets/slivers_evil_test.dart
+3
-1
slivers_protocol_test.dart
packages/flutter/test/widgets/slivers_protocol_test.dart
+3
-1
test_widgets.dart
packages/flutter/test/widgets/test_widgets.dart
+47
-0
binding.dart
packages/flutter_test/lib/src/binding.dart
+1
-1
No files found.
examples/flutter_gallery/lib/demo/list_demo.dart
View file @
5928d221
...
...
@@ -40,7 +40,8 @@ class ListDemoState extends State<ListDemo> {
decoration:
new
BoxDecoration
(
border:
new
Border
(
top:
new
BorderSide
(
color:
Colors
.
black26
))
),
child:
new
Block
(
child:
new
ScrollView
(
shrinkWrap:
true
,
children:
<
Widget
>[
new
ListItem
(
dense:
true
,
...
...
packages/flutter/lib/src/material/about.dart
View file @
5928d221
...
...
@@ -285,8 +285,8 @@ class AboutDialog extends StatelessWidget {
if
(
children
!=
null
)
body
.
addAll
(
children
);
return
new
AlertDialog
(
content:
new
Block
(
child
ren:
body
content:
new
SingleChildScrollView
(
child
:
new
BlockBody
(
children:
body
),
),
actions:
<
Widget
>[
new
FlatButton
(
...
...
packages/flutter/lib/src/material/dialog.dart
View file @
5928d221
...
...
@@ -290,9 +290,9 @@ class SimpleDialog extends StatelessWidget {
if
(
children
!=
null
)
{
body
.
add
(
new
Flexible
(
child:
new
Block
(
child:
new
SingleChildScrollView
(
padding:
contentPadding
??
const
EdgeInsets
.
fromLTRB
(
0.0
,
12.0
,
0.0
,
16.0
),
child
ren:
children
child
:
new
BlockBody
(
children:
children
),
)
));
}
...
...
packages/flutter/lib/src/material/popup_menu.dart
View file @
5928d221
...
...
@@ -292,15 +292,15 @@ class _PopupMenu<T> extends StatelessWidget {
Widget
child
=
new
ConstrainedBox
(
constraints:
const
BoxConstraints
(
minWidth:
_kMenuMinWidth
,
maxWidth:
_kMenuMaxWidth
maxWidth:
_kMenuMaxWidth
,
),
child:
new
IntrinsicWidth
(
stepWidth:
_kMenuWidthStep
,
child:
new
Block
(
children:
children
,
child:
new
SingleChildScrollView
(
padding:
const
EdgeInsets
.
symmetric
(
vertical:
_kMenuVerticalPadding
)
),
child:
new
BlockBody
(
children:
children
),
)
)
);
...
...
@@ -317,9 +317,9 @@ class _PopupMenu<T> extends StatelessWidget {
alignment:
FractionalOffset
.
topRight
,
widthFactor:
width
.
evaluate
(
route
.
animation
),
heightFactor:
height
.
evaluate
(
route
.
animation
),
child:
child
)
)
child:
child
,
)
,
)
,
);
},
child:
child
...
...
packages/flutter/lib/src/material/stepper.dart
View file @
5928d221
...
...
@@ -542,8 +542,9 @@ class _StepperState extends State<Stepper> with TickerProviderStateMixin {
);
}
return
new
Block
(
children:
children
return
new
ScrollView
(
shrinkWrap:
true
,
children:
children
,
);
}
...
...
packages/flutter/lib/src/material/two_level_list.dart
View file @
5928d221
...
...
@@ -263,7 +263,6 @@ class TwoLevelList extends StatelessWidget {
/// The [type] argument must not be null.
TwoLevelList
({
Key
key
,
this
.
scrollableKey
,
this
.
children
:
const
<
Widget
>[],
this
.
type
:
MaterialListType
.
twoLine
,
this
.
padding
...
...
@@ -279,18 +278,15 @@ class TwoLevelList extends StatelessWidget {
/// The kind of [ListItem] contained in this list.
final
MaterialListType
type
;
/// The key to use for the underlying scrollable widget.
final
Key
scrollableKey
;
/// The amount of space by which to inset the children inside the viewport.
final
EdgeInsets
padding
;
@override
Widget
build
(
BuildContext
context
)
{
return
new
Block
(
return
new
ScrollView
(
padding:
padding
,
shrinkWrap:
true
,
children:
KeyedSubtree
.
ensureUniqueKeysForList
(
children
),
scrollableKey:
scrollableKey
);
}
}
packages/flutter/lib/src/rendering/box.dart
View file @
5928d221
...
...
@@ -198,10 +198,7 @@ class BoxConstraints extends Constraints {
return
height
.
clamp
(
minHeight
,
maxHeight
);
}
/// Returns the size that both satisfies the constraints and is as close as
/// possible to the given size.
Size
constrain
(
Size
size
)
{
Size
result
=
new
Size
(
constrainWidth
(
size
.
width
),
constrainHeight
(
size
.
height
));
Size
_debugPropagateDebugSize
(
Size
size
,
Size
result
)
{
assert
(()
{
if
(
size
is
_DebugSize
)
result
=
new
_DebugSize
(
result
,
size
.
_owner
,
size
.
_canBeUsedByParent
);
...
...
@@ -210,6 +207,26 @@ class BoxConstraints extends Constraints {
return
result
;
}
/// Returns the size that both satisfies the constraints and is as close as
/// possible to the given size.
///
/// See also [constrainDimensions], which applies the same algorithm to
/// separately provided widths and heights.
Size
constrain
(
Size
size
)
{
Size
result
=
new
Size
(
constrainWidth
(
size
.
width
),
constrainHeight
(
size
.
height
));
assert
(()
{
result
=
_debugPropagateDebugSize
(
size
,
result
);
return
true
;
});
return
result
;
}
/// Returns the size that both satisfies the constraints and is as close as
/// possible to the given width and height.
///
/// When you already have a [Size], prefer [constrain], which applies the same
/// algorithm to a [Size] directly.
Size
constrainDimensions
(
double
width
,
double
height
)
{
return
new
Size
(
constrainWidth
(
width
),
constrainHeight
(
height
));
}
/// Returns a size that attempts to meet the following conditions, in order:
///
/// - The size must satisfy these constraints.
...
...
@@ -218,8 +235,11 @@ class BoxConstraints extends Constraints {
/// - The returned size as big as possible while still being equal to or
/// smaller than the given size.
Size
constrainSizeAndAttemptToPreserveAspectRatio
(
Size
size
)
{
if
(
isTight
)
return
smallest
;
if
(
isTight
)
{
Size
result
=
smallest
;
assert
(()
{
result
=
_debugPropagateDebugSize
(
size
,
result
);
return
true
;
});
return
result
;
}
double
width
=
size
.
width
;
double
height
=
size
.
height
;
...
...
@@ -247,7 +267,9 @@ class BoxConstraints extends Constraints {
width
=
height
*
aspectRatio
;
}
return
new
Size
(
constrainWidth
(
width
),
constrainHeight
(
height
));
Size
result
=
new
Size
(
constrainWidth
(
width
),
constrainHeight
(
height
));
assert
(()
{
result
=
_debugPropagateDebugSize
(
size
,
result
);
return
true
;
});
return
result
;
}
/// The biggest size that satisifes the constraints.
...
...
packages/flutter/lib/src/rendering/sliver.dart
View file @
5928d221
...
...
@@ -257,6 +257,12 @@ class SliverConstraints extends Constraints {
///
/// The actual number of pixels provided should be specified in the
/// [RenderSliver.geometry] as [SliverGeometry.paintExtent].
///
/// This value may be infinite, for example if the viewport is an
/// unconstrained [RenderShrinkWrappingViewport].
///
/// This value may be 0.0, for example if the sliver is scrolled off the
/// bottom of a downwards vertical viewport.
final
double
remainingPaintExtent
;
/// The number of pixels in the cross-axis. For a vertical list, this is the
...
...
@@ -576,6 +582,8 @@ class SliverLogicalParentData extends ParentData {
String
toString
()
=>
'scrollOffset=
${scrollOffset.toStringAsFixed(1)}
'
;
}
class
SliverLogicalContainerParentData
extends
SliverLogicalParentData
with
ContainerParentDataMixin
<
RenderSliver
>
{
}
/// Parent data structure used by parents of slivers that position their
/// children using absolute coordinates. For example, used by [RenderViewport2].
///
...
...
@@ -740,10 +748,11 @@ abstract class RenderSliver extends RenderObject {
///
/// ## Coordinates for RenderSliver objects
///
/// The `mainAxisPosition` is the distance in the [AxisDirection] from the
/// edge of the sliver's painted area. This can be an unusual direction, for
/// example in the [AxisDirection.up] case this is a distance from the
/// _bottom_ of the sliver's painted area.
/// The `mainAxisPosition` is the distance in the [AxisDirection] (after
/// applying the [GrowthDirection]) from the edge of the sliver's painted
/// area. This can be an unusual direction, for example in the
/// [AxisDirection.up] case this is a distance from the _bottom_ of the
/// sliver's painted area.
///
/// The `crossAxisPosition` is the distance in the other axis. If the cross
/// axis is horizontal (i.e. the [SliverConstraints.axisDirection] is either
...
...
@@ -1129,7 +1138,11 @@ abstract class ViewportOffset extends ChangeNotifier {
///
/// If applying the content dimensions changes the scroll offset, return
/// false. Otherwise, return true. If you return false, the [RenderViewport2]
/// will be laid out again with the new scroll offset. This is expensive.
/// will be laid out again with the new scroll offset. This is expensive. (The
/// return value is answering the question "did you accept these content
/// dimensions unconditionally?"; if the new dimensions change the
/// [ViewportOffset]'s actual [pixels] value, then the viewport will need to
/// be laid out again.)
///
/// This is called at least once each time the [RenderViewport2] is laid out,
/// even if the values have not changed. It may be called many times if the
...
...
@@ -1199,31 +1212,14 @@ class _FixedViewportOffset extends ViewportOffset {
// /// - [RenderBox], which explains more about the Box protocol.
// /// - [RenderSliverToBoxAdapter], which allows a [RenderBox] object to be
// /// placed inside a [RenderSliver] (the opposite of this class).
class
RenderViewport2
extends
RenderBox
with
ContainerRenderObjectMixin
<
RenderSliver
,
SliverPhysicalContainerParentData
>
{
/// Creates a viewport for [RenderSliver] objects.
///
/// If the [center] is not specified, then the first child in the `children`
/// list, if any, is used.
///
/// The [offset] must be specified. For testing purposes, consider passing a
/// [new ViewportOffset.zero] or [new ViewportOffset.fixed].
RenderViewport2
({
abstract
class
RenderViewportBase2
<
ParentDataClass
extends
ContainerParentDataMixin
<
RenderSliver
>>
extends
RenderBox
with
ContainerRenderObjectMixin
<
RenderSliver
,
ParentDataClass
>
{
RenderViewportBase2
({
AxisDirection
axisDirection:
AxisDirection
.
down
,
double
anchor:
0.0
,
@required
ViewportOffset
offset
,
List
<
RenderSliver
>
children
,
RenderSliver
center
,
})
:
_axisDirection
=
axisDirection
,
_anchor
=
anchor
,
_offset
=
offset
,
_center
=
center
{
assert
(
offset
!=
null
);
_offset
=
offset
{
assert
(
axisDirection
!=
null
);
assert
(
anchor
!=
null
);
assert
(
anchor
>=
0.0
&&
anchor
<=
1.0
);
addAll
(
children
);
if
(
center
==
null
&&
firstChild
!=
null
)
_center
=
firstChild
;
assert
(
offset
!=
null
);
}
AxisDirection
get
axisDirection
=>
_axisDirection
;
...
...
@@ -1238,20 +1234,6 @@ class RenderViewport2 extends RenderBox with ContainerRenderObjectMixin<RenderSl
Axis
get
axis
=>
axisDirectionToAxis
(
axisDirection
);
// TODO(ianh): Extract the shrink-wrap logic into a separate viewport class.
bool
_shrinkWrap
=
false
;
double
get
anchor
=>
_anchor
;
double
_anchor
;
set
anchor
(
double
value
)
{
assert
(
value
!=
null
);
assert
(
value
>=
0.0
&&
value
<=
1.0
);
if
(
value
==
_anchor
)
return
;
_anchor
=
value
;
markNeedsLayout
();
}
ViewportOffset
get
offset
=>
_offset
;
ViewportOffset
_offset
;
set
offset
(
ViewportOffset
value
)
{
...
...
@@ -1266,47 +1248,14 @@ class RenderViewport2 extends RenderBox with ContainerRenderObjectMixin<RenderSl
if
(
attached
)
_offset
.
addListener
(
markNeedsLayout
);
if
(
hasSize
)
{
assert
(
_minScrollExtent
!=
null
);
assert
(
_maxScrollExtent
!=
null
);
assert
(
anchor
!=
null
);
// If we already have a size, then we should re-report the dimensions
// to the new ViewportOffset. If we don't then we'll report them when
// we establish the dimensions later, so don't worry about it now.
double
effectiveExtent
;
switch
(
axis
)
{
case
Axis
.
vertical
:
effectiveExtent
=
size
.
height
;
break
;
case
Axis
.
horizontal
:
effectiveExtent
=
size
.
width
;
break
;
}
assert
(
effectiveExtent
!=
null
);
offset
.
applyViewportDimension
(
effectiveExtent
);
if
(
offset
.
applyContentDimensions
(
// when updating this, also update similar code in performLayout()
math
.
min
(
0.0
,
_minScrollExtent
+
effectiveExtent
*
anchor
),
math
.
max
(
0.0
,
_maxScrollExtent
-
effectiveExtent
*
(
1.0
-
anchor
)),
))
markNeedsLayout
();
if
(!
rereportDimensions
())
markNeedsLayout
();
}
}
RenderSliver
get
center
=>
_center
;
RenderSliver
_center
;
set
center
(
RenderSliver
value
)
{
if
(
value
==
_center
)
return
;
_center
=
value
;
markNeedsLayout
();
}
@override
void
setupParentData
(
RenderObject
child
)
{
if
(
child
.
parentData
is
!
SliverPhysicalContainerParentData
)
child
.
parentData
=
new
SliverPhysicalContainerParentData
();
}
@override
void
attach
(
PipelineOwner
owner
)
{
super
.
attach
(
owner
);
...
...
@@ -1322,181 +1271,8 @@ class RenderViewport2 extends RenderBox with ContainerRenderObjectMixin<RenderSl
@override
bool
get
isRepaintBoundary
=>
true
;
@override
bool
get
sizedByParent
=>
!
_shrinkWrap
;
@override
void
performResize
()
{
assert
(!
_shrinkWrap
);
assert
(
constraints
.
hasBoundedHeight
&&
constraints
.
hasBoundedWidth
);
size
=
constraints
.
biggest
;
switch
(
axis
)
{
case
Axis
.
vertical
:
offset
.
applyViewportDimension
(
size
.
height
);
break
;
case
Axis
.
horizontal
:
offset
.
applyViewportDimension
(
size
.
width
);
break
;
}
}
// Out-of-band data computed during layout.
double
_minScrollExtent
;
double
_maxScrollExtent
;
double
_shrinkWrapExtent
;
bool
_hasVisualOverflow
=
false
;
@override
void
performLayout
()
{
assert
(!
_shrinkWrap
||
anchor
==
0.0
);
if
(
center
==
null
)
{
assert
(
firstChild
==
null
);
if
(
_shrinkWrap
)
{
switch
(
axis
)
{
case
Axis
.
vertical
:
size
=
new
Size
(
constraints
.
maxWidth
,
0.0
);
break
;
case
Axis
.
horizontal
:
size
=
new
Size
(
0.0
,
constraints
.
maxHeight
);
break
;
}
offset
.
applyViewportDimension
(
0.0
);
}
_minScrollExtent
=
0.0
;
_maxScrollExtent
=
0.0
;
_shrinkWrapExtent
=
0.0
;
_hasVisualOverflow
=
false
;
offset
.
applyContentDimensions
(
0.0
,
0.0
);
return
;
}
assert
(
center
.
parent
==
this
);
double
extent
;
double
crossExtent
;
if
(
_shrinkWrap
)
{
switch
(
axis
)
{
case
Axis
.
vertical
:
assert
(
constraints
.
hasBoundedWidth
);
extent
=
constraints
.
maxHeight
;
crossExtent
=
constraints
.
maxWidth
;
break
;
case
Axis
.
horizontal
:
assert
(
constraints
.
hasBoundedHeight
);
extent
=
constraints
.
maxWidth
;
crossExtent
=
constraints
.
maxHeight
;
break
;
}
}
else
{
assert
(
constraints
.
hasBoundedHeight
&&
constraints
.
hasBoundedWidth
);
switch
(
axis
)
{
case
Axis
.
vertical
:
extent
=
size
.
height
;
crossExtent
=
size
.
width
;
break
;
case
Axis
.
horizontal
:
extent
=
size
.
width
;
crossExtent
=
size
.
height
;
break
;
}
}
final
double
centerOffsetAdjustment
=
center
.
centerOffsetAdjustment
;
double
correction
;
double
effectiveExtent
;
do
{
assert
(
offset
.
pixels
!=
null
);
correction
=
_attemptLayout
(
extent
,
crossExtent
,
offset
.
pixels
+
centerOffsetAdjustment
);
if
(
correction
!=
0.0
)
{
offset
.
correctBy
(
correction
);
}
else
{
if
(
_shrinkWrap
)
{
switch
(
axis
)
{
case
Axis
.
vertical
:
effectiveExtent
=
constraints
.
constrainHeight
(
_shrinkWrapExtent
);
break
;
case
Axis
.
horizontal
:
effectiveExtent
=
constraints
.
constrainWidth
(
_shrinkWrapExtent
);
break
;
}
offset
.
applyViewportDimension
(
effectiveExtent
);
}
else
{
switch
(
axis
)
{
case
Axis
.
vertical
:
effectiveExtent
=
size
.
height
;
break
;
case
Axis
.
horizontal
:
effectiveExtent
=
size
.
width
;
break
;
}
}
// when updating this, also update similar code in offset setter
if
(
offset
.
applyContentDimensions
(
math
.
min
(
0.0
,
_minScrollExtent
+
effectiveExtent
*
anchor
),
math
.
max
(
0.0
,
_maxScrollExtent
-
effectiveExtent
*
(
1.0
-
anchor
))
))
break
;
}
}
while
(
true
);
assert
(
_shrinkWrap
!=
sizedByParent
);
if
(
_shrinkWrap
)
{
switch
(
axis
)
{
case
Axis
.
vertical
:
size
=
new
Size
(
crossExtent
,
effectiveExtent
);
break
;
case
Axis
.
horizontal
:
size
=
new
Size
(
effectiveExtent
,
crossExtent
);
break
;
}
}
}
double
_attemptLayout
(
double
extent
,
double
crossExtent
,
double
correctedOffset
)
{
assert
(!
extent
.
isNaN
);
assert
(
extent
>=
0.0
);
assert
(
crossExtent
.
isFinite
);
assert
(
crossExtent
>=
0.0
);
assert
(
correctedOffset
.
isFinite
);
_minScrollExtent
=
0.0
;
_maxScrollExtent
=
0.0
;
_shrinkWrapExtent
=
0.0
;
_hasVisualOverflow
=
false
;
// centerOffset is the offset from the leading edge of the RenderViewport2
// to the zero scroll offset (the line between the forward slivers and the
// reverse slivers). The other two are that, but clamped to the visible
// region of the viewport.
final
double
centerOffset
=
extent
*
anchor
-
correctedOffset
;
final
double
clampedForwardCenter
=
math
.
max
(
0.0
,
math
.
min
(
extent
,
centerOffset
));
final
double
clampedReverseCenter
=
math
.
max
(
0.0
,
math
.
min
(
extent
,
extent
-
centerOffset
));
// negative scroll offsets
double
result
=
_layoutOneSide
(
childBefore
(
center
),
math
.
max
(
extent
,
extent
*
anchor
-
correctedOffset
)
-
extent
,
clampedReverseCenter
,
clampedForwardCenter
,
crossExtent
,
GrowthDirection
.
reverse
,
childBefore
,
);
if
(
result
!=
0.0
)
return
-
result
;
// positive scroll offsets
return
_layoutOneSide
(
center
,
math
.
max
(
0.0
,
correctedOffset
-
extent
*
anchor
),
clampedForwardCenter
,
clampedReverseCenter
,
crossExtent
,
GrowthDirection
.
forward
,
childAfter
,
);
}
double
_layoutOneSide
(
@protected
double
layoutOneSide
(
RenderSliver
child
,
double
scrollOffset
,
double
layoutOffset
,
...
...
@@ -1540,10 +1316,8 @@ class RenderViewport2 extends RenderBox with ContainerRenderObjectMixin<RenderSl
remainingPaintExtent:
math
.
max
(
0.0
,
remainingPaintExtent
-
layoutOffset
+
initialLayoutOffset
),
crossAxisExtent:
crossAxisExtent
,
),
parentUsesSize:
true
);
// collect the child's objects
final
SliverGeometry
childLayoutGeometry
=
child
.
geometry
;
final
SliverPhysicalParentData
childParentData
=
child
.
parentData
;
assert
(
childLayoutGeometry
.
debugAssertIsValid
);
...
...
@@ -1553,7 +1327,7 @@ class RenderViewport2 extends RenderBox with ContainerRenderObjectMixin<RenderSl
return
childLayoutGeometry
.
scrollOffsetCorrection
;
// geometry
childParentData
.
paintOffset
=
_computeAbsolute
PaintOffset
(
child
,
layoutOffset
,
growthDirection
);
updateChild
PaintOffset
(
child
,
layoutOffset
,
growthDirection
);
maxPaintOffset
=
math
.
max
(
layoutOffset
+
childLayoutGeometry
.
paintExtent
,
maxPaintOffset
);
scrollOffset
-=
childLayoutGeometry
.
scrollExtent
;
layoutOffset
+=
childLayoutGeometry
.
layoutExtent
;
...
...
@@ -1561,22 +1335,9 @@ class RenderViewport2 extends RenderBox with ContainerRenderObjectMixin<RenderSl
if
(
scrollOffset
<=
0.0
)
scrollOffset
=
0.0
;
// out-of-band data mutation
switch
(
growthDirection
)
{
case
GrowthDirection
.
forward
:
_maxScrollExtent
+=
childLayoutGeometry
.
scrollExtent
;
break
;
case
GrowthDirection
.
reverse
:
_minScrollExtent
-=
childLayoutGeometry
.
scrollExtent
;
break
;
}
_shrinkWrapExtent
+=
childLayoutGeometry
.
maxPaintExtent
;
if
(
childLayoutGeometry
.
hasVisualOverflow
)
_hasVisualOverflow
=
true
;
updateOutOfBoundsData
(
growthDirection
,
childLayoutGeometry
);
// move on to the next child
assert
(
child
.
parentData
==
childParentData
);
child
=
advance
(
child
);
}
...
...
@@ -1584,65 +1345,22 @@ class RenderViewport2 extends RenderBox with ContainerRenderObjectMixin<RenderSl
return
0.0
;
}
Offset
_computeAbsolutePaintOffset
(
RenderSliver
child
,
double
paintOffset
,
GrowthDirection
growthDirection
)
{
assert
(
axisDirection
!=
null
);
assert
(
growthDirection
!=
null
);
switch
(
applyGrowthDirectionToAxisDirection
(
axisDirection
,
growthDirection
))
{
case
AxisDirection
.
up
:
return
new
Offset
(
0.0
,
size
.
height
-
(
paintOffset
+
child
.
geometry
.
paintExtent
));
case
AxisDirection
.
right
:
return
new
Offset
(
paintOffset
,
0.0
);
case
AxisDirection
.
down
:
return
new
Offset
(
0.0
,
paintOffset
);
case
AxisDirection
.
left
:
return
new
Offset
(
size
.
width
-
(
paintOffset
+
child
.
geometry
.
paintExtent
),
0.0
);
}
return
null
;
}
@override
void
applyPaintTransform
(
RenderObject
child
,
Matrix4
transform
)
{
assert
(
child
!=
null
);
assert
(
child
.
parent
==
this
);
final
SliverPhysicalParentData
childParentData
=
child
.
parentData
;
childParentData
.
applyPaintTransform
(
transform
);
}
void
_paintContents
(
PaintingContext
context
,
Offset
offset
)
{
assert
(
center
.
parent
==
this
);
assert
(
firstChild
!=
null
);
RenderSliver
child
=
firstChild
;
while
(
child
!=
center
)
{
if
(
child
.
geometry
.
visible
)
{
final
SliverPhysicalParentData
childParentData
=
child
.
parentData
;
context
.
paintChild
(
child
,
offset
+
childParentData
.
paintOffset
);
}
child
=
childAfter
(
child
);
}
child
=
lastChild
;
while
(
true
)
{
if
(
child
.
geometry
.
visible
)
{
final
SliverPhysicalParentData
childParentData
=
child
.
parentData
;
context
.
paintChild
(
child
,
offset
+
childParentData
.
paintOffset
);
}
if
(
child
==
center
)
break
;
child
=
childBefore
(
child
);
}
}
@override
void
paint
(
PaintingContext
context
,
Offset
offset
)
{
if
(
center
==
null
)
{
assert
(
firstChild
==
null
);
if
(
firstChild
==
null
)
return
;
if
(
hasVisualOverflow
)
{
context
.
pushClipRect
(
needsCompositing
,
offset
,
Point
.
origin
&
size
,
paintContents
);
}
else
{
paintContents
(
context
,
offset
);
}
}
if
(
_hasVisualOverflow
)
{
context
.
pushClipRect
(
needsCompositing
,
offset
,
Point
.
origin
&
size
,
_paintContents
);
}
else
{
_paintContents
(
context
,
offset
);
@protected
void
paintContents
(
PaintingContext
context
,
Offset
offset
)
{
for
(
RenderSliver
child
in
childrenInPaintOrder
)
{
if
(
child
.
geometry
.
visible
)
context
.
paintChild
(
child
,
offset
+
paintOffsetOf
(
child
));
}
}
...
...
@@ -1657,7 +1375,6 @@ class RenderViewport2 extends RenderBox with ContainerRenderObjectMixin<RenderSl
final
Canvas
canvas
=
context
.
canvas
;
RenderSliver
child
=
firstChild
;
while
(
child
!=
null
)
{
final
SliverPhysicalParentData
childParentData
=
child
.
parentData
;
Size
size
;
switch
(
axis
)
{
case
Axis
.
vertical
:
...
...
@@ -1668,7 +1385,7 @@ class RenderViewport2 extends RenderBox with ContainerRenderObjectMixin<RenderSl
break
;
}
assert
(
size
!=
null
);
canvas
.
drawRect
(((
offset
+
childParentData
.
paintOffset
)
&
size
).
deflate
(
0.5
),
paint
);
canvas
.
drawRect
(((
offset
+
paintOffsetOf
(
child
)
)
&
size
).
deflate
(
0.5
),
paint
);
child
=
childAfter
(
child
);
}
return
true
;
...
...
@@ -1677,63 +1394,49 @@ class RenderViewport2 extends RenderBox with ContainerRenderObjectMixin<RenderSl
@override
bool
hitTestChildren
(
HitTestResult
result
,
{
Point
position
})
{
if
(
center
==
null
)
{
assert
(
firstChild
==
null
);
return
false
;
}
assert
(
center
.
parent
==
this
);
assert
(
firstChild
!=
null
);
double
crossAxisPosition
,
mainAxisPosition
;
double
mainAxisPosition
,
crossAxisPosition
;
switch
(
axis
)
{
case
Axis
.
vertical
:
crossAxisPosition
=
position
.
x
;
mainAxisPosition
=
position
.
y
;
crossAxisPosition
=
position
.
x
;
break
;
case
Axis
.
horizontal
:
crossAxisPosition
=
position
.
y
;
mainAxisPosition
=
position
.
x
;
crossAxisPosition
=
position
.
y
;
break
;
}
assert
(
mainAxisPosition
!=
null
);
assert
(
crossAxisPosition
!=
null
);
RenderSliver
child
;
child
=
center
;
while
(
child
!=
null
)
{
if
(
child
.
geometry
.
visible
&&
child
.
hitTest
(
result
,
mainAxisPosition:
_computeChildMainAxisPosition
(
child
,
mainAxisPosition
),
crossAxisPosition:
crossAxisPosition
))
{
return
true
;
}
child
=
childAfter
(
child
);
}
child
=
childBefore
(
center
);
while
(
child
!=
null
)
{
for
(
RenderSliver
child
in
childrenInHitTestOrder
)
{
if
(
child
.
geometry
.
visible
&&
child
.
hitTest
(
result
,
mainAxisPosition:
_
computeChildMainAxisPosition
(
child
,
mainAxisPosition
),
mainAxisPosition:
computeChildMainAxisPosition
(
child
,
mainAxisPosition
),
crossAxisPosition:
crossAxisPosition
))
{
return
true
;
}
child
=
childBefore
(
child
);
}
return
false
;
}
double
_computeChildMainAxisPosition
(
RenderSliver
child
,
double
parentMainAxisPosition
)
{
final
SliverPhysicalParentData
childParentData
=
child
.
parentData
;
switch
(
applyGrowthDirectionToAxisDirection
(
child
.
constraints
.
axisDirection
,
child
.
constraints
.
growthDirection
))
{
@protected
Offset
computeAbsolutePaintOffset
(
RenderSliver
child
,
double
paintOffset
,
GrowthDirection
growthDirection
)
{
assert
(
hasSize
);
// this is only usable once we have a size
assert
(
axisDirection
!=
null
);
assert
(
growthDirection
!=
null
);
assert
(
child
!=
null
);
assert
(
child
.
geometry
!=
null
);
switch
(
applyGrowthDirectionToAxisDirection
(
axisDirection
,
growthDirection
))
{
case
AxisDirection
.
up
:
return
child
.
geometry
.
paintExtent
-
(
parentMainAxisPosition
-
childParentData
.
paintOffset
.
dy
);
return
new
Offset
(
0.0
,
size
.
height
-
(
paintOffset
+
child
.
geometry
.
paintExtent
)
);
case
AxisDirection
.
right
:
return
parentMainAxisPosition
-
childParentData
.
paintOffset
.
dx
;
return
new
Offset
(
paintOffset
,
0.0
)
;
case
AxisDirection
.
down
:
return
parentMainAxisPosition
-
childParentData
.
paintOffset
.
dy
;
return
new
Offset
(
0.0
,
paintOffset
)
;
case
AxisDirection
.
left
:
return
child
.
geometry
.
paintExtent
-
(
parentMainAxisPosition
-
childParentData
.
paintOffset
.
dx
);
return
new
Offset
(
size
.
width
-
(
paintOffset
+
child
.
geometry
.
paintExtent
),
0.0
);
}
return
0.0
;
return
null
;
}
// TODO(ianh): semantics - shouldn't walk the invisible children
...
...
@@ -1742,46 +1445,646 @@ class RenderViewport2 extends RenderBox with ContainerRenderObjectMixin<RenderSl
void
debugFillDescription
(
List
<
String
>
description
)
{
super
.
debugFillDescription
(
description
);
description
.
add
(
'
$axisDirection
'
);
if
(
_shrinkWrap
)
description
.
add
(
'shrink-wrap enabled'
);
description
.
add
(
'anchor:
$anchor
'
);
description
.
add
(
'offset:
$offset
'
);
}
@override
String
debugDescribeChildren
(
String
prefix
)
{
if
(
firstChild
==
null
)
return
'
$prefix
\n
'
;
int
count
=
indexOfFirstChild
();
String
result
=
'
$prefix
\
u2502
\n
'
;
RenderSliver
child
=
firstChild
;
while
(
child
!=
lastChild
)
{
result
+=
'
${child.toStringDeep("$prefix \u251C\u2500${labelForChild(count)}
: ", "
$prefix
\
u2502")}'
;
count
+=
1
;
child
=
childAfter
(
child
);
}
assert
(
child
==
lastChild
);
result
+=
'
${child.toStringDeep("$prefix \u2514\u2500${labelForChild(count)}
: ", "
$prefix
")}'
;
return
result
;
}
// API TO BE IMPLEMENTED BY SUBCLASSES
// setupParentData
// performLayout (and optionally sizedByParent and performResize)
@protected
bool
get
hasVisualOverflow
;
@protected
void
updateOutOfBoundsData
(
GrowthDirection
growthDirection
,
SliverGeometry
childLayoutGeometry
);
@protected
void
updateChildPaintOffset
(
RenderSliver
child
,
double
paintOffset
,
GrowthDirection
growthDirection
);
@protected
Offset
paintOffsetOf
(
RenderSliver
child
);
// applyPaintTransform
/// Converts the `parentMainAxisPosition` into the child's coordinate system.
///
/// The `parentMainAxisPosition` is a distance from the top edge (for vertical
/// viewports) or left edge (for horizontal viewports) of the viewport bounds.
/// This describes a line, perpendicular to the viewport's main axis, heretofor
/// known as the target line.
///
/// The child's coordinate system's origin in the main axis is at the leading
/// edge of the given child, as given by the child's
/// [SliverConstraints.axisDirection] and [SliverConstraints.growthDirection].
///
/// This method returns the distance from the leading edge of the given child to
/// the target line described above.
///
/// (The `parentMainAxisPosition` is not from the leading edge of the
/// viewport, it's always the top or left edge.)
@protected
double
computeChildMainAxisPosition
(
RenderSliver
child
,
double
parentMainAxisPosition
);
/// Notifies the [offset] of the render object's new dimensions.
///
/// Implementations must call [ViewportOffset.applyViewportDimension] and
/// [ViewportOffset.applyContentDimensions], in that order.
///
/// Return the value returned by [ViewportOffset.applyContentDimensions]:
/// false if the [ViewportOffset] did not accept the new dimensions
/// unconditionally, but instead wants to relayout the render object (e.g.
/// because it changed its mind about the actual offset that the viewport
/// should be laid out at), and true if the [ViewportOffset] was happy with
/// the given dimensions and does not think that anything need change. If this
/// function returns false, the caller will call [markNeedsLayout].
@protected
bool
rereportDimensions
();
@protected
int
indexOfFirstChild
();
@protected
String
labelForChild
(
int
index
);
/// Provides an iterable that walks the children of the viewport, in the order
/// that they should be painted.
///
/// This should be the reverse order of [childrenInHitTestOrder].
@protected
Iterable
<
RenderSliver
>
get
childrenInPaintOrder
;
/// Provides an iterable that walks the children of the viewport, in the order
/// that hit-testing should use.
///
/// This should be the reverse order of [childrenInPaintOrder].
@protected
Iterable
<
RenderSliver
>
get
childrenInHitTestOrder
;
}
// ///
// /// See also:
// ///
// /// - [RenderSliver], which explains more about the Sliver protocol.
// /// - [RenderBox], which explains more about the Box protocol.
// /// - [RenderSliverToBoxAdapter], which allows a [RenderBox] object to be
// /// placed inside a [RenderSliver] (the opposite of this class).
// /// - [RenderShrinkWrappingViewport], a variant of [RenderViewport2] that
// /// shrink-wraps its contents along the main axis.
class
RenderViewport2
extends
RenderViewportBase2
<
SliverPhysicalContainerParentData
>
{
/// Creates a viewport for [RenderSliver] objects.
///
/// If the [center] is not specified, then the first child in the `children`
/// list, if any, is used.
///
/// The [offset] must be specified. For testing purposes, consider passing a
/// [new ViewportOffset.zero] or [new ViewportOffset.fixed].
RenderViewport2
({
AxisDirection
axisDirection:
AxisDirection
.
down
,
@required
ViewportOffset
offset
,
double
anchor:
0.0
,
List
<
RenderSliver
>
children
,
RenderSliver
center
,
})
:
_anchor
=
anchor
,
_center
=
center
,
super
(
axisDirection:
axisDirection
,
offset:
offset
)
{
assert
(
anchor
!=
null
);
assert
(
anchor
>=
0.0
&&
anchor
<=
1.0
);
addAll
(
children
);
if
(
center
==
null
&&
firstChild
!=
null
)
_center
=
firstChild
;
}
@override
void
setupParentData
(
RenderObject
child
)
{
if
(
child
.
parentData
is
!
SliverPhysicalContainerParentData
)
child
.
parentData
=
new
SliverPhysicalContainerParentData
();
}
double
get
anchor
=>
_anchor
;
double
_anchor
;
set
anchor
(
double
value
)
{
assert
(
value
!=
null
);
assert
(
value
>=
0.0
&&
value
<=
1.0
);
if
(
value
==
_anchor
)
return
;
_anchor
=
value
;
markNeedsLayout
();
}
RenderSliver
get
center
=>
_center
;
RenderSliver
_center
;
set
center
(
RenderSliver
value
)
{
if
(
value
==
_center
)
return
;
_center
=
value
;
markNeedsLayout
();
}
@override
bool
get
sizedByParent
=>
true
;
@override
void
performResize
()
{
assert
(
constraints
.
hasBoundedHeight
&&
constraints
.
hasBoundedWidth
);
size
=
constraints
.
biggest
;
switch
(
axis
)
{
case
Axis
.
vertical
:
offset
.
applyViewportDimension
(
size
.
height
);
break
;
case
Axis
.
horizontal
:
offset
.
applyViewportDimension
(
size
.
width
);
break
;
}
}
static
const
int
_kMaxLayoutCycles
=
10
;
// Out-of-band data computed during layout.
double
_minScrollExtent
;
double
_maxScrollExtent
;
bool
_hasVisualOverflow
=
false
;
@override
void
performLayout
()
{
if
(
center
==
null
)
{
assert
(
firstChild
==
null
);
return
result
;
_minScrollExtent
=
0.0
;
_maxScrollExtent
=
0.0
;
_hasVisualOverflow
=
false
;
offset
.
applyContentDimensions
(
0.0
,
0.0
);
return
;
}
assert
(
center
.
parent
==
this
);
assert
(
firstChild
!=
null
);
double
mainAxisExtent
;
double
crossAxisExtent
;
switch
(
axis
)
{
case
Axis
.
vertical
:
mainAxisExtent
=
size
.
height
;
crossAxisExtent
=
size
.
width
;
break
;
case
Axis
.
horizontal
:
mainAxisExtent
=
size
.
width
;
crossAxisExtent
=
size
.
height
;
break
;
}
final
double
centerOffsetAdjustment
=
center
.
centerOffsetAdjustment
;
double
correction
;
int
count
=
0
;
do
{
assert
(
offset
.
pixels
!=
null
);
correction
=
_attemptLayout
(
mainAxisExtent
,
crossAxisExtent
,
offset
.
pixels
+
centerOffsetAdjustment
);
if
(
correction
!=
0.0
)
{
offset
.
correctBy
(
correction
);
}
else
{
// when updating this, also update rereportDimensions
if
(
offset
.
applyContentDimensions
(
math
.
min
(
0.0
,
_minScrollExtent
+
mainAxisExtent
*
anchor
),
math
.
max
(
0.0
,
_maxScrollExtent
-
mainAxisExtent
*
(
1.0
-
anchor
)),
))
break
;
}
count
+=
1
;
}
while
(
count
<
_kMaxLayoutCycles
);
assert
(()
{
if
(
count
>=
_kMaxLayoutCycles
)
{
assert
(
count
!=
1
);
throw
new
FlutterError
(
'A RenderViewport2 exceeded its maximum number of layout cycles.
\n
'
'RenderViewport2 render objects, during layout, can retry if either their '
'slivers or their ViewportOffset decide that the offset should be corrected '
'to take into account information collected during that layout.
\n
'
'In the case of this RenderViewport2 object, however, this happened
$count
'
'times and still there was no consensus on the scroll offset. This usually '
'indicates a bug. Specifically, it means that one of the following three '
'problems is being experienced by the RenderViewport2 object:
\n
'
' * One of the RenderSliver children or the ViewportOffset have a bug such'
' that they always think that they need to correct the offset regardless.
\n
'
' * Some combination of the RenderSliver children and the ViewportOffset'
' have a bad interaction such that one applies a correction then another'
' applies a reverse correction, leading to an infinite loop of corrections.
\n
'
' * There is a pathological case that would eventually resolve, but it is'
' so complicated that it cannot be resolved in any reasonable number of'
' layout passes.'
);
}
return
true
;
});
}
double
_attemptLayout
(
double
mainAxisExtent
,
double
crossAxisExtent
,
double
correctedOffset
)
{
assert
(!
mainAxisExtent
.
isNaN
);
assert
(
mainAxisExtent
>=
0.0
);
assert
(
crossAxisExtent
.
isFinite
);
assert
(
crossAxisExtent
>=
0.0
);
assert
(
correctedOffset
.
isFinite
);
_minScrollExtent
=
0.0
;
_maxScrollExtent
=
0.0
;
_hasVisualOverflow
=
false
;
// centerOffset is the offset from the leading edge of the RenderViewport2
// to the zero scroll offset (the line between the forward slivers and the
// reverse slivers). The other two are that, but clamped to the visible
// region of the viewport.
final
double
centerOffset
=
mainAxisExtent
*
anchor
-
correctedOffset
;
final
double
clampedForwardCenter
=
math
.
max
(
0.0
,
math
.
min
(
mainAxisExtent
,
centerOffset
));
final
double
clampedReverseCenter
=
math
.
max
(
0.0
,
math
.
min
(
mainAxisExtent
,
mainAxisExtent
-
centerOffset
));
// negative scroll offsets
double
result
=
layoutOneSide
(
childBefore
(
center
),
math
.
max
(
mainAxisExtent
,
mainAxisExtent
*
anchor
-
correctedOffset
)
-
mainAxisExtent
,
clampedReverseCenter
,
clampedForwardCenter
,
crossAxisExtent
,
GrowthDirection
.
reverse
,
childBefore
,
);
if
(
result
!=
0.0
)
return
-
result
;
// positive scroll offsets
return
layoutOneSide
(
center
,
math
.
max
(
0.0
,
correctedOffset
-
mainAxisExtent
*
anchor
),
clampedForwardCenter
,
clampedReverseCenter
,
crossAxisExtent
,
GrowthDirection
.
forward
,
childAfter
,
);
}
@override
bool
get
hasVisualOverflow
=>
_hasVisualOverflow
;
@override
void
updateOutOfBoundsData
(
GrowthDirection
growthDirection
,
SliverGeometry
childLayoutGeometry
)
{
switch
(
growthDirection
)
{
case
GrowthDirection
.
forward
:
_maxScrollExtent
+=
childLayoutGeometry
.
scrollExtent
;
break
;
case
GrowthDirection
.
reverse
:
_minScrollExtent
-=
childLayoutGeometry
.
scrollExtent
;
break
;
}
if
(
childLayoutGeometry
.
hasVisualOverflow
)
_hasVisualOverflow
=
true
;
}
@override
void
updateChildPaintOffset
(
RenderSliver
child
,
double
paintOffset
,
GrowthDirection
growthDirection
)
{
final
SliverPhysicalParentData
childParentData
=
child
.
parentData
;
childParentData
.
paintOffset
=
computeAbsolutePaintOffset
(
child
,
paintOffset
,
growthDirection
);
}
@override
Offset
paintOffsetOf
(
RenderSliver
child
)
{
final
SliverPhysicalParentData
childParentData
=
child
.
parentData
;
return
childParentData
.
paintOffset
;
}
@override
void
applyPaintTransform
(
RenderObject
child
,
Matrix4
transform
)
{
assert
(
child
!=
null
);
final
SliverPhysicalParentData
childParentData
=
child
.
parentData
;
childParentData
.
applyPaintTransform
(
transform
);
}
@override
double
computeChildMainAxisPosition
(
RenderSliver
child
,
double
parentMainAxisPosition
)
{
assert
(
child
!=
null
);
assert
(
child
.
constraints
!=
null
);
final
SliverPhysicalParentData
childParentData
=
child
.
parentData
;
switch
(
applyGrowthDirectionToAxisDirection
(
child
.
constraints
.
axisDirection
,
child
.
constraints
.
growthDirection
))
{
case
AxisDirection
.
down
:
return
parentMainAxisPosition
-
childParentData
.
paintOffset
.
dy
;
case
AxisDirection
.
right
:
return
parentMainAxisPosition
-
childParentData
.
paintOffset
.
dx
;
case
AxisDirection
.
up
:
return
child
.
geometry
.
paintExtent
-
(
parentMainAxisPosition
-
childParentData
.
paintOffset
.
dy
);
case
AxisDirection
.
left
:
return
child
.
geometry
.
paintExtent
-
(
parentMainAxisPosition
-
childParentData
.
paintOffset
.
dx
);
}
return
0.0
;
}
@override
bool
rereportDimensions
()
{
assert
(
_minScrollExtent
!=
null
);
assert
(
_maxScrollExtent
!=
null
);
assert
(
anchor
!=
null
);
double
effectiveExtent
;
switch
(
axis
)
{
case
Axis
.
vertical
:
effectiveExtent
=
size
.
height
;
break
;
case
Axis
.
horizontal
:
effectiveExtent
=
size
.
width
;
break
;
}
assert
(
effectiveExtent
!=
null
);
offset
.
applyViewportDimension
(
effectiveExtent
);
return
offset
.
applyContentDimensions
(
// when updating this, also update similar code in performLayout()
math
.
min
(
0.0
,
_minScrollExtent
+
effectiveExtent
*
anchor
),
math
.
max
(
0.0
,
_maxScrollExtent
-
effectiveExtent
*
(
1.0
-
anchor
)),
);
}
@override
int
indexOfFirstChild
()
{
assert
(
center
!=
null
);
assert
(
center
.
parent
==
this
);
assert
(
firstChild
!=
null
);
int
count
=
0
;
RenderSliver
child
=
center
;
while
(
child
!=
firstChild
)
{
count
-=
1
;
child
=
childBefore
(
child
);
}
return
count
;
}
child
=
firstChild
;
while
(
child
!=
lastChild
)
{
result
+=
'
${child.toStringDeep("$prefix \u251C\u2500${_labelChild(count)}
: ", "
$prefix
\
u2502")}'
;
count
+=
1
;
@override
String
labelForChild
(
int
index
)
{
if
(
index
==
0
)
return
'center child'
;
return
'child
$index
'
;
}
@override
Iterable
<
RenderSliver
>
get
childrenInPaintOrder
sync
*
{
if
(
firstChild
==
null
)
return
;
RenderSliver
child
=
firstChild
;
while
(
child
!=
center
)
{
yield
child
;
child
=
childAfter
(
child
);
}
child
=
lastChild
;
while
(
true
)
{
yield
child
;
if
(
child
==
center
)
return
;
child
=
childBefore
(
child
);
}
}
@override
Iterable
<
RenderSliver
>
get
childrenInHitTestOrder
sync
*
{
if
(
firstChild
==
null
)
return
;
RenderSliver
child
=
center
;
while
(
child
!=
null
)
{
yield
child
;
child
=
childAfter
(
child
);
}
if
(
child
!=
null
)
{
assert
(
child
==
lastChild
);
result
+=
'
${child.toStringDeep("$prefix \u2514\u2500${_labelChild(count)}
: ", "
$prefix
")}'
;
child
=
childBefore
(
center
);
while
(
child
!=
null
)
{
yield
child
;
child
=
childBefore
(
child
);
}
return
result
;
}
static
String
_labelChild
(
int
count
)
{
if
(
count
==
0
)
return
'center child'
;
return
'child
$count
'
;
@override
void
debugFillDescription
(
List
<
String
>
description
)
{
super
.
debugFillDescription
(
description
);
description
.
add
(
'anchor:
$anchor
'
);
}
}
// ///
// /// See also:
// ///
// /// - [RenderViewport2], a viewport that does not shrink-wrap its contents
// /// - [RenderSliver], which explains more about the Sliver protocol.
// /// - [RenderBox], which explains more about the Box protocol.
// /// - [RenderSliverToBoxAdapter], which allows a [RenderBox] object to be
// /// placed inside a [RenderSliver] (the opposite of this class).
class
RenderShrinkWrappingViewport
extends
RenderViewportBase2
<
SliverLogicalContainerParentData
>
{
/// Creates a viewport (for [RenderSliver] objects) that shrink-wraps its
/// contents.
///
/// The [offset] must be specified. For testing purposes, consider passing a
/// [new ViewportOffset.zero] or [new ViewportOffset.fixed].
RenderShrinkWrappingViewport
({
AxisDirection
axisDirection:
AxisDirection
.
down
,
@required
ViewportOffset
offset
,
List
<
RenderSliver
>
children
,
})
:
super
(
axisDirection:
axisDirection
,
offset:
offset
)
{
addAll
(
children
);
}
@override
void
setupParentData
(
RenderObject
child
)
{
if
(
child
.
parentData
is
!
SliverLogicalContainerParentData
)
child
.
parentData
=
new
SliverLogicalContainerParentData
();
}
// Out-of-band data computed during layout.
double
_maxScrollExtent
;
double
_shrinkWrapExtent
;
bool
_hasVisualOverflow
=
false
;
@override
void
performLayout
()
{
if
(
firstChild
==
null
)
{
switch
(
axis
)
{
case
Axis
.
vertical
:
assert
(
constraints
.
hasBoundedWidth
);
size
=
new
Size
(
constraints
.
maxWidth
,
constraints
.
minHeight
);
break
;
case
Axis
.
horizontal
:
assert
(
constraints
.
hasBoundedHeight
);
size
=
new
Size
(
constraints
.
minWidth
,
constraints
.
maxHeight
);
break
;
}
offset
.
applyViewportDimension
(
0.0
);
_maxScrollExtent
=
0.0
;
_shrinkWrapExtent
=
0.0
;
_hasVisualOverflow
=
false
;
offset
.
applyContentDimensions
(
0.0
,
0.0
);
return
;
}
double
mainAxisExtent
;
double
crossAxisExtent
;
switch
(
axis
)
{
case
Axis
.
vertical
:
assert
(
constraints
.
hasBoundedWidth
);
mainAxisExtent
=
constraints
.
maxHeight
;
crossAxisExtent
=
constraints
.
maxWidth
;
break
;
case
Axis
.
horizontal
:
assert
(
constraints
.
hasBoundedHeight
);
mainAxisExtent
=
constraints
.
maxWidth
;
crossAxisExtent
=
constraints
.
maxHeight
;
break
;
}
double
correction
;
double
effectiveExtent
;
do
{
assert
(
offset
.
pixels
!=
null
);
correction
=
_attemptLayout
(
mainAxisExtent
,
crossAxisExtent
,
offset
.
pixels
);
if
(
correction
!=
0.0
)
{
offset
.
correctBy
(
correction
);
}
else
{
switch
(
axis
)
{
case
Axis
.
vertical
:
effectiveExtent
=
constraints
.
constrainHeight
(
_shrinkWrapExtent
);
break
;
case
Axis
.
horizontal
:
effectiveExtent
=
constraints
.
constrainWidth
(
_shrinkWrapExtent
);
break
;
}
offset
.
applyViewportDimension
(
effectiveExtent
);
// when updating this, also update similar code in rereportDimensions
if
(
offset
.
applyContentDimensions
(
0.0
,
math
.
max
(
0.0
,
_maxScrollExtent
-
effectiveExtent
)))
break
;
}
}
while
(
true
);
switch
(
axis
)
{
case
Axis
.
vertical
:
size
=
constraints
.
constrainDimensions
(
crossAxisExtent
,
effectiveExtent
);
break
;
case
Axis
.
horizontal
:
size
=
constraints
.
constrainDimensions
(
effectiveExtent
,
crossAxisExtent
);
break
;
}
}
double
_attemptLayout
(
double
mainAxisExtent
,
double
crossAxisExtent
,
double
correctedOffset
)
{
assert
(!
mainAxisExtent
.
isNaN
);
assert
(
mainAxisExtent
>=
0.0
);
assert
(
crossAxisExtent
.
isFinite
);
assert
(
crossAxisExtent
>=
0.0
);
assert
(
correctedOffset
.
isFinite
);
_maxScrollExtent
=
0.0
;
_shrinkWrapExtent
=
0.0
;
_hasVisualOverflow
=
false
;
return
layoutOneSide
(
firstChild
,
math
.
max
(
0.0
,
correctedOffset
),
0.0
,
mainAxisExtent
,
crossAxisExtent
,
GrowthDirection
.
forward
,
childAfter
,
);
}
@override
bool
get
hasVisualOverflow
=>
_hasVisualOverflow
;
@override
void
updateOutOfBoundsData
(
GrowthDirection
growthDirection
,
SliverGeometry
childLayoutGeometry
)
{
assert
(
growthDirection
==
GrowthDirection
.
forward
);
_maxScrollExtent
+=
childLayoutGeometry
.
scrollExtent
;
if
(
childLayoutGeometry
.
hasVisualOverflow
)
_hasVisualOverflow
=
true
;
_shrinkWrapExtent
+=
childLayoutGeometry
.
maxPaintExtent
;
}
@override
void
updateChildPaintOffset
(
RenderSliver
child
,
double
paintOffset
,
GrowthDirection
growthDirection
)
{
assert
(
growthDirection
==
GrowthDirection
.
forward
);
final
SliverLogicalParentData
childParentData
=
child
.
parentData
;
childParentData
.
scrollOffset
=
paintOffset
;
}
@override
Offset
paintOffsetOf
(
RenderSliver
child
)
{
final
SliverLogicalParentData
childParentData
=
child
.
parentData
;
return
computeAbsolutePaintOffset
(
child
,
childParentData
.
scrollOffset
,
GrowthDirection
.
forward
);
}
@override
void
applyPaintTransform
(
RenderObject
child
,
Matrix4
transform
)
{
assert
(
child
!=
null
);
final
Offset
offset
=
paintOffsetOf
(
child
);
transform
.
translate
(
offset
.
dx
,
offset
.
dy
);
}
@override
double
computeChildMainAxisPosition
(
RenderSliver
child
,
double
parentMainAxisPosition
)
{
assert
(
child
!=
null
);
assert
(
child
.
constraints
!=
null
);
assert
(
hasSize
);
final
SliverLogicalParentData
childParentData
=
child
.
parentData
;
switch
(
applyGrowthDirectionToAxisDirection
(
child
.
constraints
.
axisDirection
,
child
.
constraints
.
growthDirection
))
{
case
AxisDirection
.
down
:
case
AxisDirection
.
right
:
return
parentMainAxisPosition
-
childParentData
.
scrollOffset
;
case
AxisDirection
.
up
:
return
(
size
.
height
-
parentMainAxisPosition
)
-
childParentData
.
scrollOffset
;
case
AxisDirection
.
left
:
return
(
size
.
width
-
parentMainAxisPosition
)
-
childParentData
.
scrollOffset
;
}
return
0.0
;
}
@override
bool
rereportDimensions
()
{
assert
(
_maxScrollExtent
!=
null
);
double
effectiveExtent
;
switch
(
axis
)
{
case
Axis
.
vertical
:
effectiveExtent
=
size
.
height
;
break
;
case
Axis
.
horizontal
:
effectiveExtent
=
size
.
width
;
break
;
}
assert
(
effectiveExtent
!=
null
);
offset
.
applyViewportDimension
(
effectiveExtent
);
return
offset
.
applyContentDimensions
(
0.0
,
math
.
max
(
0.0
,
_maxScrollExtent
-
effectiveExtent
));
}
@override
int
indexOfFirstChild
()
=>
0
;
@override
String
labelForChild
(
int
index
)
=>
'child
$index
'
;
@override
Iterable
<
RenderSliver
>
get
childrenInPaintOrder
sync
*
{
RenderSliver
child
=
firstChild
;
while
(
child
!=
null
)
{
yield
child
;
child
=
childAfter
(
child
);
}
}
@override
Iterable
<
RenderSliver
>
get
childrenInHitTestOrder
sync
*
{
RenderSliver
child
=
lastChild
;
while
(
child
!=
null
)
{
yield
child
;
child
=
childBefore
(
child
);
}
}
}
...
...
packages/flutter/lib/src/widgets/scroll_view.dart
View file @
5928d221
...
...
@@ -9,136 +9,160 @@ import 'framework.dart';
import
'basic.dart'
;
import
'scrollable.dart'
;
import
'sliver.dart'
;
import
'viewport.dart'
;
AxisDirection
_getDirection
(
BuildContext
context
,
Axis
scrollDirection
)
{
// TODO(abarth): Consider reading direction.
switch
(
scrollDirection
)
{
case
Axis
.
horizontal
:
return
AxisDirection
.
right
;
case
Axis
.
vertical
:
return
AxisDirection
.
down
;
}
return
null
;
}
/// A convenience widget that combines common scrolling-related widgets.
class
ScrollView
extends
StatelessWidget
{
ScrollView
({
Key
key
,
this
.
padding
,
this
.
scrollDirection
:
Axis
.
vertical
,
this
.
reverse
:
false
,
this
.
padding
,
this
.
initialScrollOffset
:
0.0
,
this
.
itemExtent
,
this
.
shrinkWrap
:
false
,
this
.
children
:
const
<
Widget
>[],
})
:
super
(
key:
key
);
final
EdgeInsets
padding
;
})
:
super
(
key:
key
)
{
assert
(
reverse
!=
null
);
assert
(
initialScrollOffset
!=
null
);
assert
(
shrinkWrap
!=
null
);
}
final
Axis
scrollDirection
;
final
bool
reverse
;
final
EdgeInsets
padding
;
final
double
initialScrollOffset
;
final
double
itemExtent
;
final
bool
shrinkWrap
;
final
List
<
Widget
>
children
;
Widget
_buildChildLayout
()
{
final
SliverChildListDelegate
delegate
=
new
SliverChildListDelegate
(
children
);
SliverChildListDelegate
get
childrenDelegate
=>
new
SliverChildListDelegate
(
children
);
@protected
AxisDirection
getDirection
(
BuildContext
context
)
{
// TODO(abarth): Consider reading direction.
switch
(
scrollDirection
)
{
case
Axis
.
horizontal
:
return
reverse
?
AxisDirection
.
left
:
AxisDirection
.
right
;
case
Axis
.
vertical
:
return
reverse
?
AxisDirection
.
up
:
AxisDirection
.
down
;
}
return
null
;
}
@protected
Widget
buildChildLayout
(
BuildContext
context
)
{
if
(
itemExtent
!=
null
)
{
return
new
SliverList
(
delegate:
d
elegate
,
delegate:
childrenD
elegate
,
itemExtent:
itemExtent
,
);
}
return
new
SliverBlock
(
delegate:
delegate
);
return
new
SliverBlock
(
delegate:
childrenDelegate
);
}
@override
Widget
build
(
BuildContext
context
)
{
Widget
sliver
=
_buildChildLayout
();
Widget
sliver
=
buildChildLayout
(
context
);
if
(
padding
!=
null
)
sliver
=
new
SliverPadding
(
padding:
padding
,
child:
sliver
);
return
new
Scrollable
Viewport
2
(
axisDirection:
_getDirection
(
context
,
scrollDirection
)
,
AxisDirection
axisDirection
=
getDirection
(
context
);
return
new
Scrollable2
(
axisDirection:
axisDirection
,
initialScrollOffset:
initialScrollOffset
,
slivers:
<
Widget
>[
sliver
],
viewportBuilder:
(
BuildContext
context
,
ViewportOffset
offset
)
{
if
(
shrinkWrap
)
{
return
new
ShrinkWrappingViewport
(
axisDirection:
axisDirection
,
offset:
offset
,
slivers:
<
Widget
>[
sliver
],
);
}
else
{
return
new
Viewport2
(
axisDirection:
axisDirection
,
offset:
offset
,
slivers:
<
Widget
>[
sliver
],
);
}
}
);
}
@override
void
debugFillDescription
(
List
<
String
>
description
)
{
super
.
debugFillDescription
(
description
);
description
.
add
(
'
$scrollDirection
'
);
if
(
padding
!=
null
)
description
.
add
(
'padding:
$padding
'
);
if
(
initialScrollOffset
!=
0.0
)
description
.
add
(
'initialScrollOffset:
${initialScrollOffset.toStringAsFixed(1)}
'
);
if
(
itemExtent
!=
null
)
description
.
add
(
'itemExtent:
$itemExtent
'
);
if
(
shrinkWrap
)
description
.
add
(
'shrink-wrapping'
);
}
}
class
ScrollGrid
extends
S
tatelessWidget
{
class
ScrollGrid
extends
S
crollView
{
ScrollGrid
({
Key
key
,
this
.
padding
,
this
.
scrollDirection
:
Axis
.
vertical
,
this
.
initialScrollOffset
:
0.0
,
Axis
scrollDirection:
Axis
.
vertical
,
EdgeInsets
padding
,
double
initialScrollOffset:
0.0
,
bool
shrinkWrap:
false
,
this
.
gridDelegate
,
this
.
children
:
const
<
Widget
>[],
})
:
super
(
key:
key
);
List
<
Widget
>
children:
const
<
Widget
>[],
})
:
super
(
key:
key
,
scrollDirection:
scrollDirection
,
padding:
padding
,
shrinkWrap:
shrinkWrap
,
children:
children
);
ScrollGrid
.
count
({
Key
key
,
this
.
padding
,
this
.
scrollDirection
:
Axis
.
vertical
,
this
.
initialScrollOffset
:
0.0
,
Axis
scrollDirection:
Axis
.
vertical
,
EdgeInsets
padding
,
double
initialScrollOffset:
0.0
,
bool
shrinkWrap:
false
,
@required
int
crossAxisCount
,
double
mainAxisSpacing:
0.0
,
double
crossAxisSpacing:
0.0
,
double
childAspectRatio:
1.0
,
this
.
children
:
const
<
Widget
>[],
List
<
Widget
>
children:
const
<
Widget
>[],
})
:
gridDelegate
=
new
SliverGridDelegateWithFixedCrossAxisCount
(
crossAxisCount:
crossAxisCount
,
mainAxisSpacing:
mainAxisSpacing
,
crossAxisSpacing:
crossAxisSpacing
,
childAspectRatio:
childAspectRatio
,
),
super
(
key:
key
);
),
super
(
key:
key
,
scrollDirection:
scrollDirection
,
padding:
padding
,
shrinkWrap:
shrinkWrap
,
children:
children
);
ScrollGrid
.
extent
({
Key
key
,
this
.
padding
,
this
.
scrollDirection
:
Axis
.
vertical
,
this
.
initialScrollOffset
:
0.0
,
Axis
scrollDirection:
Axis
.
vertical
,
EdgeInsets
padding
,
double
initialScrollOffset:
0.0
,
bool
shrinkWrap:
false
,
@required
double
maxCrossAxisExtent
,
double
mainAxisSpacing:
0.0
,
double
crossAxisSpacing:
0.0
,
double
childAspectRatio:
1.0
,
this
.
children
:
const
<
Widget
>[],
List
<
Widget
>
children:
const
<
Widget
>[],
})
:
gridDelegate
=
new
SliverGridDelegateWithMaxCrossAxisExtent
(
maxCrossAxisExtent:
maxCrossAxisExtent
,
mainAxisSpacing:
mainAxisSpacing
,
crossAxisSpacing:
crossAxisSpacing
,
childAspectRatio:
childAspectRatio
,
),
super
(
key:
key
);
final
EdgeInsets
padding
;
final
Axis
scrollDirection
;
final
double
initialScrollOffset
;
),
super
(
key:
key
,
scrollDirection:
scrollDirection
,
padding:
padding
,
shrinkWrap:
shrinkWrap
,
children:
children
);
final
SliverGridDelegate
gridDelegate
;
final
List
<
Widget
>
children
;
@override
Widget
build
(
BuildContext
context
)
{
final
SliverChildListDelegate
delegate
=
new
SliverChildListDelegate
(
children
);
Widget
sliver
=
new
SliverGrid
(
delegate:
delegate
,
Widget
buildChildLayout
(
BuildContext
context
)
{
return
new
SliverGrid
(
delegate:
childrenDelegate
,
gridDelegate:
gridDelegate
,
);
if
(
padding
!=
null
)
sliver
=
new
SliverPadding
(
padding:
padding
,
child:
sliver
);
return
new
ScrollableViewport2
(
axisDirection:
_getDirection
(
context
,
scrollDirection
),
initialScrollOffset:
initialScrollOffset
,
slivers:
<
Widget
>[
sliver
],
);
}
}
packages/flutter/lib/src/widgets/scrollable.dart
View file @
5928d221
...
...
@@ -396,64 +396,6 @@ class ScrollConfiguration2 extends InheritedWidget {
}
}
class
ScrollableViewport2
extends
StatelessWidget
{
ScrollableViewport2
({
Key
key
,
this
.
initialScrollOffset
:
0.0
,
this
.
axisDirection
:
AxisDirection
.
down
,
this
.
anchor
:
0.0
,
this
.
center
,
this
.
scrollBehavior
,
this
.
slivers
:
const
<
Widget
>[],
})
{
assert
(
slivers
!=
null
);
}
final
double
initialScrollOffset
;
final
AxisDirection
axisDirection
;
final
double
anchor
;
final
Key
center
;
final
ScrollBehavior2
scrollBehavior
;
final
List
<
Widget
>
slivers
;
Axis
get
axis
=>
axisDirectionToAxis
(
axisDirection
);
@override
Widget
build
(
BuildContext
context
)
{
return
new
Scrollable2
(
initialScrollOffset:
initialScrollOffset
,
axisDirection:
axisDirection
,
scrollBehavior:
scrollBehavior
,
viewportBuilder:
(
BuildContext
context
,
ViewportOffset
offset
)
{
return
new
Viewport2
(
axisDirection:
axisDirection
,
anchor:
anchor
,
offset:
offset
,
center:
center
,
slivers:
slivers
,
);
}
);
}
@override
void
debugFillDescription
(
List
<
String
>
description
)
{
super
.
debugFillDescription
(
description
);
description
.
add
(
'
$axisDirection
'
);
if
(
anchor
!=
0.0
)
description
.
add
(
'anchor:
${anchor.toStringAsFixed(1)}
'
);
if
(
initialScrollOffset
!=
0.0
)
description
.
add
(
'initialScrollOffset:
${initialScrollOffset.toStringAsFixed(1)}
'
);
if
(
center
!=
null
)
description
.
add
(
'center:
$center
'
);
}
}
typedef
Widget
ViewportBuilder
(
BuildContext
context
,
ViewportOffset
position
);
class
Scrollable2
extends
StatefulWidget
{
...
...
packages/flutter/lib/src/widgets/single_child_scroll_view.dart
View file @
5928d221
...
...
@@ -10,10 +10,18 @@ import 'basic.dart';
import
'framework.dart'
;
import
'scrollable.dart'
;
// ///
// /// The viewport will shrink-wrap the child in both axes.
// ///
// /// See also:
// /// * [ScrollView], which handles multiple children in a scrolling list.
// /// * [ScrollGrid], which handles multiple children in a scrolling grid.
// /// * [Scrollable2], which handles arbitrary scrolling effects.
class
SingleChildScrollView
extends
StatelessWidget
{
SingleChildScrollView
({
Key
key
,
this
.
scrollDirection
:
Axis
.
vertical
,
this
.
padding
,
this
.
initialScrollOffset
:
0.0
,
this
.
child
,
})
:
super
(
key:
key
)
{
...
...
@@ -23,6 +31,8 @@ class SingleChildScrollView extends StatelessWidget {
final
Axis
scrollDirection
;
final
EdgeInsets
padding
;
final
double
initialScrollOffset
;
final
Widget
child
;
...
...
@@ -41,6 +51,9 @@ class SingleChildScrollView extends StatelessWidget {
@override
Widget
build
(
BuildContext
context
)
{
final
AxisDirection
axisDirection
=
_getDirection
(
context
);
Widget
contents
=
child
;
if
(
padding
!=
null
)
contents
=
new
Padding
(
padding:
padding
,
child:
contents
);
return
new
Scrollable2
(
axisDirection:
axisDirection
,
initialScrollOffset:
initialScrollOffset
,
...
...
@@ -49,7 +62,7 @@ class SingleChildScrollView extends StatelessWidget {
key:
key
,
axisDirection:
axisDirection
,
offset:
offset
,
child:
c
hild
,
child:
c
ontents
,
);
},
);
...
...
packages/flutter/lib/src/widgets/viewport.dart
View file @
5928d221
...
...
@@ -98,3 +98,39 @@ class Viewport2Element extends MultiChildRenderObjectElement {
}
}
}
class
ShrinkWrappingViewport
extends
MultiChildRenderObjectWidget
{
ShrinkWrappingViewport
({
Key
key
,
this
.
axisDirection
:
AxisDirection
.
down
,
@required
this
.
offset
,
List
<
Widget
>
slivers:
const
<
Widget
>[],
})
:
super
(
key:
key
,
children:
slivers
)
{
assert
(
offset
!=
null
);
}
final
AxisDirection
axisDirection
;
final
ViewportOffset
offset
;
@override
RenderShrinkWrappingViewport
createRenderObject
(
BuildContext
context
)
{
return
new
RenderShrinkWrappingViewport
(
axisDirection:
axisDirection
,
offset:
offset
,
);
}
@override
void
updateRenderObject
(
BuildContext
context
,
RenderShrinkWrappingViewport
renderObject
)
{
renderObject
..
axisDirection
=
axisDirection
..
offset
=
offset
;
}
@override
void
debugFillDescription
(
List
<
String
>
description
)
{
super
.
debugFillDescription
(
description
);
description
.
add
(
'
$axisDirection
'
);
description
.
add
(
'offset:
$offset
'
);
}
}
packages/flutter/test/material/stepper_test.dart
View file @
5928d221
...
...
@@ -34,7 +34,6 @@ void main() {
)
)
);
await
tester
.
tap
(
find
.
text
(
'Step 2'
));
expect
(
index
,
1
);
});
...
...
@@ -277,8 +276,8 @@ void main() {
)
);
Scrollable
State
scrollableState
=
tester
.
firstState
(
find
.
byType
(
Scrollable
));
expect
(
scrollableState
.
scrollOffset
,
0.0
);
Scrollable
2State
scrollableState
=
tester
.
firstState
(
find
.
byType
(
Scrollable2
));
expect
(
scrollableState
.
position
.
pixels
,
0.0
);
await
tester
.
tap
(
find
.
text
(
'Step 3'
));
await
tester
.
pumpWidget
(
...
...
@@ -313,8 +312,10 @@ void main() {
);
await
tester
.
pump
(
const
Duration
(
milliseconds:
100
));
expect
(
scrollableState
.
scrollOffset
,
greaterThan
(
0.0
));
});
expect
(
scrollableState
.
position
.
pixels
,
greaterThan
(
0.0
));
},
skip:
Scrollable
==
Scrollable
&&
ScrollableViewport
==
ScrollableViewport
&&
Block
==
Block
);
// TODO(abarth): re-enable when ensureVisible is implemented
testWidgets
(
'Stepper index test'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
...
...
packages/flutter/test/rendering/rendering_tester.dart
View file @
5928d221
...
...
@@ -134,4 +134,7 @@ class RenderSizedBox extends RenderBox {
@override
void
performLayout
()
{
}
@override
bool
hitTestSelf
(
Point
position
)
=>
true
;
}
packages/flutter/test/rendering/slivers_test.dart
View file @
5928d221
...
...
@@ -40,6 +40,12 @@ void main() {
expect
(
d
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
600.0
));
expect
(
e
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
600.0
));
expect
(
a
.
localToGlobal
(
const
Point
(
800.0
,
400.0
)),
const
Point
(
800.0
,
400.0
));
expect
(
b
.
localToGlobal
(
const
Point
(
800.0
,
400.0
)),
const
Point
(
800.0
,
800.0
));
expect
(
c
.
localToGlobal
(
const
Point
(
800.0
,
400.0
)),
const
Point
(
800.0
,
1000.0
));
expect
(
d
.
localToGlobal
(
const
Point
(
800.0
,
400.0
)),
const
Point
(
800.0
,
1000.0
));
expect
(
e
.
localToGlobal
(
const
Point
(
800.0
,
400.0
)),
const
Point
(
800.0
,
1000.0
));
root
.
offset
=
new
ViewportOffset
.
fixed
(
200.0
);
pumpFrame
();
expect
(
a
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
-
200.0
));
...
...
@@ -63,6 +69,10 @@ void main() {
expect
(
c
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
-
100.0
));
expect
(
d
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
300.0
));
expect
(
e
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
600.0
));
HitTestResult
result
=
new
HitTestResult
();
root
.
hitTest
(
result
,
position:
const
Point
(
130.0
,
150.0
));
expect
(
result
.
path
.
first
.
target
,
equals
(
c
));
});
test
(
'RenderViewport2 basic test - up'
,
()
{
...
...
@@ -112,6 +122,10 @@ void main() {
expect
(
c
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
300.0
));
expect
(
d
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
-
100.0
));
expect
(
e
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
-
400.0
));
HitTestResult
result
=
new
HitTestResult
();
root
.
hitTest
(
result
,
position:
const
Point
(
150.0
,
350.0
));
expect
(
result
.
path
.
first
.
target
,
equals
(
c
));
});
test
(
'RenderViewport2 basic test - right'
,
()
{
...
...
@@ -161,6 +175,10 @@ void main() {
expect
(
c
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(-
100.0
,
0.0
));
expect
(
d
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
300.0
,
0.0
));
expect
(
e
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
700.0
,
0.0
));
HitTestResult
result
=
new
HitTestResult
();
root
.
hitTest
(
result
,
position:
const
Point
(
150.0
,
450.0
));
expect
(
result
.
path
.
first
.
target
,
equals
(
c
));
});
test
(
'RenderViewport2 basic test - left'
,
()
{
...
...
@@ -210,12 +228,278 @@ void main() {
expect
(
c
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
500.0
,
0.0
));
expect
(
d
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
100.0
,
0.0
));
expect
(
e
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(-
300.0
,
0.0
));
HitTestResult
result
=
new
HitTestResult
();
root
.
hitTest
(
result
,
position:
const
Point
(
550.0
,
150.0
));
expect
(
result
.
path
.
first
.
target
,
equals
(
c
));
});
// TODO(ianh): test anchor
// TODO(ianh): test offset
// TODO(ianh): test center
// TODO(ianh): test hit testing
// TODO(ianh): test semantics
test
(
'RenderShrinkWrappingViewport basic test - no children'
,
()
{
RenderShrinkWrappingViewport
root
=
new
RenderShrinkWrappingViewport
(
offset:
new
ViewportOffset
.
zero
(),
);
layout
(
root
);
root
.
offset
=
new
ViewportOffset
.
fixed
(
900.0
);
pumpFrame
();
});
test
(
'RenderShrinkWrappingViewport basic test - down'
,
()
{
RenderBox
a
,
b
,
c
,
d
,
e
;
RenderShrinkWrappingViewport
root
=
new
RenderShrinkWrappingViewport
(
offset:
new
ViewportOffset
.
zero
(),
children:
<
RenderSliver
>[
new
RenderSliverToBoxAdapter
(
child:
a
=
new
RenderSizedBox
(
const
Size
(
100.0
,
400.0
))),
new
RenderSliverToBoxAdapter
(
child:
b
=
new
RenderSizedBox
(
const
Size
(
100.0
,
400.0
))),
new
RenderSliverToBoxAdapter
(
child:
c
=
new
RenderSizedBox
(
const
Size
(
100.0
,
400.0
))),
new
RenderSliverToBoxAdapter
(
child:
d
=
new
RenderSizedBox
(
const
Size
(
100.0
,
400.0
))),
new
RenderSliverToBoxAdapter
(
child:
e
=
new
RenderSizedBox
(
const
Size
(
100.0
,
400.0
))),
],
);
layout
(
root
);
expect
(
root
.
size
.
width
,
equals
(
800.0
));
expect
(
root
.
size
.
height
,
equals
(
600.0
));
expect
(
a
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
0.0
));
expect
(
b
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
400.0
));
expect
(
c
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
600.0
));
expect
(
d
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
600.0
));
expect
(
e
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
600.0
));
expect
(
a
.
localToGlobal
(
const
Point
(
800.0
,
400.0
)),
const
Point
(
800.0
,
400.0
));
expect
(
b
.
localToGlobal
(
const
Point
(
800.0
,
400.0
)),
const
Point
(
800.0
,
800.0
));
expect
(
c
.
localToGlobal
(
const
Point
(
800.0
,
400.0
)),
const
Point
(
800.0
,
1000.0
));
expect
(
d
.
localToGlobal
(
const
Point
(
800.0
,
400.0
)),
const
Point
(
800.0
,
1000.0
));
expect
(
e
.
localToGlobal
(
const
Point
(
800.0
,
400.0
)),
const
Point
(
800.0
,
1000.0
));
root
.
offset
=
new
ViewportOffset
.
fixed
(
200.0
);
pumpFrame
();
expect
(
a
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
-
200.0
));
expect
(
b
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
200.0
));
expect
(
c
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
600.0
));
expect
(
d
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
600.0
));
expect
(
e
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
600.0
));
root
.
offset
=
new
ViewportOffset
.
fixed
(
600.0
);
pumpFrame
();
expect
(
a
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
-
600.0
));
expect
(
b
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
-
200.0
));
expect
(
c
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
200.0
));
expect
(
d
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
600.0
));
expect
(
e
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
600.0
));
root
.
offset
=
new
ViewportOffset
.
fixed
(
900.0
);
pumpFrame
();
expect
(
a
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
-
900.0
));
expect
(
b
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
-
500.0
));
expect
(
c
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
-
100.0
));
expect
(
d
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
300.0
));
expect
(
e
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
600.0
));
HitTestResult
result
=
new
HitTestResult
();
root
.
hitTest
(
result
,
position:
const
Point
(
130.0
,
150.0
));
expect
(
result
.
path
.
first
.
target
,
equals
(
c
));
});
test
(
'RenderShrinkWrappingViewport basic test - up'
,
()
{
RenderBox
a
,
b
,
c
,
d
,
e
;
RenderShrinkWrappingViewport
root
=
new
RenderShrinkWrappingViewport
(
axisDirection:
AxisDirection
.
up
,
offset:
new
ViewportOffset
.
zero
(),
children:
<
RenderSliver
>[
new
RenderSliverToBoxAdapter
(
child:
a
=
new
RenderSizedBox
(
const
Size
(
100.0
,
400.0
))),
new
RenderSliverToBoxAdapter
(
child:
b
=
new
RenderSizedBox
(
const
Size
(
100.0
,
400.0
))),
new
RenderSliverToBoxAdapter
(
child:
c
=
new
RenderSizedBox
(
const
Size
(
100.0
,
400.0
))),
new
RenderSliverToBoxAdapter
(
child:
d
=
new
RenderSizedBox
(
const
Size
(
100.0
,
400.0
))),
new
RenderSliverToBoxAdapter
(
child:
e
=
new
RenderSizedBox
(
const
Size
(
100.0
,
400.0
))),
],
);
layout
(
root
);
expect
(
root
.
size
.
width
,
equals
(
800.0
));
expect
(
root
.
size
.
height
,
equals
(
600.0
));
expect
(
a
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
200.0
));
expect
(
b
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
-
200.0
));
expect
(
c
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
-
400.0
));
expect
(
d
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
-
400.0
));
expect
(
e
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
-
400.0
));
root
.
offset
=
new
ViewportOffset
.
fixed
(
200.0
);
pumpFrame
();
expect
(
a
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
400.0
));
expect
(
b
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
0.0
));
expect
(
c
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
-
400.0
));
expect
(
d
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
-
400.0
));
expect
(
e
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
-
400.0
));
root
.
offset
=
new
ViewportOffset
.
fixed
(
600.0
);
pumpFrame
();
expect
(
a
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
800.0
));
expect
(
b
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
400.0
));
expect
(
c
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
0.0
));
expect
(
d
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
-
400.0
));
expect
(
e
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
-
400.0
));
root
.
offset
=
new
ViewportOffset
.
fixed
(
900.0
);
pumpFrame
();
expect
(
a
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
1100.0
));
expect
(
b
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
700.0
));
expect
(
c
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
300.0
));
expect
(
d
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
-
100.0
));
expect
(
e
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
-
400.0
));
HitTestResult
result
=
new
HitTestResult
();
root
.
hitTest
(
result
,
position:
const
Point
(
150.0
,
350.0
));
expect
(
result
.
path
.
first
.
target
,
equals
(
c
));
});
test
(
'RenderShrinkWrappingViewport basic test - right'
,
()
{
RenderBox
a
,
b
,
c
,
d
,
e
;
RenderShrinkWrappingViewport
root
=
new
RenderShrinkWrappingViewport
(
axisDirection:
AxisDirection
.
right
,
offset:
new
ViewportOffset
.
zero
(),
children:
<
RenderSliver
>[
new
RenderSliverToBoxAdapter
(
child:
a
=
new
RenderSizedBox
(
const
Size
(
400.0
,
100.0
))),
new
RenderSliverToBoxAdapter
(
child:
b
=
new
RenderSizedBox
(
const
Size
(
400.0
,
100.0
))),
new
RenderSliverToBoxAdapter
(
child:
c
=
new
RenderSizedBox
(
const
Size
(
400.0
,
100.0
))),
new
RenderSliverToBoxAdapter
(
child:
d
=
new
RenderSizedBox
(
const
Size
(
400.0
,
100.0
))),
new
RenderSliverToBoxAdapter
(
child:
e
=
new
RenderSizedBox
(
const
Size
(
400.0
,
100.0
))),
],
);
layout
(
root
);
expect
(
root
.
size
.
width
,
equals
(
800.0
));
expect
(
root
.
size
.
height
,
equals
(
600.0
));
expect
(
a
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
0.0
));
expect
(
b
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
400.0
,
0.0
));
expect
(
c
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
800.0
,
0.0
));
expect
(
d
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
800.0
,
0.0
));
expect
(
e
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
800.0
,
0.0
));
root
.
offset
=
new
ViewportOffset
.
fixed
(
200.0
);
pumpFrame
();
expect
(
a
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(-
200.0
,
0.0
));
expect
(
b
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
200.0
,
0.0
));
expect
(
c
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
600.0
,
0.0
));
expect
(
d
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
800.0
,
0.0
));
expect
(
e
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
800.0
,
0.0
));
root
.
offset
=
new
ViewportOffset
.
fixed
(
600.0
);
pumpFrame
();
expect
(
a
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(-
600.0
,
0.0
));
expect
(
b
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(-
200.0
,
0.0
));
expect
(
c
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
200.0
,
0.0
));
expect
(
d
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
600.0
,
0.0
));
expect
(
e
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
800.0
,
0.0
));
root
.
offset
=
new
ViewportOffset
.
fixed
(
900.0
);
pumpFrame
();
expect
(
a
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(-
900.0
,
0.0
));
expect
(
b
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(-
500.0
,
0.0
));
expect
(
c
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(-
100.0
,
0.0
));
expect
(
d
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
300.0
,
0.0
));
expect
(
e
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
700.0
,
0.0
));
HitTestResult
result
=
new
HitTestResult
();
root
.
hitTest
(
result
,
position:
const
Point
(
150.0
,
450.0
));
expect
(
result
.
path
.
first
.
target
,
equals
(
c
));
});
test
(
'RenderShrinkWrappingViewport basic test - left'
,
()
{
RenderBox
a
,
b
,
c
,
d
,
e
;
RenderShrinkWrappingViewport
root
=
new
RenderShrinkWrappingViewport
(
axisDirection:
AxisDirection
.
left
,
offset:
new
ViewportOffset
.
zero
(),
children:
<
RenderSliver
>[
new
RenderSliverToBoxAdapter
(
child:
a
=
new
RenderSizedBox
(
const
Size
(
400.0
,
100.0
))),
new
RenderSliverToBoxAdapter
(
child:
b
=
new
RenderSizedBox
(
const
Size
(
400.0
,
100.0
))),
new
RenderSliverToBoxAdapter
(
child:
c
=
new
RenderSizedBox
(
const
Size
(
400.0
,
100.0
))),
new
RenderSliverToBoxAdapter
(
child:
d
=
new
RenderSizedBox
(
const
Size
(
400.0
,
100.0
))),
new
RenderSliverToBoxAdapter
(
child:
e
=
new
RenderSizedBox
(
const
Size
(
400.0
,
100.0
))),
],
);
layout
(
root
);
expect
(
root
.
size
.
width
,
equals
(
800.0
));
expect
(
root
.
size
.
height
,
equals
(
600.0
));
expect
(
a
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
400.0
,
0.0
));
expect
(
b
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
0.0
,
0.0
));
expect
(
c
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(-
400.0
,
0.0
));
expect
(
d
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(-
400.0
,
0.0
));
expect
(
e
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(-
400.0
,
0.0
));
root
.
offset
=
new
ViewportOffset
.
fixed
(
200.0
);
pumpFrame
();
expect
(
a
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
600.0
,
0.0
));
expect
(
b
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
200.0
,
0.0
));
expect
(
c
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(-
200.0
,
0.0
));
expect
(
d
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(-
400.0
,
0.0
));
expect
(
e
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(-
400.0
,
0.0
));
root
.
offset
=
new
ViewportOffset
.
fixed
(
600.0
);
pumpFrame
();
expect
(
a
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
1000.0
,
0.0
));
expect
(
b
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
600.0
,
0.0
));
expect
(
c
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
200.0
,
0.0
));
expect
(
d
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(-
200.0
,
0.0
));
expect
(
e
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(-
400.0
,
0.0
));
root
.
offset
=
new
ViewportOffset
.
fixed
(
900.0
);
pumpFrame
();
expect
(
a
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
1300.0
,
0.0
));
expect
(
b
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
900.0
,
0.0
));
expect
(
c
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
500.0
,
0.0
));
expect
(
d
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(
100.0
,
0.0
));
expect
(
e
.
localToGlobal
(
const
Point
(
0.0
,
0.0
)),
const
Point
(-
300.0
,
0.0
));
HitTestResult
result
=
new
HitTestResult
();
root
.
hitTest
(
result
,
position:
const
Point
(
550.0
,
150.0
));
expect
(
result
.
path
.
first
.
target
,
equals
(
c
));
});
test
(
'RenderShrinkWrappingViewport shrinkwrap test - 1 child'
,
()
{
RenderBox
child
;
RenderBox
root
=
new
RenderPositionedBox
(
child:
child
=
new
RenderShrinkWrappingViewport
(
axisDirection:
AxisDirection
.
left
,
offset:
new
ViewportOffset
.
fixed
(
200.0
),
children:
<
RenderSliver
>[
new
RenderSliverToBoxAdapter
(
child:
new
RenderSizedBox
(
const
Size
(
400.0
,
100.0
))),
],
),
);
layout
(
root
);
expect
(
root
.
size
.
width
,
equals
(
800.0
));
expect
(
root
.
size
.
height
,
equals
(
600.0
));
expect
(
child
.
size
.
width
,
equals
(
400.0
));
expect
(
child
.
size
.
height
,
equals
(
600.0
));
});
test
(
'RenderShrinkWrappingViewport shrinkwrap test - 2 children'
,
()
{
RenderBox
child
;
RenderBox
root
=
new
RenderPositionedBox
(
child:
child
=
new
RenderShrinkWrappingViewport
(
axisDirection:
AxisDirection
.
right
,
offset:
new
ViewportOffset
.
fixed
(
200.0
),
children:
<
RenderSliver
>[
new
RenderSliverToBoxAdapter
(
child:
new
RenderSizedBox
(
const
Size
(
300.0
,
100.0
))),
new
RenderSliverToBoxAdapter
(
child:
new
RenderSizedBox
(
const
Size
(
150.0
,
100.0
))),
],
),
);
layout
(
root
);
expect
(
root
.
size
.
width
,
equals
(
800.0
));
expect
(
root
.
size
.
height
,
equals
(
600.0
));
expect
(
child
.
size
.
width
,
equals
(
450.0
));
expect
(
child
.
size
.
height
,
equals
(
600.0
));
});
}
packages/flutter/test/widgets/block_test.dart
View file @
5928d221
...
...
@@ -6,6 +6,8 @@ import 'package:flutter_test/flutter_test.dart';
import
'package:flutter/rendering.dart'
;
import
'package:flutter/widgets.dart'
;
import
'test_widgets.dart'
;
final
Key
blockKey
=
new
Key
(
'test'
);
void
main
(
)
{
...
...
@@ -130,7 +132,7 @@ void main() {
new
Container
(),
]);
await
tester
.
pumpWidget
(
new
ScrollableViewport2
(
await
tester
.
pumpWidget
(
new
TestScrollable
(
slivers:
<
Widget
>[
new
SliverBlock
(
delegate:
delegate
,
...
...
packages/flutter/test/widgets/overscroll_indicator_test.dart
View file @
5928d221
...
...
@@ -9,6 +9,7 @@ import 'package:flutter/widgets.dart';
import
'package:flutter/rendering.dart'
;
import
'../rendering/mock_canvas.dart'
;
import
'test_widgets.dart'
;
final
Matcher
doesNotOverscroll
=
isNot
(
paints
..
circle
());
...
...
@@ -24,7 +25,7 @@ Future<Null> slowDrag(WidgetTester tester, Point start, Offset offset) async {
void
main
(
)
{
testWidgets
(
'Overscroll indicator color'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
new
ScrollableViewport2
(
new
TestScrollable
(
slivers:
<
Widget
>[
new
SliverToBoxAdapter
(
child:
new
SizedBox
(
height:
2000.0
)),
],
...
...
@@ -57,7 +58,7 @@ void main() {
testWidgets
(
'Overscroll indicator changes side when you drag on the other side'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
new
ScrollableViewport2
(
new
TestScrollable
(
slivers:
<
Widget
>[
new
SliverToBoxAdapter
(
child:
new
SizedBox
(
height:
2000.0
)),
],
...
...
@@ -92,7 +93,7 @@ void main() {
testWidgets
(
'Overscroll indicator changes side when you shift sides'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
new
ScrollableViewport2
(
new
TestScrollable
(
slivers:
<
Widget
>[
new
SliverToBoxAdapter
(
child:
new
SizedBox
(
height:
2000.0
)),
],
...
...
@@ -125,7 +126,7 @@ void main() {
group
(
'Flipping direction of scrollable doesn
\'
t change overscroll behavior'
,
()
{
testWidgets
(
'down'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
new
ScrollableViewport2
(
new
TestScrollable
(
axisDirection:
AxisDirection
.
down
,
slivers:
<
Widget
>[
new
SliverToBoxAdapter
(
child:
new
SizedBox
(
height:
20.0
)),
...
...
@@ -142,7 +143,7 @@ void main() {
testWidgets
(
'up'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
new
ScrollableViewport2
(
new
TestScrollable
(
axisDirection:
AxisDirection
.
up
,
slivers:
<
Widget
>[
new
SliverToBoxAdapter
(
child:
new
SizedBox
(
height:
20.0
)),
...
...
@@ -160,7 +161,7 @@ void main() {
testWidgets
(
'Overscroll in both directions'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
new
ScrollableViewport2
(
new
TestScrollable
(
axisDirection:
AxisDirection
.
down
,
slivers:
<
Widget
>[
new
SliverToBoxAdapter
(
child:
new
SizedBox
(
height:
20.0
)),
...
...
@@ -180,7 +181,7 @@ void main() {
testWidgets
(
'Overscroll horizontally'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
new
ScrollableViewport2
(
new
TestScrollable
(
axisDirection:
AxisDirection
.
right
,
slivers:
<
Widget
>[
new
SliverToBoxAdapter
(
child:
new
SizedBox
(
height:
20.0
)),
...
...
@@ -203,7 +204,7 @@ void main() {
RenderObject
painter
;
await
tester
.
pumpWidget
(
new
ScrollableViewport2
(
new
TestScrollable
(
axisDirection:
AxisDirection
.
left
,
scrollBehavior:
new
TestScrollBehavior1
(),
slivers:
<
Widget
>[
...
...
@@ -218,7 +219,7 @@ void main() {
await
tester
.
pumpUntilNoTransientCallbacks
(
const
Duration
(
seconds:
1
));
await
tester
.
pumpWidget
(
new
ScrollableViewport2
(
new
TestScrollable
(
axisDirection:
AxisDirection
.
right
,
scrollBehavior:
new
TestScrollBehavior2
(),
slivers:
<
Widget
>[
...
...
packages/flutter/test/widgets/scroll_grid_test.dart
View file @
5928d221
...
...
@@ -303,4 +303,7 @@ void main() {
expect
(
tester
.
getSize
(
find
.
text
(
'3'
)),
equals
(
const
Size
(
400.0
,
400.0
)));
expect
(
find
.
text
(
'4'
),
findsNothing
);
});
// TODO(ianh): can you tap a grid cell that is slightly off the bottom of the screen?
// (try it with the flutter_gallery Grid demo)
}
packages/flutter/test/widgets/scrollable_custom_scroll_behavior_test.dart
View file @
5928d221
...
...
@@ -6,6 +6,8 @@ import 'package:flutter_test/flutter_test.dart';
import
'package:flutter/material.dart'
;
import
'package:flutter/rendering.dart'
;
import
'test_widgets.dart'
;
class
TestScrollPosition
extends
ScrollPosition
{
TestScrollPosition
(
this
.
extentMultiplier
,
...
...
@@ -88,7 +90,7 @@ class TestScrollBehavior extends ScrollBehavior2 {
void
main
(
)
{
testWidgets
(
'Changing the scroll behavior dynamically'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
new
ScrollableViewport2
(
await
tester
.
pumpWidget
(
new
TestScrollable
(
scrollBehavior:
new
TestScrollBehavior
(
1.0
),
slivers:
<
Widget
>[
new
SliverToBoxAdapter
(
child:
new
SizedBox
(
height:
2000.0
)),
...
...
@@ -97,7 +99,7 @@ void main() {
Scrollable2State
state
=
tester
.
state
(
find
.
byType
(
Scrollable2
));
expect
(
state
.
position
.
getMetrics
().
extentInside
,
1.0
);
await
tester
.
pumpWidget
(
new
ScrollableViewport2
(
await
tester
.
pumpWidget
(
new
TestScrollable
(
scrollBehavior:
new
TestScrollBehavior
(
2.0
),
slivers:
<
Widget
>[
new
SliverToBoxAdapter
(
child:
new
SizedBox
(
height:
2000.0
)),
...
...
packages/flutter/test/widgets/scrollable_test.dart
View file @
5928d221
...
...
@@ -6,12 +6,14 @@ import 'package:flutter_test/flutter_test.dart';
import
'package:flutter/material.dart'
;
import
'package:flutter/rendering.dart'
;
import
'test_widgets.dart'
;
Future
<
Null
>
pumpTest
(
WidgetTester
tester
,
TargetPlatform
platform
)
async
{
await
tester
.
pumpWidget
(
new
MaterialApp
(
theme:
new
ThemeData
(
platform:
platform
,
),
home:
new
ScrollableViewport2
(
home:
new
TestScrollable
(
slivers:
<
Widget
>[
new
SliverToBoxAdapter
(
child:
new
SizedBox
(
height:
2000.0
)),
],
...
...
packages/flutter/test/widgets/sliver_fill_remaining_test.dart
View file @
5928d221
...
...
@@ -5,6 +5,8 @@
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter/widgets.dart'
;
import
'test_widgets.dart'
;
void
main
(
)
{
testWidgets
(
'SliverFillRemaining control test'
,
(
WidgetTester
tester
)
async
{
List
<
Widget
>
children
=
new
List
<
Widget
>.
generate
(
20
,
(
int
i
)
{
...
...
@@ -12,7 +14,7 @@ void main() {
});
await
tester
.
pumpWidget
(
new
ScrollableViewport2
(
new
TestScrollable
(
slivers:
<
Widget
>[
new
SliverFill
(
delegate:
new
SliverChildListDelegate
(
children
),
...
...
@@ -28,7 +30,7 @@ void main() {
expect
(
find
.
text
(
'1'
),
findsNothing
);
expect
(
find
.
text
(
'2'
),
findsNothing
);
await
tester
.
scroll
(
find
.
byType
(
Scrollable
Viewport
2
),
const
Offset
(
0.0
,
-
700.0
));
await
tester
.
scroll
(
find
.
byType
(
Scrollable2
),
const
Offset
(
0.0
,
-
700.0
));
await
tester
.
pump
();
expect
(
find
.
text
(
'0'
),
findsNothing
);
...
...
@@ -37,7 +39,7 @@ void main() {
expect
(
find
.
text
(
'3'
),
findsNothing
);
expect
(
find
.
text
(
'4'
),
findsNothing
);
await
tester
.
scroll
(
find
.
byType
(
Scrollable
Viewport
2
),
const
Offset
(
0.0
,
200.0
));
await
tester
.
scroll
(
find
.
byType
(
Scrollable2
),
const
Offset
(
0.0
,
200.0
));
await
tester
.
pump
();
expect
(
find
.
text
(
'0'
),
findsOneWidget
);
...
...
packages/flutter/test/widgets/slivers_appbar_floating_test.dart
View file @
5928d221
...
...
@@ -6,6 +6,8 @@ import 'package:flutter_test/flutter_test.dart';
import
'package:flutter/rendering.dart'
;
import
'package:flutter/widgets.dart'
;
import
'test_widgets.dart'
;
void
verifyPaintPosition
(
GlobalKey
key
,
Offset
ideal
,
bool
visible
)
{
RenderSliver
target
=
key
.
currentContext
.
findRenderObject
();
expect
(
target
.
parent
,
new
isInstanceOf
<
RenderViewport2
>());
...
...
@@ -26,7 +28,7 @@ void main() {
testWidgets
(
'Sliver appbars - floating - scroll offset doesn
\'
t change'
,
(
WidgetTester
tester
)
async
{
const
double
bigHeight
=
1000.0
;
await
tester
.
pumpWidget
(
new
ScrollableViewport2
(
new
TestScrollable
(
axisDirection:
AxisDirection
.
down
,
slivers:
<
Widget
>[
new
BigSliver
(
height:
bigHeight
),
...
...
@@ -54,7 +56,7 @@ void main() {
const
double
bigHeight
=
1000.0
;
GlobalKey
key1
,
key2
,
key3
;
await
tester
.
pumpWidget
(
new
ScrollableViewport2
(
new
TestScrollable
(
axisDirection:
AxisDirection
.
down
,
slivers:
<
Widget
>[
new
BigSliver
(
key:
key1
=
new
GlobalKey
(),
height:
bigHeight
),
...
...
@@ -124,7 +126,7 @@ void main() {
const
double
bigHeight
=
1000.0
;
GlobalKey
key1
,
key2
,
key3
;
await
tester
.
pumpWidget
(
new
ScrollableViewport2
(
new
TestScrollable
(
axisDirection:
AxisDirection
.
down
,
slivers:
<
Widget
>[
new
BigSliver
(
key:
key1
=
new
GlobalKey
(),
height:
bigHeight
),
...
...
@@ -157,7 +159,7 @@ void main() {
const
double
bigHeight
=
1000.0
;
GlobalKey
key1
,
key2
,
key3
;
await
tester
.
pumpWidget
(
new
ScrollableViewport2
(
new
TestScrollable
(
axisDirection:
AxisDirection
.
down
,
slivers:
<
Widget
>[
new
BigSliver
(
key:
key1
=
new
GlobalKey
(),
height:
bigHeight
),
...
...
packages/flutter/test/widgets/slivers_appbar_pinned_test.dart
View file @
5928d221
...
...
@@ -6,6 +6,8 @@ import 'package:flutter_test/flutter_test.dart';
import
'package:flutter/rendering.dart'
;
import
'package:flutter/widgets.dart'
;
import
'test_widgets.dart'
;
void
verifyPaintPosition
(
GlobalKey
key
,
Offset
ideal
,
bool
visible
)
{
RenderSliver
target
=
key
.
currentContext
.
findRenderObject
();
expect
(
target
.
parent
,
new
isInstanceOf
<
RenderViewport2
>());
...
...
@@ -17,7 +19,7 @@ void verifyPaintPosition(GlobalKey key, Offset ideal, bool visible) {
}
void
verifyActualBoxPosition
(
WidgetTester
tester
,
Finder
finder
,
int
index
,
Rect
ideal
)
{
RenderBox
box
=
tester
.
renderObjectList
/*<RenderBox>*/
(
finder
).
elementAt
(
index
);
RenderBox
box
=
tester
.
renderObjectList
<
RenderBox
>
(
finder
).
elementAt
(
index
);
Rect
rect
=
new
Rect
.
fromPoints
(
box
.
localToGlobal
(
Point
.
origin
),
box
.
localToGlobal
(
box
.
size
.
bottomRight
(
Point
.
origin
)));
expect
(
rect
,
equals
(
ideal
));
}
...
...
@@ -27,7 +29,7 @@ void main() {
const
double
bigHeight
=
550.0
;
GlobalKey
key1
,
key2
,
key3
,
key4
,
key5
;
await
tester
.
pumpWidget
(
new
ScrollableViewport2
(
new
TestScrollable
(
axisDirection:
AxisDirection
.
down
,
slivers:
<
Widget
>[
new
BigSliver
(
key:
key1
=
new
GlobalKey
(),
height:
bigHeight
),
...
...
@@ -61,7 +63,7 @@ void main() {
const
double
bigHeight
=
550.0
;
GlobalKey
key1
,
key2
,
key3
,
key4
,
key5
;
await
tester
.
pumpWidget
(
new
ScrollableViewport2
(
new
TestScrollable
(
axisDirection:
AxisDirection
.
down
,
slivers:
<
Widget
>[
new
BigSliver
(
key:
key1
=
new
GlobalKey
(),
height:
bigHeight
),
...
...
@@ -151,7 +153,7 @@ void main() {
const
double
bigHeight
=
650.0
;
GlobalKey
key1
,
key2
,
key3
,
key4
,
key5
;
await
tester
.
pumpWidget
(
new
ScrollableViewport2
(
new
TestScrollable
(
axisDirection:
AxisDirection
.
down
,
slivers:
<
Widget
>[
new
BigSliver
(
key:
key1
=
new
GlobalKey
(),
height:
bigHeight
),
...
...
packages/flutter/test/widgets/slivers_appbar_scrolling_test.dart
View file @
5928d221
...
...
@@ -6,6 +6,8 @@ import 'package:flutter_test/flutter_test.dart';
import
'package:flutter/rendering.dart'
;
import
'package:flutter/widgets.dart'
;
import
'test_widgets.dart'
;
void
verifyPaintPosition
(
GlobalKey
key
,
Offset
ideal
)
{
RenderObject
target
=
key
.
currentContext
.
findRenderObject
();
expect
(
target
.
parent
,
new
isInstanceOf
<
RenderViewport2
>());
...
...
@@ -18,7 +20,7 @@ void main() {
testWidgets
(
'Sliver appbars - scrolling'
,
(
WidgetTester
tester
)
async
{
GlobalKey
key1
,
key2
,
key3
,
key4
,
key5
;
await
tester
.
pumpWidget
(
new
ScrollableViewport2
(
new
TestScrollable
(
axisDirection:
AxisDirection
.
down
,
slivers:
<
Widget
>[
new
BigSliver
(
key:
key1
=
new
GlobalKey
()),
...
...
@@ -52,7 +54,7 @@ void main() {
GlobalKey
key
=
new
GlobalKey
();
TestDelegate
delegate
=
new
TestDelegate
();
await
tester
.
pumpWidget
(
new
ScrollableViewport2
(
new
TestScrollable
(
axisDirection:
AxisDirection
.
down
,
slivers:
<
Widget
>[
new
BigSliver
(),
...
...
@@ -65,7 +67,7 @@ void main() {
AbsoluteScrollPosition
position
=
tester
.
state
<
Scrollable2State
>(
find
.
byType
(
Scrollable2
)).
position
;
position
.
animate
(
to:
RenderBigSliver
.
height
+
delegate
.
maxExtent
-
5.0
,
curve:
Curves
.
linear
,
duration:
const
Duration
(
minutes:
1
));
await
tester
.
pumpUntilNoTransientCallbacks
(
const
Duration
(
milliseconds:
1000
));
RenderBox
box
=
tester
.
renderObject
/*<RenderBox>*/
(
find
.
byType
(
Container
));
RenderBox
box
=
tester
.
renderObject
<
RenderBox
>
(
find
.
byType
(
Container
));
Rect
rect
=
new
Rect
.
fromPoints
(
box
.
localToGlobal
(
Point
.
origin
),
box
.
localToGlobal
(
box
.
size
.
bottomRight
(
Point
.
origin
)));
expect
(
rect
,
equals
(
new
Rect
.
fromLTWH
(
0.0
,
-
195.0
,
800.0
,
200.0
)));
});
...
...
packages/flutter/test/widgets/slivers_evil_test.dart
View file @
5928d221
...
...
@@ -7,6 +7,8 @@ import 'package:flutter/rendering.dart';
import
'package:flutter/physics.dart'
;
import
'package:flutter/material.dart'
;
import
'test_widgets.dart'
;
class
TestSliverAppBarDelegate
extends
SliverAppBarDelegate
{
TestSliverAppBarDelegate
(
this
.
_maxExtent
);
...
...
@@ -74,7 +76,7 @@ void main() {
final
GlobalKey
centerKey
=
new
GlobalKey
();
await
tester
.
pumpWidget
(
new
Scrollbar2
(
child:
new
ScrollableViewport2
(
child:
new
TestScrollable
(
axisDirection:
AxisDirection
.
down
,
center:
centerKey
,
anchor:
0.25
,
...
...
packages/flutter/test/widgets/slivers_protocol_test.dart
View file @
5928d221
...
...
@@ -8,6 +8,8 @@ import 'package:flutter_test/flutter_test.dart';
import
'package:flutter/rendering.dart'
;
import
'package:flutter/widgets.dart'
;
import
'test_widgets.dart'
;
void
verifyPaintPosition
(
GlobalKey
key
,
Offset
ideal
)
{
RenderObject
target
=
key
.
currentContext
.
findRenderObject
();
expect
(
target
.
parent
,
new
isInstanceOf
<
RenderViewport2
>());
...
...
@@ -20,7 +22,7 @@ void main() {
testWidgets
(
'Sliver protocol'
,
(
WidgetTester
tester
)
async
{
GlobalKey
key1
,
key2
,
key3
,
key4
,
key5
;
await
tester
.
pumpWidget
(
new
ScrollableViewport2
(
new
TestScrollable
(
axisDirection:
AxisDirection
.
down
,
slivers:
<
Widget
>[
new
BigSliver
(
key:
key1
=
new
GlobalKey
()),
...
...
packages/flutter/test/widgets/test_widgets.dart
View file @
5928d221
...
...
@@ -3,6 +3,7 @@
// found in the LICENSE file.
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/widgets.dart'
;
final
BoxDecoration
kBoxDecorationA
=
const
BoxDecoration
(
...
...
@@ -56,3 +57,49 @@ class FlipWidgetState extends State<FlipWidget> {
void
flipStatefulWidget
(
WidgetTester
tester
)
{
tester
.
state
<
FlipWidgetState
>(
find
.
byType
(
FlipWidget
)).
flip
();
}
class
TestScrollable
extends
StatelessWidget
{
TestScrollable
({
Key
key
,
this
.
initialScrollOffset
:
0.0
,
this
.
axisDirection
:
AxisDirection
.
down
,
this
.
anchor
:
0.0
,
this
.
center
,
this
.
scrollBehavior
,
this
.
slivers
:
const
<
Widget
>[],
})
{
assert
(
slivers
!=
null
);
}
final
double
initialScrollOffset
;
final
AxisDirection
axisDirection
;
final
double
anchor
;
final
Key
center
;
final
ScrollBehavior2
scrollBehavior
;
final
List
<
Widget
>
slivers
;
Axis
get
axis
=>
axisDirectionToAxis
(
axisDirection
);
@override
Widget
build
(
BuildContext
context
)
{
return
new
Scrollable2
(
initialScrollOffset:
initialScrollOffset
,
axisDirection:
axisDirection
,
scrollBehavior:
scrollBehavior
,
viewportBuilder:
(
BuildContext
context
,
ViewportOffset
offset
)
{
return
new
Viewport2
(
axisDirection:
axisDirection
,
anchor:
anchor
,
offset:
offset
,
center:
center
,
slivers:
slivers
,
);
}
);
}
}
\ No newline at end of file
packages/flutter_test/lib/src/binding.dart
View file @
5928d221
...
...
@@ -18,8 +18,8 @@ import 'package:quiver/time.dart';
import
'package:test/test.dart'
as
test_package
;
import
'package:vector_math/vector_math_64.dart'
;
import
'test_async_utils.dart'
;
import
'stack_manipulation.dart'
;
import
'test_async_utils.dart'
;
/// Phases that can be reached by [WidgetTester.pumpWidget] and
/// [TestWidgetsFlutterBinding.pump].
...
...
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