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
52795630
Commit
52795630
authored
Jun 28, 2017
by
Ian Hickson
Committed by
GitHub
Jun 28, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Keep-alive for widgets in lazy lists (#11010)
parent
57746f38
Changes
10
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
905 additions
and
61 deletions
+905
-61
sliver_fixed_extent_list.dart
...s/flutter/lib/src/rendering/sliver_fixed_extent_list.dart
+3
-2
sliver_grid.dart
packages/flutter/lib/src/rendering/sliver_grid.dart
+3
-2
sliver_multi_box_adaptor.dart
...s/flutter/lib/src/rendering/sliver_multi_box_adaptor.dart
+179
-39
basic.dart
packages/flutter/lib/src/widgets/basic.dart
+3
-2
scroll_view.dart
packages/flutter/lib/src/widgets/scroll_view.dart
+56
-6
sliver.dart
packages/flutter/lib/src/widgets/sliver.dart
+77
-6
slivers_block_test.dart
packages/flutter/test/rendering/slivers_block_test.dart
+19
-0
keep_alive_test.dart
packages/flutter/test/widgets/keep_alive_test.dart
+561
-0
list_view_viewporting_test.dart
...ages/flutter/test/widgets/list_view_viewporting_test.dart
+3
-3
sliver_fill_viewport_test.dart
packages/flutter/test/widgets/sliver_fill_viewport_test.dart
+1
-1
No files found.
packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart
View file @
52795630
...
...
@@ -130,8 +130,9 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda
final
int
oldLastIndex
=
indexOf
(
lastChild
);
final
int
leadingGarbage
=
(
firstIndex
-
oldFirstIndex
).
clamp
(
0
,
childCount
);
final
int
trailingGarbage
=
targetLastIndex
==
null
?
0
:
(
oldLastIndex
-
targetLastIndex
).
clamp
(
0
,
childCount
);
if
(
leadingGarbage
+
trailingGarbage
>
0
)
collectGarbage
(
leadingGarbage
,
trailingGarbage
);
collectGarbage
(
leadingGarbage
,
trailingGarbage
);
}
else
{
collectGarbage
(
0
,
0
);
}
if
(
firstChild
==
null
)
{
...
...
packages/flutter/lib/src/rendering/sliver_grid.dart
View file @
52795630
...
...
@@ -507,8 +507,9 @@ class RenderSliverGrid extends RenderSliverMultiBoxAdaptor {
final
int
oldLastIndex
=
indexOf
(
lastChild
);
final
int
leadingGarbage
=
(
firstIndex
-
oldFirstIndex
).
clamp
(
0
,
childCount
);
final
int
trailingGarbage
=
targetLastIndex
==
null
?
0
:
(
oldLastIndex
-
targetLastIndex
).
clamp
(
0
,
childCount
);
if
(
leadingGarbage
+
trailingGarbage
>
0
)
collectGarbage
(
leadingGarbage
,
trailingGarbage
);
collectGarbage
(
leadingGarbage
,
trailingGarbage
);
}
else
{
collectGarbage
(
0
,
0
);
}
final
SliverGridGeometry
firstChildGridGeometry
=
layout
.
getGeometryForChildIndex
(
firstIndex
);
...
...
packages/flutter/lib/src/rendering/sliver_multi_box_adaptor.dart
View file @
52795630
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/widgets/basic.dart
View file @
52795630
...
...
@@ -1201,8 +1201,9 @@ class CustomSingleChildLayout extends SingleChildRenderObjectWidget {
/// Meta data for identifying children in a [CustomMultiChildLayout].
///
/// The [MultiChildLayoutDelegate] hasChild, layoutChild, and positionChild
/// methods use these identifiers.
/// The [MultiChildLayoutDelegate.hasChild],
/// [MultiChildLayoutDelegate.layoutChild], and
/// [MultiChildLayoutDelegate.positionChild] methods use these identifiers.
class
LayoutId
extends
ParentDataWidget
<
CustomMultiChildLayout
>
{
/// Marks a child with a layout identifier.
///
...
...
packages/flutter/lib/src/widgets/scroll_view.dart
View file @
52795630
...
...
@@ -514,6 +514,10 @@ class ListView extends BoxScrollView {
///
/// It is usually more efficient to create children on demand using [new
/// ListView.builder].
///
/// The `addRepaintBoundaries` argument corresponds to the
/// [SliverChildListDelegate.addRepaintBoundaries] property and must not be
/// null.
ListView
({
Key
key
,
Axis
scrollDirection:
Axis
.
vertical
,
...
...
@@ -524,8 +528,12 @@ class ListView extends BoxScrollView {
bool
shrinkWrap:
false
,
EdgeInsets
padding
,
this
.
itemExtent
,
bool
addRepaintBoundaries:
true
,
List
<
Widget
>
children:
const
<
Widget
>[],
})
:
childrenDelegate
=
new
SliverChildListDelegate
(
children
),
super
(
})
:
childrenDelegate
=
new
SliverChildListDelegate
(
children
,
addRepaintBoundaries:
addRepaintBoundaries
,
),
super
(
key:
key
,
scrollDirection:
scrollDirection
,
reverse:
reverse
,
...
...
@@ -554,6 +562,10 @@ class ListView extends BoxScrollView {
/// [ListView] itself is created, it is more efficient to use [new ListView].
/// Even more efficient, however, is to create the instances on demand using
/// this constructor's `itemBuilder` callback.
///
/// The `addRepaintBoundaries` argument corresponds to the
/// [SliverChildBuilderDelegate.addRepaintBoundaries] property and must not be
/// null.
ListView
.
builder
({
Key
key
,
Axis
scrollDirection:
Axis
.
vertical
,
...
...
@@ -566,7 +578,12 @@ class ListView extends BoxScrollView {
this
.
itemExtent
,
@required
IndexedWidgetBuilder
itemBuilder
,
int
itemCount
,
})
:
childrenDelegate
=
new
SliverChildBuilderDelegate
(
itemBuilder
,
childCount:
itemCount
),
super
(
bool
addRepaintBoundaries:
true
,
})
:
childrenDelegate
=
new
SliverChildBuilderDelegate
(
itemBuilder
,
childCount:
itemCount
,
addRepaintBoundaries:
addRepaintBoundaries
,
),
super
(
key:
key
,
scrollDirection:
scrollDirection
,
reverse:
reverse
,
...
...
@@ -765,6 +782,10 @@ class GridView extends BoxScrollView {
/// [SliverGridDelegate].
///
/// The [gridDelegate] argument must not be null.
///
/// The `addRepaintBoundaries` argument corresponds to the
/// [SliverChildListDelegate.addRepaintBoundaries] property and must not be
/// null.
GridView
({
Key
key
,
Axis
scrollDirection:
Axis
.
vertical
,
...
...
@@ -775,9 +796,13 @@ class GridView extends BoxScrollView {
bool
shrinkWrap:
false
,
EdgeInsets
padding
,
@required
this
.
gridDelegate
,
bool
addRepaintBoundaries:
true
,
List
<
Widget
>
children:
const
<
Widget
>[],
})
:
assert
(
gridDelegate
!=
null
),
childrenDelegate
=
new
SliverChildListDelegate
(
children
),
childrenDelegate
=
new
SliverChildListDelegate
(
children
,
addRepaintBoundaries:
addRepaintBoundaries
,
),
super
(
key:
key
,
scrollDirection:
scrollDirection
,
...
...
@@ -802,6 +827,10 @@ class GridView extends BoxScrollView {
/// zero and less than `itemCount`.
///
/// The [gridDelegate] argument must not be null.
///
/// The `addRepaintBoundaries` argument corresponds to the
/// [SliverChildBuilderDelegate.addRepaintBoundaries] property and must not be
/// null.
GridView
.
builder
({
Key
key
,
Axis
scrollDirection:
Axis
.
vertical
,
...
...
@@ -814,8 +843,13 @@ class GridView extends BoxScrollView {
@required
this
.
gridDelegate
,
@required
IndexedWidgetBuilder
itemBuilder
,
int
itemCount
,
bool
addRepaintBoundaries:
true
,
})
:
assert
(
gridDelegate
!=
null
),
childrenDelegate
=
new
SliverChildBuilderDelegate
(
itemBuilder
,
childCount:
itemCount
),
childrenDelegate
=
new
SliverChildBuilderDelegate
(
itemBuilder
,
childCount:
itemCount
,
addRepaintBoundaries:
addRepaintBoundaries
,
),
super
(
key:
key
,
scrollDirection:
scrollDirection
,
...
...
@@ -863,6 +897,10 @@ class GridView extends BoxScrollView {
///
/// Uses a [SliverGridDelegateWithFixedCrossAxisCount] as the [gridDelegate].
///
/// The `addRepaintBoundaries` argument corresponds to the
/// [SliverChildListDelegate.addRepaintBoundaries] property and must not be
/// null.
///
/// See also:
///
/// * [new SliverGrid.count], the equivalent constructor for [SliverGrid].
...
...
@@ -879,6 +917,7 @@ class GridView extends BoxScrollView {
double
mainAxisSpacing:
0.0
,
double
crossAxisSpacing:
0.0
,
double
childAspectRatio:
1.0
,
bool
addRepaintBoundaries:
true
,
List
<
Widget
>
children:
const
<
Widget
>[],
})
:
gridDelegate
=
new
SliverGridDelegateWithFixedCrossAxisCount
(
crossAxisCount:
crossAxisCount
,
...
...
@@ -886,7 +925,10 @@ class GridView extends BoxScrollView {
crossAxisSpacing:
crossAxisSpacing
,
childAspectRatio:
childAspectRatio
,
),
childrenDelegate
=
new
SliverChildListDelegate
(
children
),
super
(
childrenDelegate
=
new
SliverChildListDelegate
(
children
,
addRepaintBoundaries:
addRepaintBoundaries
,
),
super
(
key:
key
,
scrollDirection:
scrollDirection
,
reverse:
reverse
,
...
...
@@ -902,6 +944,10 @@ class GridView extends BoxScrollView {
///
/// Uses a [SliverGridDelegateWithMaxCrossAxisExtent] as the [gridDelegate].
///
/// The `addRepaintBoundaries` argument corresponds to the
/// [SliverChildListDelegate.addRepaintBoundaries] property and must not be
/// null.
///
/// See also:
///
/// * [new SliverGrid.extent], the equivalent constructor for [SliverGrid].
...
...
@@ -918,6 +964,7 @@ class GridView extends BoxScrollView {
double
mainAxisSpacing:
0.0
,
double
crossAxisSpacing:
0.0
,
double
childAspectRatio:
1.0
,
bool
addRepaintBoundaries:
true
,
List
<
Widget
>
children:
const
<
Widget
>[],
})
:
gridDelegate
=
new
SliverGridDelegateWithMaxCrossAxisExtent
(
maxCrossAxisExtent:
maxCrossAxisExtent
,
...
...
@@ -925,7 +972,10 @@ class GridView extends BoxScrollView {
crossAxisSpacing:
crossAxisSpacing
,
childAspectRatio:
childAspectRatio
,
),
childrenDelegate
=
new
SliverChildListDelegate
(
children
),
super
(
childrenDelegate
=
new
SliverChildListDelegate
(
children
,
addRepaintBoundaries:
addRepaintBoundaries
,
),
super
(
key:
key
,
scrollDirection:
scrollDirection
,
reverse:
reverse
,
...
...
packages/flutter/lib/src/widgets/sliver.dart
View file @
52795630
...
...
@@ -115,8 +115,11 @@ abstract class SliverChildDelegate {
///
/// Many slivers lazily construct their box children to avoid creating more
/// children than are visible through the [Viewport]. This delegate provides
/// children using an [IndexedWidgetBuilder] callback. The widgets returned from
/// the builder callback are wrapped in [RepaintBoundary] widgets.
/// children using an [IndexedWidgetBuilder] callback, so that the children do
/// not even have to be built until they are displayed.
///
/// The widgets returned from the builder callback are automatically wrapped in
/// [RepaintBoundary] widgets if [addRepaintBoundaries] is true (the default).
///
/// See also:
///
...
...
@@ -124,8 +127,15 @@ abstract class SliverChildDelegate {
/// of children.
class
SliverChildBuilderDelegate
extends
SliverChildDelegate
{
/// Creates a delegate that supplies children for slivers using the given
/// builder callback
const
SliverChildBuilderDelegate
(
this
.
builder
,
{
this
.
childCount
});
/// builder callback.
///
/// The [builder] and [addRepaintBoundaries] arguments must not be null.
const
SliverChildBuilderDelegate
(
this
.
builder
,
{
this
.
childCount
,
this
.
addRepaintBoundaries
:
true
,
})
:
assert
(
builder
!=
null
),
assert
(
addRepaintBoundaries
!=
null
);
/// Called to build children for the sliver.
///
...
...
@@ -145,6 +155,17 @@ class SliverChildBuilderDelegate extends SliverChildDelegate {
/// [builder] returns null.
final
int
childCount
;
/// Whether to wrap each child in a [RepaintBoundary].
///
/// Typically, children in a scrolling container are wrapped in repaint
/// boundaries so that they do not need to be repainted as the list scrolls.
/// If the children are easy to repaint (e.g., solid color blocks or a short
/// snippet of text), it might be more efficient to not add a repaint boundary
/// and simply repaint the children during scrolling.
///
/// Defaults to true.
final
bool
addRepaintBoundaries
;
@override
Widget
build
(
BuildContext
context
,
int
index
)
{
assert
(
builder
!=
null
);
...
...
@@ -153,7 +174,7 @@ class SliverChildBuilderDelegate extends SliverChildDelegate {
final
Widget
child
=
builder
(
context
,
index
);
if
(
child
==
null
)
return
null
;
return
new
RepaintBoundary
.
wrap
(
child
,
index
)
;
return
addRepaintBoundaries
?
new
RepaintBoundary
.
wrap
(
child
,
index
)
:
child
;
}
@override
...
...
@@ -183,6 +204,9 @@ class SliverChildBuilderDelegate extends SliverChildDelegate {
/// demand). For example, the body of a dialog box might fit both of these
/// conditions.
///
/// The widgets in the given [children] list are automatically wrapped in
/// [RepaintBoundary] widgets if [addRepaintBoundaries] is true (the default).
///
/// See also:
///
/// * [SliverChildBuilderDelegate], which is a delegate that uses a builder
...
...
@@ -190,7 +214,13 @@ class SliverChildBuilderDelegate extends SliverChildDelegate {
class
SliverChildListDelegate
extends
SliverChildDelegate
{
/// Creates a delegate that supplies children for slivers using the given
/// list.
const
SliverChildListDelegate
(
this
.
children
,
{
this
.
addRepaintBoundaries
:
true
});
///
/// The [children] and [addRepaintBoundaries] arguments must not be null.
const
SliverChildListDelegate
(
this
.
children
,
{
this
.
addRepaintBoundaries
:
true
,
})
:
assert
(
children
!=
null
),
assert
(
addRepaintBoundaries
!=
null
);
/// Whether to wrap each child in a [RepaintBoundary].
///
...
...
@@ -815,3 +845,44 @@ class SliverFillRemaining extends SingleChildRenderObjectWidget {
@override
RenderSliverFillRemaining
createRenderObject
(
BuildContext
context
)
=>
new
RenderSliverFillRemaining
();
}
/// Mark a child as needing to stay alive even when it's in a lazy list that
/// would otherwise remove it.
///
/// This widget is for use in [SliverMultiBoxAdaptorWidget]s, such as
/// [SliverGrid] or [SliverList].
class
KeepAlive
extends
ParentDataWidget
<
SliverMultiBoxAdaptorWidget
>
{
/// Marks a child as needing to remain alive.
///
/// The [child] and [keepAlive] arguments must not be null.
KeepAlive
({
Key
key
,
@required
this
.
keepAlive
,
@required
Widget
child
,
})
:
assert
(
child
!=
null
),
assert
(
keepAlive
!=
null
),
super
(
key:
key
,
child:
child
);
/// Whether to keep the child alive.
///
/// If this is false, it is as if this widget was omitted.
final
bool
keepAlive
;
@override
void
applyParentData
(
RenderObject
renderObject
)
{
assert
(
renderObject
.
parentData
is
SliverMultiBoxAdaptorParentData
);
final
SliverMultiBoxAdaptorParentData
parentData
=
renderObject
.
parentData
;
if
(
parentData
.
keepAlive
!=
keepAlive
)
{
parentData
.
keepAlive
=
keepAlive
;
final
AbstractNode
targetParent
=
renderObject
.
parent
;
if
(
targetParent
is
RenderObject
)
targetParent
.
markNeedsLayout
();
}
}
@override
void
debugFillDescription
(
List
<
String
>
description
)
{
super
.
debugFillDescription
(
description
);
description
.
add
(
'keepAlive:
$keepAlive
'
);
}
}
packages/flutter/test/rendering/slivers_block_test.dart
View file @
52795630
...
...
@@ -244,4 +244,23 @@ void main() {
expect
(
inner
.
geometry
.
scrollOffsetCorrection
,
isNull
);
});
test
(
'SliverMultiBoxAdaptorParentData.toString'
,
()
{
final
SliverMultiBoxAdaptorParentData
candidate
=
new
SliverMultiBoxAdaptorParentData
();
expect
(
candidate
.
keepAlive
,
isFalse
);
expect
(
candidate
.
index
,
isNull
);
expect
(
candidate
.
toString
(),
'index=null; layoutOffset=0.0'
);
candidate
.
keepAlive
=
null
;
expect
(
candidate
.
toString
(),
'index=null; layoutOffset=0.0'
);
candidate
.
keepAlive
=
true
;
expect
(
candidate
.
toString
(),
'index=null; keepAlive; layoutOffset=0.0'
);
candidate
.
keepAlive
=
false
;
expect
(
candidate
.
toString
(),
'index=null; layoutOffset=0.0'
);
candidate
.
index
=
0
;
expect
(
candidate
.
toString
(),
'index=0; layoutOffset=0.0'
);
candidate
.
index
=
1
;
expect
(
candidate
.
toString
(),
'index=1; layoutOffset=0.0'
);
candidate
.
index
=
-
1
;
expect
(
candidate
.
toString
(),
'index=-1; layoutOffset=0.0'
);
});
}
packages/flutter/test/widgets/keep_alive_test.dart
0 → 100644
View file @
52795630
This diff is collapsed.
Click to expand it.
packages/flutter/test/widgets/list_view_viewporting_test.dart
View file @
52795630
...
...
@@ -295,7 +295,7 @@ void main() {
' │ maxPaintExtent: 300.0, )
\n
'
' │ currently live children: 0 to 2
\n
'
' │
\n
'
' ├─child
1
: RenderRepaintBoundary#00000 relayoutBoundary=up2
\n
'
' ├─child
with index 0
: RenderRepaintBoundary#00000 relayoutBoundary=up2
\n
'
' │ │ creator: RepaintBoundary-[<0>] ← SliverList ← Viewport ←
\n
'
' │ │ _ScrollableScope ← IgnorePointer-[GlobalKey#00000] ← Listener ←
\n
'
' │ │ _GestureSemantics ←
\n
'
...
...
@@ -347,7 +347,7 @@ void main() {
' │ size: Size(800.0, 100.0)
\n
'
' │ additionalConstraints: BoxConstraints(biggest)
\n
'
' │
\n
'
' ├─child
2
: RenderRepaintBoundary#00000 relayoutBoundary=up2
\n
'
' ├─child
with index 1
: RenderRepaintBoundary#00000 relayoutBoundary=up2
\n
'
' │ │ creator: RepaintBoundary-[<1>] ← SliverList ← Viewport ←
\n
'
' │ │ _ScrollableScope ← IgnorePointer-[GlobalKey#00000] ← Listener ←
\n
'
' │ │ _GestureSemantics ←
\n
'
...
...
@@ -399,7 +399,7 @@ void main() {
' │ size: Size(800.0, 100.0)
\n
'
' │ additionalConstraints: BoxConstraints(biggest)
\n
'
' │
\n
'
' └─child
3
: RenderRepaintBoundary#00000 relayoutBoundary=up2
\n
'
' └─child
with index 2
: RenderRepaintBoundary#00000 relayoutBoundary=up2
\n
'
' │ creator: RepaintBoundary-[<2>] ← SliverList ← Viewport ←
\n
'
' │ _ScrollableScope ← IgnorePointer-[GlobalKey#00000] ← Listener ←
\n
'
' │ _GestureSemantics ←
\n
'
...
...
packages/flutter/test/widgets/sliver_fill_viewport_test.dart
View file @
52795630
...
...
@@ -80,7 +80,7 @@ void main() {
' │ 600.0, maxPaintExtent: 12000.0, hasVisualOverflow: true, )
\n
'
' │ currently live children: 0 to 0
\n
'
' │
\n
'
' └─child
1
: RenderRepaintBoundary#00000
\n
'
' └─child
with index 0
: RenderRepaintBoundary#00000
\n
'
' │ creator: RepaintBoundary-[<0>] ← SliverFillViewport ← Viewport ←
\n
'
' │ _ScrollableScope ← IgnorePointer-[GlobalKey#00000] ← Listener ←
\n
'
' │ _GestureSemantics ←
\n
'
...
...
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