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
f683abd7
Commit
f683abd7
authored
Jan 24, 2017
by
Ian Hickson
Committed by
GitHub
Jan 24, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Sliver Block (#7618)
parent
2380d854
Changes
11
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
1382 additions
and
7 deletions
+1382
-7
rendering.dart
packages/flutter/lib/rendering.dart
+1
-0
sliver.dart
packages/flutter/lib/src/rendering/sliver.dart
+9
-5
sliver_block.dart
packages/flutter/lib/src/rendering/sliver_block.dart
+613
-0
block.dart
packages/flutter/lib/src/widgets/block.dart
+280
-0
viewport.dart
packages/flutter/lib/src/widgets/viewport.dart
+2
-1
widgets.dart
packages/flutter/lib/widgets.dart
+1
-0
slivers_block_test.dart
packages/flutter/test/rendering/slivers_block_test.dart
+185
-0
slivers_layout_test.dart
packages/flutter/test/rendering/slivers_layout_test.dart
+1
-0
slivers_test.dart
packages/flutter/test/rendering/slivers_test.dart
+7
-1
slivers_block_global_key_test.dart
...s/flutter/test/widgets/slivers_block_global_key_test.dart
+124
-0
slivers_block_test.dart
packages/flutter/test/widgets/slivers_block_test.dart
+159
-0
No files found.
packages/flutter/lib/rendering.dart
View file @
f683abd7
...
@@ -45,6 +45,7 @@ export 'src/rendering/rotated_box.dart';
...
@@ -45,6 +45,7 @@ export 'src/rendering/rotated_box.dart';
export
'src/rendering/semantics.dart'
;
export
'src/rendering/semantics.dart'
;
export
'src/rendering/shifted_box.dart'
;
export
'src/rendering/shifted_box.dart'
;
export
'src/rendering/sliver.dart'
;
export
'src/rendering/sliver.dart'
;
export
'src/rendering/sliver_block.dart'
;
export
'src/rendering/stack.dart'
;
export
'src/rendering/stack.dart'
;
export
'src/rendering/table.dart'
;
export
'src/rendering/table.dart'
;
export
'src/rendering/tweens.dart'
;
export
'src/rendering/tweens.dart'
;
...
...
packages/flutter/lib/src/rendering/sliver.dart
View file @
f683abd7
...
@@ -1145,22 +1145,26 @@ class RenderViewport2 extends RenderBox with ContainerRenderObjectMixin<RenderSl
...
@@ -1145,22 +1145,26 @@ class RenderViewport2 extends RenderBox with ContainerRenderObjectMixin<RenderSl
///
///
/// If the [center] is not specified, then the first child in the `children`
/// If the [center] is not specified, then the first child in the `children`
/// list, if any, is used.
/// list, if any, is used.
///
/// The [offset] must be specified. For testing purposes, consider passing a
/// [new ViewportOffset.zero] or [new ViewportOffset.fixed].
RenderViewport2
({
RenderViewport2
({
AxisDirection
axisDirection:
AxisDirection
.
down
,
AxisDirection
axisDirection:
AxisDirection
.
down
,
double
anchor:
0.0
,
double
anchor:
0.0
,
ViewportOffset
offset
,
@required
ViewportOffset
offset
,
List
<
RenderSliver
>
children
,
List
<
RenderSliver
>
children
,
RenderSliver
center
,
RenderSliver
center
,
})
:
_axisDirection
=
axisDirection
,
})
:
_axisDirection
=
axisDirection
,
_anchor
=
anchor
,
_anchor
=
anchor
,
_offset
=
offset
??
new
ViewportOffset
.
zero
()
,
_offset
=
offset
,
_center
=
center
{
_center
=
center
{
addAll
(
children
);
assert
(
offset
!=
null
);
if
(
center
==
null
&&
firstChild
!=
null
)
_center
=
firstChild
;
assert
(
axisDirection
!=
null
);
assert
(
axisDirection
!=
null
);
assert
(
anchor
!=
null
);
assert
(
anchor
!=
null
);
assert
(
anchor
>=
0.0
&&
anchor
<=
1.0
);
assert
(
anchor
>=
0.0
&&
anchor
<=
1.0
);
addAll
(
children
);
if
(
center
==
null
&&
firstChild
!=
null
)
_center
=
firstChild
;
}
}
AxisDirection
get
axisDirection
=>
_axisDirection
;
AxisDirection
get
axisDirection
=>
_axisDirection
;
...
...
packages/flutter/lib/src/rendering/sliver_block.dart
0 → 100644
View file @
f683abd7
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/foundation.dart'
;
import
'package:flutter/gestures.dart'
;
import
'package:meta/meta.dart'
;
import
'package:vector_math/vector_math_64.dart'
;
import
'box.dart'
;
import
'binding.dart'
;
import
'object.dart'
;
import
'sliver.dart'
;
class
SliverBlockParentData
extends
SliverLogicalParentData
with
ContainerParentDataMixin
<
RenderBox
>
{
int
index
;
@override
String
toString
()
=>
'index=
$index
;
${super.toString()}
'
;
}
// ///
// ///
// /// The contract for adding and removing children from this render object is
// /// more strict than for normal render objects:
// ///
// /// - Children can be removed except during a layout pass if they have already
// /// been laid out during that layout pass.
// /// - Children cannot be added except during a call to [allowAdditionsFor], and
// /// then only if there is no child correspending to that index (or the child
// /// child corresponding to that index was first removed).
// ///
// /// ## Writing a RenderSliverBlock subclass
// ///
// /// There are three methods to override:
// ///
// /// - [createChild], which must create the child for the given index, and then
// /// insert it in the given location in the child list.
// ///
// /// - [removeChild], which is called when the given child is cleaned up,
// /// and which should remove the given child from the child list.
// ///
// /// - [estimateScrollOffsetExtent], which should return the total extent (e.g.
// /// the height, if this is a vertical block) of all the children.
abstract
class
RenderSliverBlock
extends
RenderSliver
with
ContainerRenderObjectMixin
<
RenderBox
,
SliverBlockParentData
>,
RenderSliverHelpers
{
@override
void
setupParentData
(
RenderObject
child
)
{
if
(
child
.
parentData
is
!
SliverBlockParentData
)
child
.
parentData
=
new
SliverBlockParentData
();
}
/// Called during layout when a new child is needed. The child should be
/// inserted into the child list in the appropriate position, after the
/// `after` child (at the start of the list if `after` is null). Its index and
/// scroll offsets will automatically be set appropriately.
///
/// The `index` argument gives the index of the child to show. The first child
/// that will be requested will have index zero, and this should be the child
/// that is aligned with the zero scroll offset. Subsequent requests will be
/// for indices adjacent to previously requested indices. It is possible for
/// negative indices to be requested. For example: if the user scrolls from
/// child 0 to child 10, and then those children get much smaller, and then
/// the user scrolls back up again, this method will eventually be asked to
/// produce a child for index -1.
///
/// If no child corresponds to `index`, then do nothing.
///
/// Which child is indicated by index zero depends on the [GrowthDirection]
/// specified in the [constraints]. For example if the children are the
/// alphabet, then if [constraints.growthDirection] is
/// [GrowthDirection.forward] then index zero is A, and index 25 is Z. On the
/// other hand if [constraints.growthDirection] is [GrowthDirection.reverse]
/// then index zero is Z, and index 25 is A.
///
/// During a call to [createChild] it is valid to remove other children from
/// the [RenderSliverBlock] object if they were not created during this frame
/// and have not yet been updated during this frame. It is not valid to add
/// any children to this render object.
@protected
void
createChild
(
int
index
,
{
@required
RenderBox
after
});
/// Remove the given child from the child list.
///
/// Called by [collectGarbage], which itself is called from [performLayout],
/// after the layout algorithm has finished and the non-visible children are
/// to be removed.
///
/// The default implementation calls [remove], which removes the child from
/// the child list.
///
/// The index of the given child can be obtained using the [indexOf] method,
/// which reads it from the [SliverBlockParentData.index] field of the child's
/// [parentData].
@protected
void
removeChild
(
RenderBox
child
)
{
remove
(
child
);
}
int
_currentlyUpdatingChildIndex
;
@protected
void
allowAdditionsFor
(
int
index
,
VoidCallback
callback
)
{
assert
(
_currentlyUpdatingChildIndex
==
null
);
assert
(
index
!=
null
);
_currentlyUpdatingChildIndex
=
index
;
try
{
callback
();
}
finally
{
_currentlyUpdatingChildIndex
=
null
;
}
}
@override
void
adoptChild
(
RenderObject
child
)
{
assert
(
_currentlyUpdatingChildIndex
!=
null
);
super
.
adoptChild
(
child
);
final
SliverBlockParentData
childParentData
=
child
.
parentData
;
childParentData
.
index
=
_currentlyUpdatingChildIndex
;
}
@override
void
insert
(
RenderBox
child
,
{
RenderBox
after
})
{
super
.
insert
(
child
,
after:
after
);
assert
(
firstChild
!=
null
);
assert
(()
{
int
index
=
indexOf
(
firstChild
);
RenderBox
child
=
childAfter
(
firstChild
);
while
(
child
!=
null
)
{
assert
(
indexOf
(
child
)
>
index
);
index
=
indexOf
(
child
);
child
=
childAfter
(
child
);
}
return
true
;
});
}
/// Called to estimate the total scrollable extents of this object.
///
/// Must return the total distance from the start of the child with the
/// earliest possible index to the end of the child with the last possible
/// index.
@protected
double
estimateScrollOffsetExtent
({
int
firstIndex
,
int
lastIndex
,
double
leadingScrollOffset
,
double
trailingScrollOffset
,
});
/// Called during layout to create and add the child with index 0 and scroll
/// offset 0.0.
///
/// Calls [createChild] to actually create and add the child.
///
/// Returns false if createChild did not add any child, otherwise returns
/// true.
///
/// Does not layout the new child.
///
/// When this is called, there are no children, so no children can be removed
/// during the call to createChild. No child should be added during that call
/// either, except for the one that is created and returned by [createChild].
@protected
bool
addInitialChild
()
{
assert
(
_currentlyUpdatingChildIndex
==
null
);
assert
(
firstChild
==
null
);
bool
result
;
invokeLayoutCallback
<
SliverConstraints
>((
SliverConstraints
constraints
)
{
assert
(
constraints
==
this
.
constraints
);
allowAdditionsFor
(
0
,
()
{
createChild
(
0
,
after:
null
);
if
(
firstChild
!=
null
)
{
assert
(
firstChild
==
lastChild
);
assert
(
indexOf
(
firstChild
)
==
0
);
final
SliverBlockParentData
firstChildParentData
=
firstChild
.
parentData
;
firstChildParentData
.
scrollOffset
=
0.0
;
result
=
true
;
}
else
{
result
=
false
;
}
});
});
return
result
;
}
/// Called during layout to create, add, and layout the child before
/// [firstChild].
///
/// Calls [createChild] to actually create and add the child.
///
/// Returns the new child.
///
/// The child that was previously the first child, as well as any subsequent
/// children, may be removed by this call if they have not yet been laid out
/// during this layout pass. No child should be added during that call except
/// for the one that is created and returned by [createChild].
@protected
RenderBox
insertAndLayoutLeadingChild
(
BoxConstraints
childConstraints
)
{
assert
(
_currentlyUpdatingChildIndex
==
null
);
final
int
index
=
indexOf
(
firstChild
)
-
1
;
final
double
endScrollOffset
=
offsetOf
(
firstChild
);
invokeLayoutCallback
<
SliverConstraints
>((
SliverConstraints
constraints
)
{
assert
(
constraints
==
this
.
constraints
);
allowAdditionsFor
(
index
,
()
{
createChild
(
index
,
after:
null
);
});
});
if
(
indexOf
(
firstChild
)
==
index
)
{
firstChild
.
layout
(
childConstraints
,
parentUsesSize:
true
);
SliverBlockParentData
firstChildParentData
=
firstChild
.
parentData
;
firstChildParentData
.
scrollOffset
=
endScrollOffset
-
paintExtentOf
(
firstChild
);
return
firstChild
;
}
return
null
;
}
/// Called during layout to create, add, and layout the child after
/// the given child.
///
/// Calls [createChild] to actually create and add the child.
///
/// Returns the new child. It is the responsibility of the caller to configure
/// the child's scroll offset.
///
/// Children after the `after` child may be removed in the process. Only the
/// new child may be added.
@protected
RenderBox
insertAndLayoutChild
(
BoxConstraints
childConstraints
,
{
@required
RenderBox
after
})
{
assert
(
_currentlyUpdatingChildIndex
==
null
);
assert
(
after
!=
null
);
final
int
index
=
indexOf
(
after
)
+
1
;
invokeLayoutCallback
<
SliverConstraints
>((
SliverConstraints
constraints
)
{
assert
(
constraints
==
this
.
constraints
);
allowAdditionsFor
(
index
,
()
{
createChild
(
index
,
after:
after
);
});
});
final
RenderBox
child
=
childAfter
(
after
);
if
(
child
!=
null
&&
indexOf
(
child
)
==
index
)
{
assert
(
indexOf
(
child
)
==
index
);
child
.
layout
(
childConstraints
,
parentUsesSize:
true
);
return
child
;
}
return
null
;
}
/// Called after layout with the number of children that can be garbage
/// collected at the head and tail of the child list.
@protected
void
collectGarbage
(
int
leadingGarbage
,
int
trailingGarbage
)
{
assert
(
_currentlyUpdatingChildIndex
==
null
);
assert
(
childCount
>=
leadingGarbage
+
trailingGarbage
);
invokeLayoutCallback
<
SliverConstraints
>((
SliverConstraints
constraints
)
{
while
(
leadingGarbage
>
0
)
{
removeChild
(
firstChild
);
leadingGarbage
-=
1
;
}
while
(
trailingGarbage
>
0
)
{
removeChild
(
lastChild
);
trailingGarbage
-=
1
;
}
});
}
/// Returns the index of the given child, as given by the
/// [SliverBlockParentData.index] field of the child's [parentData].
@protected
int
indexOf
(
RenderBox
child
)
{
assert
(
child
!=
null
);
final
SliverBlockParentData
childParentData
=
child
.
parentData
;
assert
(
childParentData
.
index
!=
null
);
return
childParentData
.
index
;
}
/// Returns the scroll offset of the given child, as given by the
/// [SliverBlockParentData.scrollOffset] field of the child's [parentData].
@protected
double
offsetOf
(
RenderBox
child
)
{
assert
(
child
!=
null
);
final
SliverBlockParentData
childParentData
=
child
.
parentData
;
assert
(
childParentData
.
scrollOffset
!=
null
);
return
childParentData
.
scrollOffset
;
}
/// Returns the dimension of the given child in the main axis, as given by the
/// child's [RenderBox.size] property. This is only valid after layout.
@protected
double
paintExtentOf
(
RenderBox
child
)
{
assert
(
child
!=
null
);
assert
(
child
.
hasSize
);
switch
(
constraints
.
axis
)
{
case
Axis
.
horizontal
:
return
child
.
size
.
width
;
case
Axis
.
vertical
:
return
child
.
size
.
height
;
}
return
null
;
}
@override
void
performLayout
()
{
assert
(
_currentlyUpdatingChildIndex
==
null
);
double
scrollOffset
=
constraints
.
scrollOffset
;
assert
(
scrollOffset
>=
0.0
);
double
remainingPaintExtent
=
constraints
.
remainingPaintExtent
;
assert
(
remainingPaintExtent
>=
0.0
);
double
targetEndScrollOffset
=
scrollOffset
+
remainingPaintExtent
;
BoxConstraints
childConstraints
=
constraints
.
asBoxConstraints
();
int
leadingGarbage
=
0
;
int
trailingGarbage
=
0
;
bool
reachedEnd
=
false
;
// This algorithm in principle is straight-forward: find the first child
// that overlaps the given scrollOffset, creating more children at the top
// of the list if necessary, then walk down the list updating and laying out
// each child and adding more at the end if necessary until we have enough
// children to cover the entire viewport.
//
// It is complicated by one minor issue, which is that any time you update
// or create a child, it's possible that the some of the children that
// haven't yet been laid out will be removed, leaving the list in an
// inconsistent state, and requiring that missing nodes be recreated.
//
// To keep this mess tractable, this algorithm starts from what is currently
// the first child, if any, and then walks up and/or down from there, so
// that the nodes that might get removed are always at the edges of what has
// already been laid out.
// Make sure we have at least one child to start from.
if
(
firstChild
==
null
)
{
if
(!
addInitialChild
())
{
// There are no children.
geometry
=
new
SliverGeometry
(
scrollExtent:
0.0
,
paintExtent:
0.0
,
maxPaintExtent:
0.0
,
);
return
;
}
}
// We have at least one child.
// These variables track the range of children that we have laid out. Within
// this range, the children have consecutive indices. Outside this range,
// it's possible for a child to get removed without notice.
RenderBox
leadingChildWithLayout
,
trailingChildWithLayout
;
// Find the last child that is at or before the scrollOffset.
RenderBox
earliestUsefulChild
=
firstChild
;
while
(
offsetOf
(
earliestUsefulChild
)
>
scrollOffset
)
{
// We have to add children before the earliestUsefulChild.
earliestUsefulChild
=
insertAndLayoutLeadingChild
(
childConstraints
);
if
(
earliestUsefulChild
==
null
)
{
// We ran out of children before reaching the scroll offset.
// We must inform our parent that this sliver cannot fulfill
// its contract and that we need a scroll offset correction.
geometry
=
new
SliverGeometry
(
scrollOffsetCorrection:
-
offsetOf
(
firstChild
),
);
return
;
}
assert
(
earliestUsefulChild
==
firstChild
);
leadingChildWithLayout
=
earliestUsefulChild
;
trailingChildWithLayout
??=
earliestUsefulChild
;
}
// At this point, earliestUsefulChild is the first child, and is a child
// whose scrollOffset is at or before the scrollOffset, and
// leadingChildWithLayout and trailingChildWithLayout are either null or
// cover a range of render boxes that we have laid out with the first being
// the same as earliestUsefulChild and the last being either at or after the
// scroll offset.
assert
(
earliestUsefulChild
==
firstChild
);
assert
(
offsetOf
(
earliestUsefulChild
)
<=
scrollOffset
);
// Make sure we've laid out at least one child.
if
(
leadingChildWithLayout
==
null
)
{
earliestUsefulChild
.
layout
(
childConstraints
,
parentUsesSize:
true
);
leadingChildWithLayout
=
earliestUsefulChild
;
trailingChildWithLayout
=
earliestUsefulChild
;
}
// Here, earliestUsefulChild is still the first child, it's got a
// scrollOffset that is at or before our actual scrollOffset, and it has
// been laid out, and is in fact our leadingChildWithLayout. It's possible
// that some children beyond that one have also been laid out.
bool
inLayoutRange
=
true
;
RenderBox
child
=
earliestUsefulChild
;
int
index
=
indexOf
(
child
);
double
endScrollOffset
=
offsetOf
(
child
)
+
paintExtentOf
(
child
);
bool
advance
()
{
// returns true if we advanced, false if we have no more children
// This function is used in two different places below, to avoid code duplication.
assert
(
child
!=
null
);
if
(
child
==
trailingChildWithLayout
)
inLayoutRange
=
false
;
child
=
childAfter
(
child
);
if
(
child
==
null
)
inLayoutRange
=
false
;
index
+=
1
;
if
(!
inLayoutRange
)
{
if
(
child
==
null
||
indexOf
(
child
)
!=
index
)
{
// We are missing a child. Insert it (and lay it out) if possible.
child
=
insertAndLayoutChild
(
childConstraints
,
after:
trailingChildWithLayout
);
if
(
child
==
null
)
{
// We have run out of children.
return
false
;
}
}
else
{
// Lay out the child.
child
.
layout
(
childConstraints
,
parentUsesSize:
true
);
}
trailingChildWithLayout
=
child
;
}
assert
(
child
!=
null
);
final
SliverBlockParentData
childParentData
=
child
.
parentData
;
childParentData
.
scrollOffset
=
endScrollOffset
;
assert
(
childParentData
.
index
==
index
);
endScrollOffset
=
offsetOf
(
child
)
+
paintExtentOf
(
child
);
return
true
;
}
// Find the first child that ends after the scroll offset.
while
(
endScrollOffset
<
scrollOffset
)
{
leadingGarbage
+=
1
;
if
(!
advance
())
{
assert
(
leadingGarbage
==
childCount
);
assert
(
child
==
null
);
// we want to make sure we keep the last child around so we know the end scroll offset
collectGarbage
(
leadingGarbage
-
1
,
0
);
assert
(
firstChild
==
lastChild
);
final
double
extent
=
offsetOf
(
lastChild
)
+
paintExtentOf
(
lastChild
);
geometry
=
new
SliverGeometry
(
scrollExtent:
extent
,
paintExtent:
0.0
,
maxPaintExtent:
extent
,
);
return
;
}
}
// Now find the first child that ends after our end.
while
(
endScrollOffset
<
targetEndScrollOffset
)
{
if
(!
advance
())
{
reachedEnd
=
true
;
break
;
}
}
// Finally count up all the remaining children and label them as garbage.
if
(
child
!=
null
)
{
child
=
childAfter
(
child
);
while
(
child
!=
null
)
{
trailingGarbage
+=
1
;
child
=
childAfter
(
child
);
}
}
// At this point everything should be good to go, we just have to clean up
// the garbage and report the geometry.
collectGarbage
(
leadingGarbage
,
trailingGarbage
);
assert
(
firstChild
!=
null
);
assert
(()
{
int
index
=
indexOf
(
firstChild
);
RenderBox
child
=
childAfter
(
firstChild
);
while
(
child
!=
null
)
{
index
+=
1
;
assert
(
indexOf
(
child
)
==
index
);
child
=
childAfter
(
child
);
}
return
true
;
});
double
estimatedTotalExtent
;
if
(
reachedEnd
)
{
estimatedTotalExtent
=
endScrollOffset
;
}
else
{
estimatedTotalExtent
=
estimateScrollOffsetExtent
(
firstIndex:
indexOf
(
firstChild
),
lastIndex:
indexOf
(
lastChild
),
leadingScrollOffset:
offsetOf
(
firstChild
),
trailingScrollOffset:
endScrollOffset
,
);
assert
(
estimatedTotalExtent
>=
endScrollOffset
-
offsetOf
(
firstChild
));
}
double
paintedExtent
=
calculatePaintOffset
(
constraints
,
from:
offsetOf
(
firstChild
),
to:
endScrollOffset
,
);
geometry
=
new
SliverGeometry
(
scrollExtent:
estimatedTotalExtent
,
paintExtent:
paintedExtent
,
maxPaintExtent:
estimatedTotalExtent
,
);
assert
(
_currentlyUpdatingChildIndex
==
null
);
}
@override
bool
hitTestChildren
(
HitTestResult
result
,
{
@required
double
mainAxisPosition
,
@required
double
crossAxisPosition
})
{
RenderBox
child
=
lastChild
;
while
(
child
!=
null
)
{
if
(
child
!=
null
)
{
if
(
hitTestBoxChild
(
result
,
child
,
mainAxisPosition:
mainAxisPosition
,
crossAxisPosition:
crossAxisPosition
))
return
true
;
}
child
=
childBefore
(
child
);
}
return
false
;
}
@override
double
childPosition
(
RenderBox
child
)
{
return
offsetOf
(
child
);
}
// TODO(ianh): There's a lot of duplicate code in the next two functions,
// but I don't see a good way to avoid it, since both functions are hot.
@override
void
applyPaintTransform
(
RenderObject
child
,
Matrix4
transform
)
{
// coordinate system origin here is at the top-left corner, regardless of our axis direction.
// originOffset gives us the delta from the real origin to the origin in the axis direction.
Offset
unitOffset
,
originOffset
;
bool
addExtent
;
switch
(
applyGrowthDirectionToAxisDirection
(
constraints
.
axisDirection
,
constraints
.
growthDirection
))
{
case
AxisDirection
.
up
:
unitOffset
=
const
Offset
(
0.0
,
-
1.0
);
originOffset
=
new
Offset
(
0.0
,
geometry
.
paintExtent
);
addExtent
=
true
;
break
;
case
AxisDirection
.
right
:
unitOffset
=
const
Offset
(
1.0
,
0.0
);
originOffset
=
Offset
.
zero
;
addExtent
=
false
;
break
;
case
AxisDirection
.
down
:
unitOffset
=
const
Offset
(
0.0
,
1.0
);
originOffset
=
Offset
.
zero
;
addExtent
=
false
;
break
;
case
AxisDirection
.
left
:
unitOffset
=
const
Offset
(-
1.0
,
0.0
);
originOffset
=
new
Offset
(
geometry
.
paintExtent
,
0.0
);
addExtent
=
true
;
break
;
}
assert
(
unitOffset
!=
null
);
assert
(
addExtent
!=
null
);
Offset
childOffset
=
originOffset
+
unitOffset
*
(
offsetOf
(
child
)
-
constraints
.
scrollOffset
);
if
(
addExtent
)
childOffset
+=
unitOffset
*
paintExtentOf
(
child
);
transform
.
translate
(
childOffset
.
dx
,
childOffset
.
dy
);
}
@override
void
paint
(
PaintingContext
context
,
Offset
offset
)
{
if
(
firstChild
==
null
)
return
;
// offset is to the top-left corner, regardless of our axis direction.
// originOffset gives us the delta from the real origin to the origin in the axis direction.
Offset
unitOffset
,
originOffset
;
bool
addExtent
;
switch
(
applyGrowthDirectionToAxisDirection
(
constraints
.
axisDirection
,
constraints
.
growthDirection
))
{
case
AxisDirection
.
up
:
unitOffset
=
const
Offset
(
0.0
,
-
1.0
);
originOffset
=
offset
+
new
Offset
(
0.0
,
geometry
.
paintExtent
);
addExtent
=
true
;
break
;
case
AxisDirection
.
right
:
unitOffset
=
const
Offset
(
1.0
,
0.0
);
originOffset
=
offset
;
addExtent
=
false
;
break
;
case
AxisDirection
.
down
:
unitOffset
=
const
Offset
(
0.0
,
1.0
);
originOffset
=
offset
;
addExtent
=
false
;
break
;
case
AxisDirection
.
left
:
unitOffset
=
const
Offset
(-
1.0
,
0.0
);
originOffset
=
offset
+
new
Offset
(
geometry
.
paintExtent
,
0.0
);
addExtent
=
true
;
break
;
}
assert
(
unitOffset
!=
null
);
assert
(
addExtent
!=
null
);
RenderBox
child
=
firstChild
;
while
(
child
!=
null
)
{
Offset
childOffset
=
originOffset
+
unitOffset
*
(
offsetOf
(
child
)
-
constraints
.
scrollOffset
);
if
(
addExtent
)
childOffset
+=
unitOffset
*
paintExtentOf
(
child
);
context
.
paintChild
(
child
,
childOffset
);
child
=
childAfter
(
child
);
}
}
@override
void
debugFillDescription
(
List
<
String
>
description
)
{
super
.
debugFillDescription
(
description
);
if
(
firstChild
!=
null
)
{
description
.
add
(
'currently live children:
${indexOf(firstChild)}
to
${indexOf(lastChild)}
'
);
}
else
{
description
.
add
(
'no children current live'
);
}
}
}
packages/flutter/lib/src/widgets/block.dart
0 → 100644
View file @
f683abd7
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:collection'
show
SplayTreeMap
,
HashMap
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/scheduler.dart'
;
import
'framework.dart'
;
import
'basic.dart'
;
abstract
class
SliverBlockDelegate
{
/// Abstract const constructor. This constructor enables subclasses to provide
/// const constructors so that they can be used in const expressions.
const
SliverBlockDelegate
();
Widget
build
(
BuildContext
context
,
int
index
);
bool
shouldRebuild
(
@checked
SliverBlockDelegate
oldDelegate
);
int
get
childCount
;
double
estimateScrollOffsetExtent
(
int
firstIndex
,
int
lastIndex
,
double
leadingScrollOffset
,
double
trailingScrollOffset
,
)
{
return
childCount
*
(
trailingScrollOffset
-
leadingScrollOffset
)
/
(
lastIndex
-
firstIndex
+
1
);
}
}
// ///
// /// In general building all the widgets in advance is not efficient. It is
// /// better to create a delegate that builds them on demand by subclassing
// /// [SliverBlockDelegate] directly.
// ///
// /// This class is provided for the cases where either the list of children is
// /// known well in advance (ideally the children are themselves compile-time
// /// constants, for example), and therefore will not be built each time the
// /// delegate itself is created, or the list is small, such that it's likely
// /// always visible (and thus there is nothing to be gained by building it on
// /// demand). For example, the body of a dialog box might fit both of these
// /// conditions.
class
SliverBlockChildListDelegate
extends
SliverBlockDelegate
{
/// Abstract const constructor. This constructor enables subclasses to provide
/// const constructors so that they can be used in const expressions.
const
SliverBlockChildListDelegate
(
this
.
children
);
final
List
<
Widget
>
children
;
@override
Widget
build
(
BuildContext
context
,
int
index
)
{
assert
(
children
!=
null
);
if
(
index
<
0
||
index
>=
children
.
length
)
return
null
;
return
children
[
index
];
}
@override
bool
shouldRebuild
(
@checked
SliverBlockChildListDelegate
oldDelegate
)
{
return
children
!=
oldDelegate
.
children
;
}
@override
int
get
childCount
=>
children
.
length
;
}
class
SliverBlock
extends
RenderObjectWidget
{
SliverBlock
({
Key
key
,
@required
this
.
delegate
,
})
:
super
(
key:
key
)
{
assert
(
delegate
!=
null
);
}
final
SliverBlockDelegate
delegate
;
@override
_SliverBlockElement
createElement
()
=>
new
_SliverBlockElement
(
this
);
@override
_RenderSliverBlockForWidgets
createRenderObject
(
BuildContext
context
)
=>
new
_RenderSliverBlockForWidgets
();
@override
void
debugFillDescription
(
List
<
String
>
description
)
{
super
.
debugFillDescription
(
description
);
description
.
add
(
'delegate:
$delegate
'
);
}
}
class
_SliverBlockElement
extends
RenderObjectElement
{
_SliverBlockElement
(
SliverBlock
widget
)
:
super
(
widget
);
@override
SliverBlock
get
widget
=>
super
.
widget
;
@override
_RenderSliverBlockForWidgets
get
renderObject
=>
super
.
renderObject
;
@override
void
mount
(
Element
parent
,
dynamic
newSlot
)
{
super
.
mount
(
parent
,
newSlot
);
renderObject
.
_element
=
this
;
}
@override
void
unmount
()
{
super
.
unmount
();
renderObject
.
_element
=
null
;
}
@override
void
update
(
SliverBlock
newWidget
)
{
final
SliverBlock
oldWidget
=
widget
;
super
.
update
(
newWidget
);
final
SliverBlockDelegate
newDelegate
=
newWidget
.
delegate
;
final
SliverBlockDelegate
oldDelegate
=
oldWidget
.
delegate
;
if
(
newDelegate
!=
oldDelegate
&&
(
newDelegate
.
runtimeType
!=
oldDelegate
.
runtimeType
||
newDelegate
.
shouldRebuild
(
oldDelegate
)))
performRebuild
();
}
Map
<
int
,
Element
>
_childElements
=
new
SplayTreeMap
<
int
,
Element
>();
Map
<
int
,
Widget
>
_childWidgets
=
new
HashMap
<
int
,
Widget
>();
RenderBox
_currentBeforeChild
;
bool
_debugOpenToChanges
=
false
;
@override
void
performRebuild
()
{
_childWidgets
.
clear
();
super
.
performRebuild
();
_currentBeforeChild
=
null
;
assert
(!
_debugOpenToChanges
);
assert
(()
{
_debugOpenToChanges
=
true
;
return
true
;
});
try
{
// The "toList()" below is to get a copy of the array so that we can
// mutate _childElements within the loop. Basically we just update all the
// same indexes as we had before. If any of them mutate the tree, then
// this will also trigger a layout and so forth. (We won't call the
// delegate's build function multiple times, though, because we cache the
// delegate's results until the next time we need to rebuild the whole
// block widget.)
for
(
int
index
in
_childElements
.
keys
.
toList
())
{
Element
newChild
;
renderObject
.
_rebuild
(
index
,
()
{
newChild
=
updateChild
(
_childElements
[
index
],
_build
(
index
),
index
);
});
if
(
newChild
!=
null
)
{
_childElements
[
index
]
=
newChild
;
_currentBeforeChild
=
newChild
.
renderObject
;
}
else
{
_childElements
.
remove
(
index
);
}
}
}
finally
{
assert
(()
{
_debugOpenToChanges
=
false
;
return
true
;
});
}
}
Widget
_build
(
int
index
)
{
return
_childWidgets
.
putIfAbsent
(
index
,
()
{
Widget
child
=
widget
.
delegate
.
build
(
this
,
index
);
if
(
child
==
null
)
return
null
;
return
new
RepaintBoundary
.
wrap
(
child
,
index
);
});
}
void
_createChild
(
int
index
,
bool
insertFirst
)
{
assert
(!
_debugOpenToChanges
);
owner
.
buildScope
(
this
,
()
{
assert
(
insertFirst
||
_childElements
[
index
-
1
]
!=
null
);
assert
(()
{
_debugOpenToChanges
=
true
;
return
true
;
});
_currentBeforeChild
=
insertFirst
?
null
:
_childElements
[
index
-
1
].
renderObject
;
Element
newChild
;
try
{
newChild
=
updateChild
(
_childElements
[
index
],
_build
(
index
),
index
);
}
finally
{
assert
(()
{
_debugOpenToChanges
=
false
;
return
true
;
});
}
if
(
newChild
!=
null
)
{
_childElements
[
index
]
=
newChild
;
}
else
{
_childElements
.
remove
(
index
);
}
});
}
@override
void
forgetChild
(
Element
child
)
{
assert
(
child
!=
null
);
assert
(
child
.
slot
!=
null
);
assert
(
_childElements
.
containsKey
(
child
.
slot
));
_childElements
.
remove
(
child
.
slot
);
}
void
_removeChild
(
int
index
)
{
assert
(!
_debugOpenToChanges
);
assert
(
index
>=
0
);
owner
.
buildScope
(
this
,
()
{
assert
(
_childElements
.
containsKey
(
index
));
assert
(()
{
_debugOpenToChanges
=
true
;
return
true
;
});
try
{
Element
result
=
updateChild
(
_childElements
[
index
],
null
,
index
);
assert
(
result
==
null
);
}
finally
{
assert
(()
{
_debugOpenToChanges
=
false
;
return
true
;
});
}
_childElements
.
remove
(
index
);
assert
(!
_childElements
.
containsKey
(
index
));
});
}
@override
void
insertChildRenderObject
(
@checked
RenderObject
child
,
int
slot
)
{
assert
(
_debugOpenToChanges
);
renderObject
.
insert
(
child
,
after:
_currentBeforeChild
);
assert
(()
{
SliverBlockParentData
childParentData
=
child
.
parentData
;
assert
(
slot
==
childParentData
.
index
);
return
true
;
});
}
@override
void
moveChildRenderObject
(
@checked
RenderObject
child
,
int
slot
)
{
// TODO(ianh): At some point we should be better about noticing when a
// particular LocalKey changes slot, and handle moving the nodes around.
assert
(
false
);
}
@override
void
removeChildRenderObject
(
@checked
RenderObject
child
)
{
assert
(
_debugOpenToChanges
);
renderObject
.
remove
(
child
);
}
@override
void
visitChildren
(
ElementVisitor
visitor
)
{
// The toList() is to make a copy so that the underlying list can be modified by
// the visitor:
assert
(!
_childElements
.
values
.
any
((
Element
child
)
=>
child
==
null
));
_childElements
.
values
.
toList
().
forEach
(
visitor
);
}
}
class
_RenderSliverBlockForWidgets
extends
RenderSliverBlock
{
_SliverBlockElement
_element
;
@override
void
createChild
(
int
index
,
{
@required
RenderBox
after
})
{
assert
(
_element
!=
null
);
_element
.
_createChild
(
index
,
after
==
null
);
}
@override
void
removeChild
(
RenderBox
child
)
{
assert
(
_element
!=
null
);
_element
.
_removeChild
(
indexOf
(
child
));
}
void
_rebuild
(
int
index
,
VoidCallback
callback
)
{
allowAdditionsFor
(
index
,
callback
);
}
@override
double
estimateScrollOffsetExtent
({
int
firstIndex
,
int
lastIndex
,
double
leadingScrollOffset
,
double
trailingScrollOffset
,
})
{
assert
(
lastIndex
>=
firstIndex
);
assert
(
_element
!=
null
);
return
_element
.
widget
.
delegate
.
estimateScrollOffsetExtent
(
firstIndex
,
lastIndex
,
leadingScrollOffset
,
trailingScrollOffset
);
}
}
packages/flutter/lib/src/widgets/viewport.dart
View file @
f683abd7
...
@@ -16,10 +16,11 @@ class Viewport2 extends MultiChildRenderObjectWidget {
...
@@ -16,10 +16,11 @@ class Viewport2 extends MultiChildRenderObjectWidget {
Key
key
,
Key
key
,
this
.
axisDirection
:
AxisDirection
.
down
,
this
.
axisDirection
:
AxisDirection
.
down
,
this
.
anchor
:
0.0
,
this
.
anchor
:
0.0
,
this
.
offset
,
@required
this
.
offset
,
this
.
center
,
this
.
center
,
List
<
Widget
>
children:
const
<
Widget
>[],
List
<
Widget
>
children:
const
<
Widget
>[],
})
:
super
(
key:
key
,
children:
children
)
{
})
:
super
(
key:
key
,
children:
children
)
{
assert
(
offset
!=
null
);
assert
(
center
==
null
||
children
.
where
((
Widget
child
)
=>
child
.
key
==
center
).
length
==
1
);
assert
(
center
==
null
||
children
.
where
((
Widget
child
)
=>
child
.
key
==
center
).
length
==
1
);
}
}
...
...
packages/flutter/lib/widgets.dart
View file @
f683abd7
...
@@ -13,6 +13,7 @@ export 'src/widgets/app.dart';
...
@@ -13,6 +13,7 @@ export 'src/widgets/app.dart';
export
'src/widgets/banner.dart'
;
export
'src/widgets/banner.dart'
;
export
'src/widgets/basic.dart'
;
export
'src/widgets/basic.dart'
;
export
'src/widgets/binding.dart'
;
export
'src/widgets/binding.dart'
;
export
'src/widgets/block.dart'
;
export
'src/widgets/clamp_overscrolls.dart'
;
export
'src/widgets/clamp_overscrolls.dart'
;
export
'src/widgets/container.dart'
;
export
'src/widgets/container.dart'
;
export
'src/widgets/debug.dart'
;
export
'src/widgets/debug.dart'
;
...
...
packages/flutter/test/rendering/slivers_block_test.dart
0 → 100644
View file @
f683abd7
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/rendering.dart'
;
import
'package:meta/meta.dart'
;
import
'package:test/test.dart'
;
import
'rendering_tester.dart'
;
class
RenderSliverBlockTest
extends
RenderSliverBlock
{
RenderSliverBlockTest
({
this
.
children
,
});
List
<
RenderBox
>
children
;
@override
void
createChild
(
int
index
,
{
@required
RenderBox
after
})
{
assert
(
index
>=
0
);
if
(
index
<
0
||
index
>=
children
.
length
)
return
null
;
insert
(
children
[
index
],
after:
after
);
}
@override
double
estimateScrollOffsetExtent
({
int
firstIndex
,
int
lastIndex
,
double
leadingScrollOffset
,
double
trailingScrollOffset
,
})
{
assert
(
lastIndex
>=
firstIndex
);
return
children
.
length
*
(
trailingScrollOffset
-
leadingScrollOffset
)
/
(
lastIndex
-
firstIndex
+
1
);
}
}
void
main
(
)
{
test
(
'RenderSliverBlock basic test - down'
,
()
{
RenderObject
inner
;
RenderBox
a
,
b
,
c
,
d
,
e
;
RenderViewport2
root
=
new
RenderViewport2
(
axisDirection:
AxisDirection
.
down
,
offset:
new
ViewportOffset
.
zero
(),
children:
<
RenderSliver
>[
inner
=
new
RenderSliverBlockTest
(
children:
<
RenderBox
>[
a
=
new
RenderSizedBox
(
const
Size
(
100.0
,
400.0
)),
b
=
new
RenderSizedBox
(
const
Size
(
100.0
,
400.0
)),
c
=
new
RenderSizedBox
(
const
Size
(
100.0
,
400.0
)),
d
=
new
RenderSizedBox
(
const
Size
(
100.0
,
400.0
)),
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
.
attached
,
false
);
expect
(
d
.
attached
,
false
);
expect
(
e
.
attached
,
false
);
// make sure that layout is stable by laying out again
inner
.
markNeedsLayout
();
pumpFrame
();
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
.
attached
,
false
);
expect
(
d
.
attached
,
false
);
expect
(
e
.
attached
,
false
);
// now try various scroll offsets
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
.
attached
,
false
);
expect
(
d
.
attached
,
false
);
expect
(
e
.
attached
,
false
);
root
.
offset
=
new
ViewportOffset
.
fixed
(
600.0
);
pumpFrame
();
expect
(
a
.
attached
,
false
);
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
.
attached
,
false
);
expect
(
e
.
attached
,
false
);
root
.
offset
=
new
ViewportOffset
.
fixed
(
900.0
);
pumpFrame
();
expect
(
a
.
attached
,
false
);
expect
(
b
.
attached
,
false
);
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
.
attached
,
false
);
// try going back up
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
.
attached
,
false
);
expect
(
d
.
attached
,
false
);
expect
(
e
.
attached
,
false
);
});
test
(
'RenderSliverBlock basic test - up'
,
()
{
RenderObject
inner
;
RenderBox
a
,
b
,
c
,
d
,
e
;
RenderViewport2
root
=
new
RenderViewport2
(
axisDirection:
AxisDirection
.
up
,
offset:
new
ViewportOffset
.
zero
(),
children:
<
RenderSliver
>[
inner
=
new
RenderSliverBlockTest
(
children:
<
RenderBox
>[
a
=
new
RenderSizedBox
(
const
Size
(
100.0
,
400.0
)),
b
=
new
RenderSizedBox
(
const
Size
(
100.0
,
400.0
)),
c
=
new
RenderSizedBox
(
const
Size
(
100.0
,
400.0
)),
d
=
new
RenderSizedBox
(
const
Size
(
100.0
,
400.0
)),
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
.
attached
,
false
);
expect
(
d
.
attached
,
false
);
expect
(
e
.
attached
,
false
);
// make sure that layout is stable by laying out again
inner
.
markNeedsLayout
();
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
.
attached
,
false
);
expect
(
d
.
attached
,
false
);
expect
(
e
.
attached
,
false
);
// now try various scroll offsets
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
.
attached
,
false
);
expect
(
d
.
attached
,
false
);
expect
(
e
.
attached
,
false
);
root
.
offset
=
new
ViewportOffset
.
fixed
(
600.0
);
pumpFrame
();
expect
(
a
.
attached
,
false
);
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
.
attached
,
false
);
expect
(
e
.
attached
,
false
);
root
.
offset
=
new
ViewportOffset
.
fixed
(
900.0
);
pumpFrame
();
expect
(
a
.
attached
,
false
);
expect
(
b
.
attached
,
false
);
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
.
attached
,
false
);
// try going back up
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
.
attached
,
false
);
expect
(
d
.
attached
,
false
);
expect
(
e
.
attached
,
false
);
});
}
packages/flutter/test/rendering/slivers_layout_test.dart
View file @
f683abd7
...
@@ -25,6 +25,7 @@ void main() {
...
@@ -25,6 +25,7 @@ void main() {
RenderBox
box
;
RenderBox
box
;
RenderObject
root
=
new
RenderLayoutWatcher
(
RenderObject
root
=
new
RenderLayoutWatcher
(
viewport
=
new
RenderViewport2
(
viewport
=
new
RenderViewport2
(
offset:
new
ViewportOffset
.
zero
(),
children:
<
RenderSliver
>[
children:
<
RenderSliver
>[
sliver
=
new
RenderSliverToBoxAdapter
(
child:
box
=
new
RenderSizedBox
(
const
Size
(
100.0
,
400.0
))),
sliver
=
new
RenderSliverToBoxAdapter
(
child:
box
=
new
RenderSizedBox
(
const
Size
(
100.0
,
400.0
))),
],
],
...
...
packages/flutter/test/rendering/slivers_test.dart
View file @
f683abd7
...
@@ -9,7 +9,9 @@ import 'rendering_tester.dart';
...
@@ -9,7 +9,9 @@ import 'rendering_tester.dart';
void
main
(
)
{
void
main
(
)
{
test
(
'RenderViewport2 basic test - no children'
,
()
{
test
(
'RenderViewport2 basic test - no children'
,
()
{
RenderViewport2
root
=
new
RenderViewport2
();
RenderViewport2
root
=
new
RenderViewport2
(
offset:
new
ViewportOffset
.
zero
(),
);
layout
(
root
);
layout
(
root
);
root
.
offset
=
new
ViewportOffset
.
fixed
(
900.0
);
root
.
offset
=
new
ViewportOffset
.
fixed
(
900.0
);
pumpFrame
();
pumpFrame
();
...
@@ -18,6 +20,7 @@ void main() {
...
@@ -18,6 +20,7 @@ void main() {
test
(
'RenderViewport2 basic test - down'
,
()
{
test
(
'RenderViewport2 basic test - down'
,
()
{
RenderBox
a
,
b
,
c
,
d
,
e
;
RenderBox
a
,
b
,
c
,
d
,
e
;
RenderViewport2
root
=
new
RenderViewport2
(
RenderViewport2
root
=
new
RenderViewport2
(
offset:
new
ViewportOffset
.
zero
(),
children:
<
RenderSliver
>[
children:
<
RenderSliver
>[
new
RenderSliverToBoxAdapter
(
child:
a
=
new
RenderSizedBox
(
const
Size
(
100.0
,
400.0
))),
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:
b
=
new
RenderSizedBox
(
const
Size
(
100.0
,
400.0
))),
...
@@ -66,6 +69,7 @@ void main() {
...
@@ -66,6 +69,7 @@ void main() {
RenderBox
a
,
b
,
c
,
d
,
e
;
RenderBox
a
,
b
,
c
,
d
,
e
;
RenderViewport2
root
=
new
RenderViewport2
(
RenderViewport2
root
=
new
RenderViewport2
(
axisDirection:
AxisDirection
.
up
,
axisDirection:
AxisDirection
.
up
,
offset:
new
ViewportOffset
.
zero
(),
children:
<
RenderSliver
>[
children:
<
RenderSliver
>[
new
RenderSliverToBoxAdapter
(
child:
a
=
new
RenderSizedBox
(
const
Size
(
100.0
,
400.0
))),
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:
b
=
new
RenderSizedBox
(
const
Size
(
100.0
,
400.0
))),
...
@@ -114,6 +118,7 @@ void main() {
...
@@ -114,6 +118,7 @@ void main() {
RenderBox
a
,
b
,
c
,
d
,
e
;
RenderBox
a
,
b
,
c
,
d
,
e
;
RenderViewport2
root
=
new
RenderViewport2
(
RenderViewport2
root
=
new
RenderViewport2
(
axisDirection:
AxisDirection
.
right
,
axisDirection:
AxisDirection
.
right
,
offset:
new
ViewportOffset
.
zero
(),
children:
<
RenderSliver
>[
children:
<
RenderSliver
>[
new
RenderSliverToBoxAdapter
(
child:
a
=
new
RenderSizedBox
(
const
Size
(
400.0
,
100.0
))),
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:
b
=
new
RenderSizedBox
(
const
Size
(
400.0
,
100.0
))),
...
@@ -162,6 +167,7 @@ void main() {
...
@@ -162,6 +167,7 @@ void main() {
RenderBox
a
,
b
,
c
,
d
,
e
;
RenderBox
a
,
b
,
c
,
d
,
e
;
RenderViewport2
root
=
new
RenderViewport2
(
RenderViewport2
root
=
new
RenderViewport2
(
axisDirection:
AxisDirection
.
left
,
axisDirection:
AxisDirection
.
left
,
offset:
new
ViewportOffset
.
zero
(),
children:
<
RenderSliver
>[
children:
<
RenderSliver
>[
new
RenderSliverToBoxAdapter
(
child:
a
=
new
RenderSizedBox
(
const
Size
(
400.0
,
100.0
))),
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:
b
=
new
RenderSizedBox
(
const
Size
(
400.0
,
100.0
))),
...
...
packages/flutter/test/widgets/slivers_block_global_key_test.dart
0 → 100644
View file @
f683abd7
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/widgets.dart'
;
int
globalGeneration
=
0
;
class
GenerationText
extends
StatefulWidget
{
GenerationText
(
this
.
value
);
final
int
value
;
@override
_GenerationTextState
createState
()
=>
new
_GenerationTextState
();
}
class
_GenerationTextState
extends
State
<
GenerationText
>
{
_GenerationTextState
()
:
generation
=
globalGeneration
;
final
int
generation
;
@override
Widget
build
(
BuildContext
context
)
=>
new
Text
(
'
${config.value}
:
$generation
'
);
}
Future
<
Null
>
test
(
WidgetTester
tester
,
double
offset
,
List
<
int
>
keys
)
{
globalGeneration
+=
1
;
return
tester
.
pumpWidget
(
new
Viewport2
(
offset:
new
ViewportOffset
.
fixed
(
offset
),
children:
<
Widget
>[
new
SliverBlock
(
delegate:
new
SliverBlockChildListDelegate
(
keys
.
map
((
int
key
)
{
return
new
SizedBox
(
key:
new
GlobalObjectKey
(
key
),
height:
100.0
,
child:
new
GenerationText
(
key
));
}).
toList
()),
),
],
));
}
void
verify
(
WidgetTester
tester
,
List
<
Point
>
answerKey
,
String
text
)
{
List
<
Point
>
testAnswers
=
tester
.
renderObjectList
/*<RenderBox>*/
(
find
.
byType
(
SizedBox
)).
map
/*<Point>*/
(
(
RenderBox
target
)
=>
target
.
localToGlobal
(
const
Point
(
0.0
,
0.0
))
).
toList
();
expect
(
testAnswers
,
equals
(
answerKey
));
final
String
foundText
=
tester
.
widgetList
/*<Text>*/
(
find
.
byType
(
Text
))
.
map
/*<String>*/
((
Text
widget
)
=>
widget
.
data
)
.
reduce
((
String
value
,
String
element
)
=>
value
+
element
);
expect
(
foundText
,
equals
(
text
));
}
void
main
(
)
{
testWidgets
(
'Viewport2+SliverBlock with GlobalKey reparenting'
,
(
WidgetTester
tester
)
async
{
await
test
(
tester
,
0.0
,
<
int
>[
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
]);
verify
(
tester
,
<
Point
>[
const
Point
(
0.0
,
0.0
),
const
Point
(
0.0
,
100.0
),
const
Point
(
0.0
,
200.0
),
const
Point
(
0.0
,
300.0
),
const
Point
(
0.0
,
400.0
),
const
Point
(
0.0
,
500.0
),
],
'1:1 2:1 3:1 4:1 5:1 6:1 '
);
// gen 2 - flipping the order:
await
test
(
tester
,
0.0
,
<
int
>[
9
,
8
,
7
,
6
,
5
,
4
,
3
,
2
,
1
]);
verify
(
tester
,
<
Point
>[
const
Point
(
0.0
,
0.0
),
const
Point
(
0.0
,
100.0
),
const
Point
(
0.0
,
200.0
),
const
Point
(
0.0
,
300.0
),
const
Point
(
0.0
,
400.0
),
const
Point
(
0.0
,
500.0
),
],
'9:2 8:2 7:2 6:1 5:1 4:1 '
);
// gen 3 - flipping the order back:
await
test
(
tester
,
0.0
,
<
int
>[
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
]);
verify
(
tester
,
<
Point
>[
const
Point
(
0.0
,
0.0
),
const
Point
(
0.0
,
100.0
),
const
Point
(
0.0
,
200.0
),
const
Point
(
0.0
,
300.0
),
const
Point
(
0.0
,
400.0
),
const
Point
(
0.0
,
500.0
),
],
'1:3 2:3 3:3 4:1 5:1 6:1 '
);
// gen 4 - removal:
await
test
(
tester
,
0.0
,
<
int
>[
1
,
2
,
3
,
5
,
6
,
7
,
8
,
9
]);
verify
(
tester
,
<
Point
>[
const
Point
(
0.0
,
0.0
),
const
Point
(
0.0
,
100.0
),
const
Point
(
0.0
,
200.0
),
const
Point
(
0.0
,
300.0
),
const
Point
(
0.0
,
400.0
),
const
Point
(
0.0
,
500.0
),
],
'1:3 2:3 3:3 5:1 6:1 7:4 '
);
// gen 5 - insertion:
await
test
(
tester
,
0.0
,
<
int
>[
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
]);
verify
(
tester
,
<
Point
>[
const
Point
(
0.0
,
0.0
),
const
Point
(
0.0
,
100.0
),
const
Point
(
0.0
,
200.0
),
const
Point
(
0.0
,
300.0
),
const
Point
(
0.0
,
400.0
),
const
Point
(
0.0
,
500.0
),
],
'1:3 2:3 3:3 4:5 5:1 6:1 '
);
// gen 6 - adjacent reordering:
await
test
(
tester
,
0.0
,
<
int
>[
1
,
2
,
3
,
5
,
4
,
6
,
7
,
8
,
9
]);
verify
(
tester
,
<
Point
>[
const
Point
(
0.0
,
0.0
),
const
Point
(
0.0
,
100.0
),
const
Point
(
0.0
,
200.0
),
const
Point
(
0.0
,
300.0
),
const
Point
(
0.0
,
400.0
),
const
Point
(
0.0
,
500.0
),
],
'1:3 2:3 3:3 5:1 4:5 6:1 '
);
// gen 7 - scrolling:
await
test
(
tester
,
120.0
,
<
int
>[
1
,
2
,
3
,
5
,
4
,
6
,
7
,
8
,
9
]);
verify
(
tester
,
<
Point
>[
const
Point
(
0.0
,
-
20.0
),
const
Point
(
0.0
,
80.0
),
const
Point
(
0.0
,
180.0
),
const
Point
(
0.0
,
280.0
),
const
Point
(
0.0
,
380.0
),
const
Point
(
0.0
,
480.0
),
const
Point
(
0.0
,
580.0
),
],
'2:3 3:3 5:1 4:5 6:1 7:7 8:7 '
);
});
}
packages/flutter/test/widgets/slivers_block_test.dart
0 → 100644
View file @
f683abd7
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/widgets.dart'
;
Future
<
Null
>
test
(
WidgetTester
tester
,
double
offset
)
{
return
tester
.
pumpWidget
(
new
Viewport2
(
offset:
new
ViewportOffset
.
fixed
(
offset
),
children:
<
Widget
>[
new
SliverBlock
(
delegate:
new
SliverBlockChildListDelegate
(<
Widget
>[
new
SizedBox
(
height:
400.0
,
child:
new
Text
(
'a'
)),
new
SizedBox
(
height:
400.0
,
child:
new
Text
(
'b'
)),
new
SizedBox
(
height:
400.0
,
child:
new
Text
(
'c'
)),
new
SizedBox
(
height:
400.0
,
child:
new
Text
(
'd'
)),
new
SizedBox
(
height:
400.0
,
child:
new
Text
(
'e'
)),
]),
),
],
));
}
void
verify
(
WidgetTester
tester
,
List
<
Point
>
answerKey
,
String
text
)
{
List
<
Point
>
testAnswers
=
tester
.
renderObjectList
/*<RenderBox>*/
(
find
.
byType
(
SizedBox
)).
map
/*<Point>*/
(
(
RenderBox
target
)
=>
target
.
localToGlobal
(
const
Point
(
0.0
,
0.0
))
).
toList
();
expect
(
testAnswers
,
equals
(
answerKey
));
final
String
foundText
=
tester
.
widgetList
/*<Text>*/
(
find
.
byType
(
Text
))
.
map
/*<String>*/
((
Text
widget
)
=>
widget
.
data
)
.
reduce
((
String
value
,
String
element
)
=>
value
+
element
);
expect
(
foundText
,
equals
(
text
));
}
void
main
(
)
{
testWidgets
(
'Viewport2+SliverBlock basic test'
,
(
WidgetTester
tester
)
async
{
await
test
(
tester
,
0.0
);
expect
(
tester
.
renderObject
/*<RenderBox>*/
(
find
.
byType
(
Viewport2
)).
size
,
equals
(
const
Size
(
800.0
,
600.0
)));
verify
(
tester
,
<
Point
>[
const
Point
(
0.0
,
0.0
),
const
Point
(
0.0
,
400.0
),
],
'ab'
);
await
test
(
tester
,
200.0
);
verify
(
tester
,
<
Point
>[
const
Point
(
0.0
,
-
200.0
),
const
Point
(
0.0
,
200.0
),
],
'ab'
);
await
test
(
tester
,
600.0
);
verify
(
tester
,
<
Point
>[
const
Point
(
0.0
,
-
200.0
),
const
Point
(
0.0
,
200.0
),
],
'bc'
);
await
test
(
tester
,
900.0
);
verify
(
tester
,
<
Point
>[
const
Point
(
0.0
,
-
100.0
),
const
Point
(
0.0
,
300.0
),
],
'cd'
);
await
test
(
tester
,
200.0
);
verify
(
tester
,
<
Point
>[
const
Point
(
0.0
,
-
200.0
),
const
Point
(
0.0
,
200.0
),
],
'ab'
);
});
testWidgets
(
'Viewport2 with GlobalKey reparenting'
,
(
WidgetTester
tester
)
async
{
Key
key1
=
new
GlobalKey
();
ViewportOffset
offset
=
new
ViewportOffset
.
zero
();
await
tester
.
pumpWidget
(
new
Viewport2
(
offset:
offset
,
children:
<
Widget
>[
new
SliverBlock
(
delegate:
new
SliverBlockChildListDelegate
(<
Widget
>[
new
SizedBox
(
height:
251.0
,
child:
new
Text
(
'a'
)),
new
SizedBox
(
height:
252.0
,
child:
new
Text
(
'b'
)),
new
SizedBox
(
key:
key1
,
height:
253.0
,
child:
new
Text
(
'c'
)),
]),
),
],
));
verify
(
tester
,
<
Point
>[
const
Point
(
0.0
,
0.0
),
const
Point
(
0.0
,
251.0
),
const
Point
(
0.0
,
503.0
),
],
'abc'
);
await
tester
.
pumpWidget
(
new
Viewport2
(
offset:
offset
,
children:
<
Widget
>[
new
SliverBlock
(
delegate:
new
SliverBlockChildListDelegate
(<
Widget
>[
new
SizedBox
(
key:
key1
,
height:
253.0
,
child:
new
Text
(
'c'
)),
new
SizedBox
(
height:
251.0
,
child:
new
Text
(
'a'
)),
new
SizedBox
(
height:
252.0
,
child:
new
Text
(
'b'
)),
]),
),
],
));
verify
(
tester
,
<
Point
>[
const
Point
(
0.0
,
0.0
),
const
Point
(
0.0
,
253.0
),
const
Point
(
0.0
,
504.0
),
],
'cab'
);
await
tester
.
pumpWidget
(
new
Viewport2
(
offset:
offset
,
children:
<
Widget
>[
new
SliverBlock
(
delegate:
new
SliverBlockChildListDelegate
(<
Widget
>[
new
SizedBox
(
height:
251.0
,
child:
new
Text
(
'a'
)),
new
SizedBox
(
key:
key1
,
height:
253.0
,
child:
new
Text
(
'c'
)),
new
SizedBox
(
height:
252.0
,
child:
new
Text
(
'b'
)),
]),
),
],
));
verify
(
tester
,
<
Point
>[
const
Point
(
0.0
,
0.0
),
const
Point
(
0.0
,
251.0
),
const
Point
(
0.0
,
504.0
),
],
'acb'
);
await
tester
.
pumpWidget
(
new
Viewport2
(
offset:
offset
,
children:
<
Widget
>[
new
SliverBlock
(
delegate:
new
SliverBlockChildListDelegate
(<
Widget
>[
new
SizedBox
(
height:
251.0
,
child:
new
Text
(
'a'
)),
new
SizedBox
(
height:
252.0
,
child:
new
Text
(
'b'
)),
]),
),
],
));
verify
(
tester
,
<
Point
>[
const
Point
(
0.0
,
0.0
),
const
Point
(
0.0
,
251.0
),
],
'ab'
);
await
tester
.
pumpWidget
(
new
Viewport2
(
offset:
offset
,
children:
<
Widget
>[
new
SliverBlock
(
delegate:
new
SliverBlockChildListDelegate
(<
Widget
>[
new
SizedBox
(
height:
251.0
,
child:
new
Text
(
'a'
)),
new
SizedBox
(
key:
key1
,
height:
253.0
,
child:
new
Text
(
'c'
)),
new
SizedBox
(
height:
252.0
,
child:
new
Text
(
'b'
)),
]),
),
],
));
verify
(
tester
,
<
Point
>[
const
Point
(
0.0
,
0.0
),
const
Point
(
0.0
,
251.0
),
const
Point
(
0.0
,
504.0
),
],
'acb'
);
});
}
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