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
765e5d5b
Commit
765e5d5b
authored
May 16, 2017
by
Hans Muller
Committed by
GitHub
May 16, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added SliverPrototypeExtentList et al (#10097)
parent
73dcca65
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
339 additions
and
4 deletions
+339
-4
sliver_fixed_extent_list.dart
...s/flutter/lib/src/rendering/sliver_fixed_extent_list.dart
+4
-0
basic.dart
packages/flutter/lib/src/widgets/basic.dart
+5
-3
sliver.dart
packages/flutter/lib/src/widgets/sliver.dart
+13
-1
sliver_prototype_item_list.dart
...s/flutter/lib/src/widgets/sliver_prototype_item_list.dart
+183
-0
widgets.dart
packages/flutter/lib/widgets.dart
+1
-0
sliver_prototype_item_extent_test.dart
...utter/test/widgets/sliver_prototype_item_extent_test.dart
+133
-0
No files found.
packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart
View file @
765e5d5b
...
@@ -28,6 +28,8 @@ import 'sliver_multi_box_adaptor.dart';
...
@@ -28,6 +28,8 @@ import 'sliver_multi_box_adaptor.dart';
/// See also:
/// See also:
///
///
/// * [RenderSliverFixedExtentList], which has a configurable [itemExtent].
/// * [RenderSliverFixedExtentList], which has a configurable [itemExtent].
/// * [RenderSliverPrototypeExtentList], which uses a prototype list item
/// instead of a pixel value, to define the extent of each item.
/// * [RenderSliverFillViewport], which determines the [itemExtent] based on
/// * [RenderSliverFillViewport], which determines the [itemExtent] based on
/// [SliverConstraints.viewportMainAxisExtent].
/// [SliverConstraints.viewportMainAxisExtent].
/// * [RenderSliverFillRemaining], which determines the [itemExtent] based on
/// * [RenderSliverFillRemaining], which determines the [itemExtent] based on
...
@@ -231,6 +233,8 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda
...
@@ -231,6 +233,8 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda
///
///
/// See also:
/// See also:
///
///
/// * [RenderSliverPrototypeExtentList], which uses a prototype list item
/// instead of a pixel value, to define the extent of each item.
/// * [RenderSliverList], which does not require its children to have the same
/// * [RenderSliverList], which does not require its children to have the same
/// extent in the main axis.
/// extent in the main axis.
/// * [RenderSliverFillViewport], which determines the [itemExtent] based on
/// * [RenderSliverFillViewport], which determines the [itemExtent] based on
...
...
packages/flutter/lib/src/widgets/basic.dart
View file @
765e5d5b
...
@@ -1557,9 +1557,9 @@ class Baseline extends SingleChildRenderObjectWidget {
...
@@ -1557,9 +1557,9 @@ class Baseline extends SingleChildRenderObjectWidget {
///
///
/// Rather than using multiple [SliverToBoxAdapter] widgets to display multiple
/// Rather than using multiple [SliverToBoxAdapter] widgets to display multiple
/// box widgets in a [CustomScrollView], consider using [SliverList],
/// box widgets in a [CustomScrollView], consider using [SliverList],
/// [SliverFixedExtentList],
or [SliverGrid], which are more efficient because
/// [SliverFixedExtentList],
[SliverPrototypeExtentList], or [SliverGrid],
///
they instantiate only those children that are actually visible through the
///
which are more efficient because they instantiate only those children that
/// scroll view's viewport.
///
are actually visible through the
scroll view's viewport.
///
///
/// See also:
/// See also:
///
///
...
@@ -1567,6 +1567,8 @@ class Baseline extends SingleChildRenderObjectWidget {
...
@@ -1567,6 +1567,8 @@ class Baseline extends SingleChildRenderObjectWidget {
/// * [SliverList], which displays multiple box widgets in a linear array.
/// * [SliverList], which displays multiple box widgets in a linear array.
/// * [SliverFixedExtentList], which displays multiple box widgets with the
/// * [SliverFixedExtentList], which displays multiple box widgets with the
/// same main-axis extent in a linear array.
/// same main-axis extent in a linear array.
/// * [SliverPrototypeExtentList], which displays multiple box widgets with the
/// same main-axis extent as a prototype item, in a linear array.
/// * [SliverGrid], which displays multiple box widgets in arbitrary positions.
/// * [SliverGrid], which displays multiple box widgets in arbitrary positions.
class
SliverToBoxAdapter
extends
SingleChildRenderObjectWidget
{
class
SliverToBoxAdapter
extends
SingleChildRenderObjectWidget
{
/// Creates a sliver that contains a single box widget.
/// Creates a sliver that contains a single box widget.
...
...
packages/flutter/lib/src/widgets/sliver.dart
View file @
765e5d5b
...
@@ -304,6 +304,9 @@ abstract class SliverMultiBoxAdaptorWidget extends RenderObjectWidget {
...
@@ -304,6 +304,9 @@ abstract class SliverMultiBoxAdaptorWidget extends RenderObjectWidget {
///
///
/// * [SliverFixedExtentList], which is more efficient for children with
/// * [SliverFixedExtentList], which is more efficient for children with
/// the same extent in the main axis.
/// the same extent in the main axis.
/// * [SliverPrototypeExtentList], which is similar to [SliverFixedExtentList]
/// except that it uses a prototype list item intead a pixel value to define
/// the main axis extent of each item.
/// * [SliverGrid], which places its children in arbitrary positions.
/// * [SliverGrid], which places its children in arbitrary positions.
class
SliverList
extends
SliverMultiBoxAdaptorWidget
{
class
SliverList
extends
SliverMultiBoxAdaptorWidget
{
/// Creates a sliver that places box children in a linear array.
/// Creates a sliver that places box children in a linear array.
...
@@ -333,6 +336,9 @@ class SliverList extends SliverMultiBoxAdaptorWidget {
...
@@ -333,6 +336,9 @@ class SliverList extends SliverMultiBoxAdaptorWidget {
///
///
/// See also:
/// See also:
///
///
/// * [SliverPrototypeExtentList], which is similar to [SliverFixedExtentList]
/// except that it uses a prototype list item intead a pixel value to define
/// the main axis extent of each item.
/// * [SliverFillViewport], which determines the [itemExtent] based on
/// * [SliverFillViewport], which determines the [itemExtent] based on
/// [SliverConstraints.viewportMainAxisExtent].
/// [SliverConstraints.viewportMainAxisExtent].
/// * [SliverList], which does not require its children to have the same
/// * [SliverList], which does not require its children to have the same
...
@@ -372,6 +378,9 @@ class SliverFixedExtentList extends SliverMultiBoxAdaptorWidget {
...
@@ -372,6 +378,9 @@ class SliverFixedExtentList extends SliverMultiBoxAdaptorWidget {
/// * [SliverList], which places its children in a linear array.
/// * [SliverList], which places its children in a linear array.
/// * [SliverFixedExtentList], which places its children in a linear
/// * [SliverFixedExtentList], which places its children in a linear
/// array with a fixed extent in the main axis.
/// array with a fixed extent in the main axis.
/// * [SliverPrototypeExtentList], which is similar to [SliverFixedExtentList]
/// except that it uses a prototype list item intead a pixel value to define
/// the main axis extent of each item.
class
SliverGrid
extends
SliverMultiBoxAdaptorWidget
{
class
SliverGrid
extends
SliverMultiBoxAdaptorWidget
{
/// Creates a sliver that places multiple box children in a two dimensional
/// Creates a sliver that places multiple box children in a two dimensional
/// arrangement.
/// arrangement.
...
@@ -423,6 +432,9 @@ class SliverGrid extends SliverMultiBoxAdaptorWidget {
...
@@ -423,6 +432,9 @@ class SliverGrid extends SliverMultiBoxAdaptorWidget {
///
///
/// * [SliverFixedExtentList], which has a configurable
/// * [SliverFixedExtentList], which has a configurable
/// [SliverFixedExtentList.itemExtent].
/// [SliverFixedExtentList.itemExtent].
/// * [SliverPrototypeExtentList], which is similar to [SliverFixedExtentList]
/// except that it uses a prototype list item intead a pixel value to define
/// the main axis extent of each item.
/// * [SliverList], which does not require its children to have the same
/// * [SliverList], which does not require its children to have the same
/// extent in the main axis.
/// extent in the main axis.
class
SliverFillViewport
extends
SliverMultiBoxAdaptorWidget
{
class
SliverFillViewport
extends
SliverMultiBoxAdaptorWidget
{
...
@@ -469,7 +481,7 @@ class SliverMultiBoxAdaptorElement extends RenderObjectElement implements Render
...
@@ -469,7 +481,7 @@ class SliverMultiBoxAdaptorElement extends RenderObjectElement implements Render
RenderSliverMultiBoxAdaptor
get
renderObject
=>
super
.
renderObject
;
RenderSliverMultiBoxAdaptor
get
renderObject
=>
super
.
renderObject
;
@override
@override
void
update
(
SliverMultiBoxAdaptorWidget
newWidget
)
{
void
update
(
covariant
SliverMultiBoxAdaptorWidget
newWidget
)
{
final
SliverMultiBoxAdaptorWidget
oldWidget
=
widget
;
final
SliverMultiBoxAdaptorWidget
oldWidget
=
widget
;
super
.
update
(
newWidget
);
super
.
update
(
newWidget
);
final
SliverChildDelegate
newDelegate
=
newWidget
.
delegate
;
final
SliverChildDelegate
newDelegate
=
newWidget
.
delegate
;
...
...
packages/flutter/lib/src/widgets/sliver_prototype_item_list.dart
0 → 100644
View file @
765e5d5b
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/foundation.dart'
;
import
'package:flutter/rendering.dart'
;
import
'basic.dart'
;
import
'framework.dart'
;
import
'sliver.dart'
;
/// A sliver that places its box children in a linear array and constrains them
/// to have the same extent as a prototype item along the main axis.
///
/// [SliverPrototypeExtentList] arranges its children in a line along
/// the main axis starting at offset zero and without gaps. Each child is
/// constrained to the same extent as the [prototypeItem] along the main axis
/// and the [SliverConstraints.crossAxisExtent] along the cross axis.
///
/// [SliverPrototypeExtentList] is more efficient than [SliverList] because
/// [SliverPrototypeExtentList] does not need to lay out its children to obtain
/// their extent along the main axis. It's a little more flexible than
/// [SliverFixedExtentList] because there's no need to determine the approriate
/// item extent in pixels.
///
/// See also:
///
/// * [SliverFixedExtentList], whose [itemExtent] is a pixel value.
/// * [SliverList], which does not require its children to have the same
/// extent in the main axis.
/// * [SliverFillViewport], which sizes its children based on the
/// size of the viewport, regardless of what else is in the scroll view.
/// * [SliverList], which shows a list of variable-sized children in a
/// viewport.
class
SliverPrototypeExtentList
extends
SliverMultiBoxAdaptorWidget
{
/// Creates a sliver that places its box children in a linear array and
/// constrains them to have the same extent as a prototype item along
/// the main axis.
const
SliverPrototypeExtentList
({
Key
key
,
@required
SliverChildDelegate
delegate
,
@required
this
.
prototypeItem
,
})
:
assert
(
prototypeItem
!=
null
),
super
(
key:
key
,
delegate:
delegate
);
/// Defines the main axis extent of all of this sliver's children.
///
/// The [prototypeItem] is laid out before the rest of the sliver's children
/// and its size along the main axis fixes the size of each child. The
/// [prototypeItem] is essentially [Offstage]: it is not painted and it
/// cannot respond to input.
final
Widget
prototypeItem
;
@override
_RenderSliverPrototypeExtentList
createRenderObject
(
BuildContext
context
)
{
final
_SliverPrototypeExtentListElement
element
=
context
;
return
new
_RenderSliverPrototypeExtentList
(
childManager:
element
);
}
@override
_SliverPrototypeExtentListElement
createElement
()
=>
new
_SliverPrototypeExtentListElement
(
this
);
}
class
_SliverPrototypeExtentListElement
extends
SliverMultiBoxAdaptorElement
{
_SliverPrototypeExtentListElement
(
SliverPrototypeExtentList
widget
)
:
super
(
widget
);
@override
SliverPrototypeExtentList
get
widget
=>
super
.
widget
;
@override
_RenderSliverPrototypeExtentList
get
renderObject
=>
super
.
renderObject
;
Element
_prototype
;
static
final
Object
_prototypeSlot
=
new
Object
();
@override
void
insertChildRenderObject
(
covariant
RenderObject
child
,
covariant
dynamic
slot
)
{
if
(
slot
==
_prototypeSlot
)
{
assert
(
child
is
RenderBox
);
renderObject
.
child
=
child
;
}
else
{
super
.
insertChildRenderObject
(
child
,
slot
);
}
}
@override
void
didAdoptChild
(
RenderBox
child
)
{
if
(
child
!=
renderObject
.
child
)
super
.
didAdoptChild
(
child
);
}
@override
void
moveChildRenderObject
(
RenderBox
child
,
dynamic
slot
)
{
if
(
slot
==
_prototypeSlot
)
assert
(
false
);
// There's only one prototype child so it cannot be moved.
else
super
.
moveChildRenderObject
(
child
,
slot
);
}
@override
void
removeChildRenderObject
(
RenderBox
child
)
{
if
(
renderObject
.
child
==
child
)
renderObject
.
child
=
null
;
else
super
.
removeChildRenderObject
(
child
);
}
@override
void
visitChildren
(
ElementVisitor
visitor
)
{
if
(
_prototype
!=
null
)
visitor
(
_prototype
);
super
.
visitChildren
(
visitor
);
}
@override
void
mount
(
Element
parent
,
dynamic
newSlot
)
{
super
.
mount
(
parent
,
newSlot
);
_prototype
=
updateChild
(
_prototype
,
widget
.
prototypeItem
,
_prototypeSlot
);
}
@override
void
update
(
SliverPrototypeExtentList
newWidget
)
{
super
.
update
(
newWidget
);
assert
(
widget
==
newWidget
);
_prototype
=
updateChild
(
_prototype
,
widget
.
prototypeItem
,
_prototypeSlot
);
}
}
class
_RenderSliverPrototypeExtentList
extends
RenderSliverFixedExtentBoxAdaptor
{
_RenderSliverPrototypeExtentList
({
@required
_SliverPrototypeExtentListElement
childManager
,
})
:
super
(
childManager:
childManager
);
RenderBox
_child
;
RenderBox
get
child
=>
_child
;
set
child
(
RenderBox
value
)
{
if
(
_child
!=
null
)
dropChild
(
_child
);
_child
=
value
;
if
(
_child
!=
null
)
adoptChild
(
_child
);
markNeedsLayout
();
}
@override
void
performLayout
()
{
child
.
layout
(
constraints
.
asBoxConstraints
(),
parentUsesSize:
true
);
super
.
performLayout
();
}
@override
void
attach
(
PipelineOwner
owner
)
{
super
.
attach
(
owner
);
if
(
_child
!=
null
)
_child
.
attach
(
owner
);
}
@override
void
detach
()
{
super
.
detach
();
if
(
_child
!=
null
)
_child
.
detach
();
}
@override
void
redepthChildren
()
{
if
(
_child
!=
null
)
redepthChild
(
_child
);
super
.
redepthChildren
();
}
@override
void
visitChildren
(
RenderObjectVisitor
visitor
)
{
if
(
_child
!=
null
)
visitor
(
_child
);
super
.
visitChildren
(
visitor
);
}
@override
double
get
itemExtent
{
assert
(
child
!=
null
&&
child
.
hasSize
);
return
constraints
.
axis
==
Axis
.
vertical
?
child
.
size
.
height
:
child
.
size
.
width
;
}
}
packages/flutter/lib/widgets.dart
View file @
765e5d5b
...
@@ -72,6 +72,7 @@ export 'src/widgets/single_child_scroll_view.dart';
...
@@ -72,6 +72,7 @@ export 'src/widgets/single_child_scroll_view.dart';
export
'src/widgets/size_changed_layout_notifier.dart'
;
export
'src/widgets/size_changed_layout_notifier.dart'
;
export
'src/widgets/sliver.dart'
;
export
'src/widgets/sliver.dart'
;
export
'src/widgets/sliver_persistent_header.dart'
;
export
'src/widgets/sliver_persistent_header.dart'
;
export
'src/widgets/sliver_prototype_item_list.dart'
;
export
'src/widgets/status_transitions.dart'
;
export
'src/widgets/status_transitions.dart'
;
export
'src/widgets/table.dart'
;
export
'src/widgets/table.dart'
;
export
'src/widgets/text.dart'
;
export
'src/widgets/text.dart'
;
...
...
packages/flutter/test/widgets/sliver_prototype_item_extent_test.dart
0 → 100644
View file @
765e5d5b
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter/widgets.dart'
;
class
TestItem
extends
StatelessWidget
{
const
TestItem
({
Key
key
,
this
.
item
,
this
.
width
,
this
.
height
})
:
super
(
key:
key
);
final
int
item
;
final
double
width
;
final
double
height
;
@override
Widget
build
(
BuildContext
context
)
{
return
new
Container
(
width:
width
,
height:
height
,
alignment:
FractionalOffset
.
center
,
child:
new
Text
(
'Item
$item
'
),
);
}
}
Widget
buildFrame
(
{
int
count
,
double
width
,
double
height
,
Axis
scrollDirection
})
{
return
new
CustomScrollView
(
scrollDirection:
scrollDirection
??
Axis
.
vertical
,
slivers:
<
Widget
>[
new
SliverPrototypeExtentList
(
prototypeItem:
new
TestItem
(
item:
-
1
,
width:
width
,
height:
height
),
delegate:
new
SliverChildBuilderDelegate
(
(
BuildContext
context
,
int
index
)
=>
new
TestItem
(
item:
index
),
childCount:
count
,
),
),
],
);
}
void
main
(
)
{
testWidgets
(
'SliverPrototypeExtentList vertical scrolling basics'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
buildFrame
(
count:
20
,
height:
100.0
));
// The viewport is 600 pixels high, lazily created items are 100 pixels high.
for
(
int
i
=
0
;
i
<
6
;
i
+=
1
)
{
final
Finder
item
=
find
.
widgetWithText
(
Container
,
'Item
$i
'
);
expect
(
item
,
findsOneWidget
);
expect
(
tester
.
getTopLeft
(
item
).
dy
,
i
*
100.0
);
expect
(
tester
.
getSize
(
item
).
height
,
100.0
);
}
for
(
int
i
=
7
;
i
<
20
;
i
+=
1
)
expect
(
find
.
text
(
'Item
$i
'
),
findsNothing
);
// Fling scroll to the end.
await
tester
.
fling
(
find
.
text
(
'Item 2'
),
const
Offset
(
0.0
,
-
200.0
),
5000.0
);
await
tester
.
pumpAndSettle
();
for
(
int
i
=
19
;
i
>=
14
;
i
-=
1
)
expect
(
find
.
text
(
'Item
$i
'
),
findsOneWidget
);
for
(
int
i
=
13
;
i
>=
0
;
i
-=
1
)
expect
(
find
.
text
(
'Item
$i
'
),
findsNothing
);
});
testWidgets
(
'SliverPrototypeExtentList horizontal scrolling basics'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
buildFrame
(
count:
20
,
width:
100.0
,
scrollDirection:
Axis
.
horizontal
));
// The viewport is 800 pixels wide, lazily created items are 100 pixels wide.
for
(
int
i
=
0
;
i
<
8
;
i
+=
1
)
{
final
Finder
item
=
find
.
widgetWithText
(
Container
,
'Item
$i
'
);
expect
(
item
,
findsOneWidget
);
expect
(
tester
.
getTopLeft
(
item
).
dx
,
i
*
100.0
);
expect
(
tester
.
getSize
(
item
).
width
,
100.0
);
}
for
(
int
i
=
9
;
i
<
20
;
i
+=
1
)
expect
(
find
.
text
(
'Item
$i
'
),
findsNothing
);
// Fling scroll to the end.
await
tester
.
fling
(
find
.
text
(
'Item 3'
),
const
Offset
(-
200.0
,
0.0
),
5000.0
);
await
tester
.
pumpAndSettle
();
for
(
int
i
=
19
;
i
>=
12
;
i
-=
1
)
expect
(
find
.
text
(
'Item
$i
'
),
findsOneWidget
);
for
(
int
i
=
11
;
i
>=
0
;
i
-=
1
)
expect
(
find
.
text
(
'Item
$i
'
),
findsNothing
);
});
testWidgets
(
'SliverPrototypeExtentList change the prototype item'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
buildFrame
(
count:
10
,
height:
60.0
));
// The viewport is 600 pixels high, each of the 10 items is 60 pixels high
for
(
int
i
=
0
;
i
<
10
;
i
+=
1
)
expect
(
find
.
text
(
'Item
$i
'
),
findsOneWidget
);
await
tester
.
pumpWidget
(
buildFrame
(
count:
10
,
height:
120.0
));
// Now the items are 120 pixels high, so only 5 fit.
for
(
int
i
=
0
;
i
<
5
;
i
+=
1
)
expect
(
find
.
text
(
'Item
$i
'
),
findsOneWidget
);
for
(
int
i
=
5
;
i
<
10
;
i
+=
1
)
expect
(
find
.
text
(
'Item
$i
'
),
findsNothing
);
await
tester
.
pumpWidget
(
buildFrame
(
count:
10
,
height:
60.0
));
// Now they all fit again
for
(
int
i
=
0
;
i
<
10
;
i
+=
1
)
expect
(
find
.
text
(
'Item
$i
'
),
findsOneWidget
);
});
testWidgets
(
'SliverPrototypeExtentList first item is also the prototype'
,
(
WidgetTester
tester
)
async
{
final
List
<
Widget
>
items
=
new
List
<
Widget
>.
generate
(
10
,
(
int
index
)
{
return
new
TestItem
(
key:
new
ValueKey
<
int
>(
index
),
item:
index
,
height:
index
==
0
?
60.0
:
null
);
}).
toList
();
await
tester
.
pumpWidget
(
new
CustomScrollView
(
slivers:
<
Widget
>[
new
SliverPrototypeExtentList
(
prototypeItem:
items
[
0
],
delegate:
new
SliverChildBuilderDelegate
(
(
BuildContext
context
,
int
index
)
=>
items
[
index
],
childCount:
10
,
),
),
],
)
);
// Item 0 exists in the list and as the prototype item.
expect
(
tester
.
widgetList
(
find
.
text
(
'Item 0'
)).
length
,
2
);
for
(
int
i
=
1
;
i
<
10
;
i
+=
1
)
expect
(
find
.
text
(
'Item
$i
'
),
findsOneWidget
);
});
}
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