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
68f33d30
Commit
68f33d30
authored
Feb 06, 2016
by
Adam Barth
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1642 from abarth/rm_viewport
Remove HomogeneousViewport
parents
bc3202ff
5b896694
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
329 additions
and
522 deletions
+329
-522
date_picker.dart
packages/flutter/lib/src/material/date_picker.dart
+28
-12
grid.dart
packages/flutter/lib/src/rendering/grid.dart
+2
-0
list.dart
packages/flutter/lib/src/rendering/list.dart
+4
-1
viewport.dart
packages/flutter/lib/src/rendering/viewport.dart
+1
-1
homogeneous_viewport.dart
packages/flutter/lib/src/widgets/homogeneous_viewport.dart
+0
-220
pageable_list.dart
packages/flutter/lib/src/widgets/pageable_list.dart
+1
-2
scrollable.dart
packages/flutter/lib/src/widgets/scrollable.dart
+0
-173
scrollable_grid.dart
packages/flutter/lib/src/widgets/scrollable_grid.dart
+1
-2
scrollable_list.dart
packages/flutter/lib/src/widgets/scrollable_list.dart
+148
-20
virtual_viewport.dart
packages/flutter/lib/src/widgets/virtual_viewport.dart
+98
-31
widgets.dart
packages/flutter/lib/widgets.dart
+0
-1
remember_scroll_position_test.dart
...es/flutter/test/widget/remember_scroll_position_test.dart
+13
-19
scrollable_lazy_list_test.dart
packages/flutter/test/widget/scrollable_lazy_list_test.dart
+33
-40
No files found.
packages/flutter/lib/src/material/date_picker.dart
View file @
68f33d30
...
@@ -268,15 +268,15 @@ class DayPicker extends StatelessComponent {
...
@@ -268,15 +268,15 @@ class DayPicker extends StatelessComponent {
}
}
}
}
// Scrollable list of DayPickers to allow choosing a month
class
MonthPicker
extends
StatefulComponent
{
class
MonthPicker
extends
ScrollableWidgetList
{
MonthPicker
({
MonthPicker
({
Key
key
,
this
.
selectedDate
,
this
.
selectedDate
,
this
.
onChanged
,
this
.
onChanged
,
this
.
firstDate
,
this
.
firstDate
,
this
.
lastDate
,
this
.
lastDate
,
double
itemExtent
this
.
itemExtent
})
:
super
(
itemExtent:
itemExtent
)
{
})
:
super
(
key:
key
)
{
assert
(
selectedDate
!=
null
);
assert
(
selectedDate
!=
null
);
assert
(
onChanged
!=
null
);
assert
(
onChanged
!=
null
);
assert
(
lastDate
.
isAfter
(
firstDate
));
assert
(
lastDate
.
isAfter
(
firstDate
));
...
@@ -286,11 +286,12 @@ class MonthPicker extends ScrollableWidgetList {
...
@@ -286,11 +286,12 @@ class MonthPicker extends ScrollableWidgetList {
final
ValueChanged
<
DateTime
>
onChanged
;
final
ValueChanged
<
DateTime
>
onChanged
;
final
DateTime
firstDate
;
final
DateTime
firstDate
;
final
DateTime
lastDate
;
final
DateTime
lastDate
;
final
double
itemExtent
;
_MonthPickerState
createState
()
=>
new
_MonthPickerState
();
_MonthPickerState
createState
()
=>
new
_MonthPickerState
();
}
}
class
_MonthPickerState
extends
S
crollableWidgetListS
tate
<
MonthPicker
>
{
class
_MonthPickerState
extends
State
<
MonthPicker
>
{
void
initState
()
{
void
initState
()
{
super
.
initState
();
super
.
initState
();
_updateCurrentDate
();
_updateCurrentDate
();
...
@@ -313,8 +314,6 @@ class _MonthPickerState extends ScrollableWidgetListState<MonthPicker> {
...
@@ -313,8 +314,6 @@ class _MonthPickerState extends ScrollableWidgetListState<MonthPicker> {
});
});
}
}
int
get
itemCount
=>
(
config
.
lastDate
.
year
-
config
.
firstDate
.
year
)
*
12
+
config
.
lastDate
.
month
-
config
.
firstDate
.
month
+
1
;
List
<
Widget
>
buildItems
(
BuildContext
context
,
int
start
,
int
count
)
{
List
<
Widget
>
buildItems
(
BuildContext
context
,
int
start
,
int
count
)
{
List
<
Widget
>
result
=
new
List
<
Widget
>();
List
<
Widget
>
result
=
new
List
<
Widget
>();
DateTime
startDate
=
new
DateTime
(
config
.
firstDate
.
year
+
start
~/
12
,
config
.
firstDate
.
month
+
start
%
12
);
DateTime
startDate
=
new
DateTime
(
config
.
firstDate
.
year
+
start
~/
12
,
config
.
firstDate
.
month
+
start
%
12
);
...
@@ -335,6 +334,14 @@ class _MonthPickerState extends ScrollableWidgetListState<MonthPicker> {
...
@@ -335,6 +334,14 @@ class _MonthPickerState extends ScrollableWidgetListState<MonthPicker> {
return
result
;
return
result
;
}
}
Widget
build
(
BuildContext
context
)
{
return
new
ScrollableLazyList
(
itemExtent:
config
.
itemExtent
,
itemCount:
(
config
.
lastDate
.
year
-
config
.
firstDate
.
year
)
*
12
+
config
.
lastDate
.
month
-
config
.
firstDate
.
month
+
1
,
itemBuilder:
buildItems
);
}
void
dispose
()
{
void
dispose
()
{
if
(
_timer
!=
null
)
if
(
_timer
!=
null
)
_timer
.
cancel
();
_timer
.
cancel
();
...
@@ -343,13 +350,14 @@ class _MonthPickerState extends ScrollableWidgetListState<MonthPicker> {
...
@@ -343,13 +350,14 @@ class _MonthPickerState extends ScrollableWidgetListState<MonthPicker> {
}
}
// Scrollable list of years to allow picking a year
// Scrollable list of years to allow picking a year
class
YearPicker
extends
S
crollableWidgetLis
t
{
class
YearPicker
extends
S
tatefulComponen
t
{
YearPicker
({
YearPicker
({
Key
key
,
this
.
selectedDate
,
this
.
selectedDate
,
this
.
onChanged
,
this
.
onChanged
,
this
.
firstDate
,
this
.
firstDate
,
this
.
lastDate
this
.
lastDate
})
:
super
(
itemExtent:
50.0
)
{
})
:
super
(
key:
key
)
{
assert
(
selectedDate
!=
null
);
assert
(
selectedDate
!=
null
);
assert
(
onChanged
!=
null
);
assert
(
onChanged
!=
null
);
assert
(
lastDate
.
isAfter
(
firstDate
));
assert
(
lastDate
.
isAfter
(
firstDate
));
...
@@ -363,8 +371,8 @@ class YearPicker extends ScrollableWidgetList {
...
@@ -363,8 +371,8 @@ class YearPicker extends ScrollableWidgetList {
_YearPickerState
createState
()
=>
new
_YearPickerState
();
_YearPickerState
createState
()
=>
new
_YearPickerState
();
}
}
class
_YearPickerState
extends
S
crollableWidgetListS
tate
<
YearPicker
>
{
class
_YearPickerState
extends
State
<
YearPicker
>
{
int
get
itemCount
=>
config
.
lastDate
.
year
-
config
.
firstDate
.
year
+
1
;
static
const
double
_itemExtent
=
50.0
;
List
<
Widget
>
buildItems
(
BuildContext
context
,
int
start
,
int
count
)
{
List
<
Widget
>
buildItems
(
BuildContext
context
,
int
start
,
int
count
)
{
TextStyle
style
=
Theme
.
of
(
context
).
text
.
body1
.
copyWith
(
color:
Colors
.
black54
);
TextStyle
style
=
Theme
.
of
(
context
).
text
.
body1
.
copyWith
(
color:
Colors
.
black54
);
...
@@ -379,7 +387,7 @@ class _YearPickerState extends ScrollableWidgetListState<YearPicker> {
...
@@ -379,7 +387,7 @@ class _YearPickerState extends ScrollableWidgetListState<YearPicker> {
config
.
onChanged
(
result
);
config
.
onChanged
(
result
);
},
},
child:
new
Container
(
child:
new
Container
(
height:
config
.
itemExtent
,
height:
_
itemExtent
,
decoration:
year
==
config
.
selectedDate
.
year
?
new
BoxDecoration
(
decoration:
year
==
config
.
selectedDate
.
year
?
new
BoxDecoration
(
backgroundColor:
Theme
.
of
(
context
).
primarySwatch
[
100
],
backgroundColor:
Theme
.
of
(
context
).
primarySwatch
[
100
],
shape:
BoxShape
.
circle
shape:
BoxShape
.
circle
...
@@ -393,4 +401,12 @@ class _YearPickerState extends ScrollableWidgetListState<YearPicker> {
...
@@ -393,4 +401,12 @@ class _YearPickerState extends ScrollableWidgetListState<YearPicker> {
}
}
return
items
;
return
items
;
}
}
Widget
build
(
BuildContext
context
)
{
return
new
ScrollableLazyList
(
itemExtent:
_itemExtent
,
itemCount:
config
.
lastDate
.
year
-
config
.
firstDate
.
year
+
1
,
itemBuilder:
buildItems
);
}
}
}
packages/flutter/lib/src/rendering/grid.dart
View file @
68f33d30
...
@@ -344,6 +344,8 @@ class RenderGrid extends RenderVirtualViewport<GridParentData> {
...
@@ -344,6 +344,8 @@ class RenderGrid extends RenderVirtualViewport<GridParentData> {
_delegate
=
newDelegate
;
_delegate
=
newDelegate
;
}
}
int
get
virtualChildCount
=>
super
.
virtualChildCount
??
childCount
;
/// The virtual index of the first child.
/// The virtual index of the first child.
///
///
/// When asking the delegate for the position of each child, the grid will add
/// When asking the delegate for the position of each child, the grid will add
...
...
packages/flutter/lib/src/rendering/list.dart
View file @
68f33d30
...
@@ -76,7 +76,10 @@ class RenderList extends RenderVirtualViewport<ListParentData> implements HasScr
...
@@ -76,7 +76,10 @@ class RenderList extends RenderVirtualViewport<ListParentData> implements HasScr
double
get
_preferredExtent
{
double
get
_preferredExtent
{
if
(
itemExtent
==
null
)
if
(
itemExtent
==
null
)
return
double
.
INFINITY
;
return
double
.
INFINITY
;
double
extent
=
itemExtent
*
virtualChildCount
;
int
count
=
virtualChildCount
;
if
(
count
==
null
)
return
double
.
INFINITY
;
double
extent
=
itemExtent
*
count
;
if
(
padding
!=
null
)
if
(
padding
!=
null
)
extent
+=
_scrollAxisPadding
;
extent
+=
_scrollAxisPadding
;
return
extent
;
return
extent
;
...
...
packages/flutter/lib/src/rendering/viewport.dart
View file @
68f33d30
...
@@ -192,7 +192,7 @@ abstract class RenderVirtualViewport<T extends ContainerBoxParentDataMixin<Rende
...
@@ -192,7 +192,7 @@ abstract class RenderVirtualViewport<T extends ContainerBoxParentDataMixin<Rende
_callback
=
callback
,
_callback
=
callback
,
_overlayPainter
=
overlayPainter
;
_overlayPainter
=
overlayPainter
;
int
get
virtualChildCount
=>
_virtualChildCount
??
childCount
;
int
get
virtualChildCount
=>
_virtualChildCount
;
int
_virtualChildCount
;
int
_virtualChildCount
;
void
set
virtualChildCount
(
int
value
)
{
void
set
virtualChildCount
(
int
value
)
{
if
(
_virtualChildCount
==
value
)
if
(
_virtualChildCount
==
value
)
...
...
packages/flutter/lib/src/widgets/homogeneous_viewport.dart
deleted
100644 → 0
View file @
bc3202ff
// 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
'dart:math'
as
math
;
import
'package:flutter/rendering.dart'
;
import
'framework.dart'
;
import
'basic.dart'
;
typedef
List
<
Widget
>
ListBuilder
(
BuildContext
context
,
int
startIndex
,
int
count
);
abstract
class
_ViewportBase
extends
RenderObjectWidget
{
_ViewportBase
({
Key
key
,
this
.
builder
,
this
.
itemsWrap
:
false
,
this
.
itemCount
,
this
.
direction
:
Axis
.
vertical
,
this
.
startOffset
:
0.0
,
this
.
overlayPainter
})
:
super
(
key:
key
);
final
ListBuilder
builder
;
final
bool
itemsWrap
;
final
int
itemCount
;
final
Axis
direction
;
final
double
startOffset
;
final
Painter
overlayPainter
;
// we don't pass constructor arguments to the RenderBlockViewport() because until
// we know our children, the constructor arguments we could give have no effect
RenderBlockViewport
createRenderObject
()
=>
new
RenderBlockViewport
();
bool
isLayoutDifferentThan
(
_ViewportBase
oldWidget
)
{
// changing the builder doesn't imply the layout changed
return
itemsWrap
!=
oldWidget
.
itemsWrap
||
itemCount
!=
oldWidget
.
itemCount
||
direction
!=
oldWidget
.
direction
||
startOffset
!=
oldWidget
.
startOffset
;
}
}
abstract
class
_ViewportBaseElement
<
T
extends
_ViewportBase
>
extends
RenderObjectElement
<
T
>
{
_ViewportBaseElement
(
T
widget
)
:
super
(
widget
);
List
<
Element
>
_children
=
const
<
Element
>[];
int
_layoutFirstIndex
;
int
_layoutItemCount
;
RenderBlockViewport
get
renderObject
=>
super
.
renderObject
;
void
visitChildren
(
ElementVisitor
visitor
)
{
if
(
_children
==
null
)
return
;
for
(
Element
child
in
_children
)
visitor
(
child
);
}
void
mount
(
Element
parent
,
dynamic
newSlot
)
{
super
.
mount
(
parent
,
newSlot
);
renderObject
.
callback
=
layout
;
renderObject
.
totalExtentCallback
=
getTotalExtent
;
renderObject
.
minCrossAxisExtentCallback
=
getMinCrossAxisExtent
;
renderObject
.
maxCrossAxisExtentCallback
=
getMaxCrossAxisExtent
;
renderObject
.
overlayPainter
=
widget
.
overlayPainter
;
}
void
unmount
()
{
renderObject
.
callback
=
null
;
renderObject
.
totalExtentCallback
=
null
;
renderObject
.
minCrossAxisExtentCallback
=
null
;
renderObject
.
maxCrossAxisExtentCallback
=
null
;
renderObject
.
overlayPainter
=
null
;
super
.
unmount
();
}
void
update
(
T
newWidget
)
{
bool
needLayout
=
newWidget
.
isLayoutDifferentThan
(
widget
);
super
.
update
(
newWidget
);
// TODO(abarth): Don't we need to update overlayPainter here?
if
(
needLayout
)
renderObject
.
markNeedsLayout
();
else
_updateChildren
();
}
void
reinvokeBuilders
()
{
_updateChildren
();
}
void
layout
(
BoxConstraints
constraints
);
void
_updateChildren
()
{
assert
(
_layoutFirstIndex
!=
null
);
assert
(
_layoutItemCount
!=
null
);
List
<
Widget
>
newWidgets
;
if
(
_layoutItemCount
>
0
)
newWidgets
=
widget
.
builder
(
this
,
_layoutFirstIndex
,
_layoutItemCount
).
map
((
Widget
widget
)
{
return
new
RepaintBoundary
(
key:
new
ValueKey
<
Key
>(
widget
.
key
),
child:
widget
);
}).
toList
();
else
newWidgets
=
<
Widget
>[];
_children
=
updateChildren
(
_children
,
newWidgets
);
}
double
getTotalExtent
(
BoxConstraints
constraints
);
double
getMinCrossAxisExtent
(
BoxConstraints
constraints
)
{
return
0.0
;
}
double
getMaxCrossAxisExtent
(
BoxConstraints
constraints
)
{
if
(
widget
.
direction
==
Axis
.
vertical
)
return
constraints
.
maxWidth
;
return
constraints
.
maxHeight
;
}
void
insertChildRenderObject
(
RenderObject
child
,
Element
slot
)
{
renderObject
.
insert
(
child
,
after:
slot
?.
renderObject
);
}
void
moveChildRenderObject
(
RenderObject
child
,
Element
slot
)
{
assert
(
child
.
parent
==
renderObject
);
renderObject
.
move
(
child
,
after:
slot
?.
renderObject
);
}
void
removeChildRenderObject
(
RenderObject
child
)
{
assert
(
child
.
parent
==
renderObject
);
renderObject
.
remove
(
child
);
}
}
class
HomogeneousViewport
extends
_ViewportBase
{
HomogeneousViewport
({
Key
key
,
ListBuilder
builder
,
bool
itemsWrap:
false
,
int
itemCount
,
// optional, but you cannot shrink-wrap this class or otherwise use its intrinsic dimensions if you don't specify it
Axis
direction:
Axis
.
vertical
,
double
startOffset:
0.0
,
Painter
overlayPainter
,
this
.
itemExtent
// required, must be non-zero
})
:
super
(
key:
key
,
builder:
builder
,
itemsWrap:
itemsWrap
,
itemCount:
itemCount
,
direction:
direction
,
startOffset:
startOffset
,
overlayPainter:
overlayPainter
)
{
assert
(
itemExtent
!=
null
);
assert
(
itemExtent
>
0
);
}
final
double
itemExtent
;
_HomogeneousViewportElement
createElement
()
=>
new
_HomogeneousViewportElement
(
this
);
bool
isLayoutDifferentThan
(
HomogeneousViewport
oldWidget
)
{
return
itemExtent
!=
oldWidget
.
itemExtent
||
super
.
isLayoutDifferentThan
(
oldWidget
);
}
}
class
_HomogeneousViewportElement
extends
_ViewportBaseElement
<
HomogeneousViewport
>
{
_HomogeneousViewportElement
(
HomogeneousViewport
widget
)
:
super
(
widget
);
void
layout
(
BoxConstraints
constraints
)
{
// We enter a build scope (meaning that markNeedsBuild() is forbidden)
// because we are in the middle of layout and if we allowed people to set
// state, they'd expect to have that state reflected immediately, which, if
// we were to try to honour it, would potentially result in assertions
// because you can't normally mutate the render object tree during layout.
// (If there were a way to limit these writes to descendants of this, it'd
// be ok because we are exempt from that assert since we are still actively
// doing our own layout.)
BuildableElement
.
lockState
(()
{
double
mainAxisExtent
=
widget
.
direction
==
Axis
.
vertical
?
constraints
.
maxHeight
:
constraints
.
maxWidth
;
double
offset
;
if
(
widget
.
startOffset
<=
0.0
&&
!
widget
.
itemsWrap
)
{
_layoutFirstIndex
=
0
;
offset
=
-
widget
.
startOffset
;
}
else
{
_layoutFirstIndex
=
(
widget
.
startOffset
/
widget
.
itemExtent
).
floor
();
offset
=
-(
widget
.
startOffset
%
widget
.
itemExtent
);
}
if
(
mainAxisExtent
<
double
.
INFINITY
)
{
_layoutItemCount
=
((
mainAxisExtent
-
offset
)
/
widget
.
itemExtent
).
ceil
();
if
(
widget
.
itemCount
!=
null
&&
!
widget
.
itemsWrap
)
_layoutItemCount
=
math
.
min
(
_layoutItemCount
,
widget
.
itemCount
-
_layoutFirstIndex
);
}
else
{
assert
(()
{
'This HomogeneousViewport has no specified number of items (meaning it has infinite items), '
+
'and has been placed in an unconstrained environment where all items can be rendered. '
+
'It is most likely that you have placed your HomogeneousViewport (which is an internal '
+
'component of several scrollable widgets) inside either another scrolling box, a flexible '
+
'box (Row, Column), or a Stack, without giving it a specific size.'
;
return
widget
.
itemCount
!=
null
;
});
_layoutItemCount
=
widget
.
itemCount
-
_layoutFirstIndex
;
}
_layoutItemCount
=
math
.
max
(
0
,
_layoutItemCount
);
_updateChildren
();
// Update the renderObject configuration
renderObject
.
direction
=
widget
.
direction
;
renderObject
.
itemExtent
=
widget
.
itemExtent
;
renderObject
.
minExtent
=
getTotalExtent
(
null
);
renderObject
.
startOffset
=
offset
;
renderObject
.
overlayPainter
=
widget
.
overlayPainter
;
},
building:
true
);
}
double
getTotalExtent
(
BoxConstraints
constraints
)
{
// constraints is null when called by layout() above
return
widget
.
itemCount
!=
null
?
widget
.
itemCount
*
widget
.
itemExtent
:
double
.
INFINITY
;
}
}
packages/flutter/lib/src/widgets/pageable_list.dart
View file @
68f33d30
...
@@ -180,9 +180,8 @@ class PageableListState<T extends PageableList> extends ScrollableState<T> {
...
@@ -180,9 +180,8 @@ class PageableListState<T extends PageableList> extends ScrollableState<T> {
}
}
}
}
class
PageViewport
extends
VirtualViewport
{
class
PageViewport
extends
VirtualViewport
with
VirtualViewportIterableMixin
{
PageViewport
({
PageViewport
({
Key
key
,
this
.
startOffset
:
0.0
,
this
.
startOffset
:
0.0
,
this
.
scrollDirection
:
Axis
.
vertical
,
this
.
scrollDirection
:
Axis
.
vertical
,
this
.
itemsWrap
:
false
,
this
.
itemsWrap
:
false
,
...
...
packages/flutter/lib/src/widgets/scrollable.dart
View file @
68f33d30
...
@@ -14,7 +14,6 @@ import 'package:flutter/rendering.dart';
...
@@ -14,7 +14,6 @@ import 'package:flutter/rendering.dart';
import
'basic.dart'
;
import
'basic.dart'
;
import
'framework.dart'
;
import
'framework.dart'
;
import
'gesture_detector.dart'
;
import
'gesture_detector.dart'
;
import
'homogeneous_viewport.dart'
;
import
'mixed_viewport.dart'
;
import
'mixed_viewport.dart'
;
import
'notification_listener.dart'
;
import
'notification_listener.dart'
;
import
'page_storage.dart'
;
import
'page_storage.dart'
;
...
@@ -597,178 +596,6 @@ abstract class ScrollableListPainter extends Painter {
...
@@ -597,178 +596,6 @@ abstract class ScrollableListPainter extends Painter {
Future
scrollEnded
()
=>
new
Future
.
value
();
Future
scrollEnded
()
=>
new
Future
.
value
();
}
}
/// An optimized scrollable widget for a large number of children that are all
/// the same size (extent) in the scrollDirection. For example for
/// ScrollDirection.vertical itemExtent is the height of each item. Use this
/// widget when you have a large number of children or when you are concerned
// about offscreen widgets consuming resources.
abstract
class
ScrollableWidgetList
extends
Scrollable
{
ScrollableWidgetList
({
Key
key
,
double
initialScrollOffset
,
Axis
scrollDirection:
Axis
.
vertical
,
ScrollListener
onScroll
,
SnapOffsetCallback
snapOffsetCallback
,
double
snapAlignmentOffset:
0.0
,
this
.
itemsWrap
:
false
,
this
.
itemExtent
,
this
.
padding
,
this
.
scrollableListPainter
})
:
super
(
key:
key
,
initialScrollOffset:
initialScrollOffset
,
scrollDirection:
scrollDirection
,
onScroll:
onScroll
,
snapOffsetCallback:
snapOffsetCallback
,
snapAlignmentOffset:
snapAlignmentOffset
)
{
assert
(
itemExtent
!=
null
);
}
final
bool
itemsWrap
;
final
double
itemExtent
;
final
EdgeDims
padding
;
final
ScrollableListPainter
scrollableListPainter
;
}
abstract
class
ScrollableWidgetListState
<
T
extends
ScrollableWidgetList
>
extends
ScrollableState
<
T
>
{
/// Subclasses must implement `get itemCount` to tell ScrollableWidgetList
/// how many items there are in the list.
int
get
itemCount
;
int
_previousItemCount
;
Size
_containerSize
=
Size
.
zero
;
void
didUpdateConfig
(
T
oldConfig
)
{
super
.
didUpdateConfig
(
oldConfig
);
bool
scrollBehaviorUpdateNeeded
=
config
.
padding
!=
oldConfig
.
padding
||
config
.
itemExtent
!=
oldConfig
.
itemExtent
||
config
.
scrollDirection
!=
oldConfig
.
scrollDirection
;
if
(
config
.
itemsWrap
!=
oldConfig
.
itemsWrap
)
{
_scrollBehavior
=
null
;
scrollBehaviorUpdateNeeded
=
true
;
}
if
(
itemCount
!=
_previousItemCount
)
{
_previousItemCount
=
itemCount
;
scrollBehaviorUpdateNeeded
=
true
;
}
if
(
scrollBehaviorUpdateNeeded
)
_updateScrollBehavior
();
}
ScrollBehavior
createScrollBehavior
()
=>
new
OverscrollBehavior
();
ExtentScrollBehavior
get
scrollBehavior
=>
super
.
scrollBehavior
;
double
get
_containerExtent
{
return
config
.
scrollDirection
==
Axis
.
vertical
?
_containerSize
.
height
:
_containerSize
.
width
;
}
void
_handleSizeChanged
(
Size
newSize
)
{
setState
(()
{
_containerSize
=
newSize
;
_updateScrollBehavior
();
});
}
double
get
_leadingPadding
{
EdgeDims
padding
=
config
.
padding
;
if
(
config
.
scrollDirection
==
Axis
.
vertical
)
return
padding
!=
null
?
padding
.
top
:
0.0
;
return
padding
!=
null
?
padding
.
left
:
-.
0
;
}
double
get
_trailingPadding
{
EdgeDims
padding
=
config
.
padding
;
if
(
config
.
scrollDirection
==
Axis
.
vertical
)
return
padding
!=
null
?
padding
.
bottom
:
0.0
;
return
padding
!=
null
?
padding
.
right
:
0.0
;
}
EdgeDims
get
_crossAxisPadding
{
EdgeDims
padding
=
config
.
padding
;
if
(
padding
==
null
)
return
null
;
if
(
config
.
scrollDirection
==
Axis
.
vertical
)
return
new
EdgeDims
.
only
(
left:
padding
.
left
,
right:
padding
.
right
);
return
new
EdgeDims
.
only
(
top:
padding
.
top
,
bottom:
padding
.
bottom
);
}
double
get
_contentExtent
{
if
(
itemCount
==
null
)
return
null
;
double
contentExtent
=
config
.
itemExtent
*
itemCount
;
if
(
config
.
padding
!=
null
)
contentExtent
+=
_leadingPadding
+
_trailingPadding
;
return
contentExtent
;
}
void
_updateScrollBehavior
()
{
// if you don't call this from build(), you must call it from setState().
if
(
config
.
scrollableListPainter
!=
null
)
config
.
scrollableListPainter
.
contentExtent
=
_contentExtent
;
scrollTo
(
scrollBehavior
.
updateExtents
(
contentExtent:
_contentExtent
,
containerExtent:
_containerExtent
,
scrollOffset:
scrollOffset
));
}
void
dispatchOnScrollStart
()
{
super
.
dispatchOnScrollStart
();
config
.
scrollableListPainter
?.
scrollStarted
();
}
void
dispatchOnScroll
()
{
super
.
dispatchOnScroll
();
if
(
config
.
scrollableListPainter
!=
null
)
config
.
scrollableListPainter
.
scrollOffset
=
scrollOffset
;
}
void
dispatchOnScrollEnd
()
{
super
.
dispatchOnScrollEnd
();
config
.
scrollableListPainter
?.
scrollEnded
();
}
Widget
buildContent
(
BuildContext
context
)
{
if
(
itemCount
!=
_previousItemCount
)
{
_previousItemCount
=
itemCount
;
_updateScrollBehavior
();
}
return
new
SizeObserver
(
onSizeChanged:
_handleSizeChanged
,
child:
new
Container
(
padding:
_crossAxisPadding
,
child:
new
HomogeneousViewport
(
builder:
_buildItems
,
itemsWrap:
config
.
itemsWrap
,
itemExtent:
config
.
itemExtent
,
itemCount:
itemCount
,
direction:
config
.
scrollDirection
,
startOffset:
scrollOffset
-
_leadingPadding
,
overlayPainter:
config
.
scrollableListPainter
)
)
);
}
List
<
Widget
>
_buildItems
(
BuildContext
context
,
int
start
,
int
count
)
{
List
<
Widget
>
result
=
buildItems
(
context
,
start
,
count
);
assert
(
result
.
every
((
Widget
item
)
=>
item
.
key
!=
null
));
return
result
;
}
List
<
Widget
>
buildItems
(
BuildContext
context
,
int
start
,
int
count
);
}
/// A general scrollable list for a large number of children that might not all
/// A general scrollable list for a large number of children that might not all
/// have the same height. Prefer [ScrollableWidgetList] when all the children
/// have the same height. Prefer [ScrollableWidgetList] when all the children
/// have the same height because it can use that property to be more efficient.
/// have the same height because it can use that property to be more efficient.
...
...
packages/flutter/lib/src/widgets/scrollable_grid.dart
View file @
68f33d30
...
@@ -65,9 +65,8 @@ class _ScrollableGridState extends ScrollableState<ScrollableGrid> {
...
@@ -65,9 +65,8 @@ class _ScrollableGridState extends ScrollableState<ScrollableGrid> {
}
}
}
}
class
GridViewport
extends
VirtualViewport
{
class
GridViewport
extends
VirtualViewport
with
VirtualViewportIterableMixin
{
GridViewport
({
GridViewport
({
Key
key
,
this
.
startOffset
,
this
.
startOffset
,
this
.
delegate
,
this
.
delegate
,
this
.
onExtentsChanged
,
this
.
onExtentsChanged
,
...
...
packages/flutter/lib/src/widgets/scrollable_list.dart
View file @
68f33d30
...
@@ -88,18 +88,16 @@ class _ScrollableListState extends ScrollableState<ScrollableList> {
...
@@ -88,18 +88,16 @@ class _ScrollableListState extends ScrollableState<ScrollableList> {
}
}
}
}
class
ListViewport
extends
VirtualViewport
{
class
_VirtualListViewport
extends
VirtualViewport
{
ListViewport
({
_VirtualListViewport
(
Key
key
,
this
.
onExtentsChanged
,
this
.
onExtentsChanged
,
this
.
startOffset
:
0.0
,
this
.
startOffset
,
this
.
scrollDirection
:
Axis
.
vertical
,
this
.
scrollDirection
,
this
.
itemExtent
,
this
.
itemExtent
,
this
.
itemsWrap
:
false
,
this
.
itemsWrap
,
this
.
padding
,
this
.
padding
,
this
.
overlayPainter
,
this
.
overlayPainter
this
.
children
)
{
})
{
assert
(
scrollDirection
!=
null
);
assert
(
scrollDirection
!=
null
);
assert
(
itemExtent
!=
null
);
assert
(
itemExtent
!=
null
);
}
}
...
@@ -111,15 +109,14 @@ class ListViewport extends VirtualViewport {
...
@@ -111,15 +109,14 @@ class ListViewport extends VirtualViewport {
final
bool
itemsWrap
;
final
bool
itemsWrap
;
final
EdgeDims
padding
;
final
EdgeDims
padding
;
final
Painter
overlayPainter
;
final
Painter
overlayPainter
;
final
Iterable
<
Widget
>
children
;
RenderList
createRenderObject
()
=>
new
RenderList
(
itemExtent:
itemExtent
);
RenderList
createRenderObject
()
=>
new
RenderList
(
itemExtent:
itemExtent
);
_
ListViewportElement
createElement
()
=>
new
_
ListViewportElement
(
this
);
_
VirtualListViewportElement
createElement
()
=>
new
_Virtual
ListViewportElement
(
this
);
}
}
class
_
ListViewportElement
extends
VirtualViewportElement
<
ListViewport
>
{
class
_
VirtualListViewportElement
extends
VirtualViewportElement
<
_Virtual
ListViewport
>
{
_
ListViewportElement
(
List
Viewport
widget
)
:
super
(
widget
);
_
VirtualListViewportElement
(
Virtual
Viewport
widget
)
:
super
(
widget
);
RenderList
get
renderObject
=>
super
.
renderObject
;
RenderList
get
renderObject
=>
super
.
renderObject
;
...
@@ -135,11 +132,12 @@ class _ListViewportElement extends VirtualViewportElement<ListViewport> {
...
@@ -135,11 +132,12 @@ class _ListViewportElement extends VirtualViewportElement<ListViewport> {
double
get
startOffsetLimit
=>
_startOffsetLimit
;
double
get
startOffsetLimit
=>
_startOffsetLimit
;
double
_startOffsetLimit
;
double
_startOffsetLimit
;
void
updateRenderObject
(
ListViewport
oldWidget
)
{
void
updateRenderObject
(
_VirtualListViewport
oldWidget
)
{
renderObject
.
scrollDirection
=
widget
.
scrollDirection
;
renderObject
renderObject
.
itemExtent
=
widget
.
itemExtent
;
..
scrollDirection
=
widget
.
scrollDirection
renderObject
.
padding
=
widget
.
padding
;
..
itemExtent
=
widget
.
itemExtent
renderObject
.
overlayPainter
=
widget
.
overlayPainter
;
..
padding
=
widget
.
padding
..
overlayPainter
=
widget
.
overlayPainter
;
super
.
updateRenderObject
(
oldWidget
);
super
.
updateRenderObject
(
oldWidget
);
}
}
...
@@ -160,13 +158,13 @@ class _ListViewportElement extends VirtualViewportElement<ListViewport> {
...
@@ -160,13 +158,13 @@ class _ListViewportElement extends VirtualViewportElement<ListViewport> {
final
double
itemExtent
=
widget
.
itemExtent
;
final
double
itemExtent
=
widget
.
itemExtent
;
final
EdgeDims
padding
=
widget
.
padding
??
EdgeDims
.
zero
;
final
EdgeDims
padding
=
widget
.
padding
??
EdgeDims
.
zero
;
double
contentExtent
=
widget
.
itemExtent
*
length
+
padding
.
top
+
padding
.
bottom
;
double
contentExtent
=
length
==
null
?
double
.
INFINITY
:
widget
.
itemExtent
*
length
+
padding
.
top
+
padding
.
bottom
;
double
containerExtent
=
_getContainerExtentFromRenderObject
();
double
containerExtent
=
_getContainerExtentFromRenderObject
();
_materializedChildBase
=
math
.
max
(
0
,
(
widget
.
startOffset
-
padding
.
top
)
~/
itemExtent
);
_materializedChildBase
=
math
.
max
(
0
,
(
widget
.
startOffset
-
padding
.
top
)
~/
itemExtent
);
int
materializedChildLimit
=
math
.
max
(
0
,
((
widget
.
startOffset
+
containerExtent
)
/
itemExtent
).
ceil
());
int
materializedChildLimit
=
math
.
max
(
0
,
((
widget
.
startOffset
+
containerExtent
)
/
itemExtent
).
ceil
());
if
(!
widget
.
itemsWrap
)
{
if
(!
widget
.
itemsWrap
&&
length
!=
null
)
{
_materializedChildBase
=
math
.
min
(
length
,
_materializedChildBase
);
_materializedChildBase
=
math
.
min
(
length
,
_materializedChildBase
);
materializedChildLimit
=
math
.
min
(
length
,
materializedChildLimit
);
materializedChildLimit
=
math
.
min
(
length
,
materializedChildLimit
);
}
else
if
(
length
==
0
)
{
}
else
if
(
length
==
0
)
{
...
@@ -186,3 +184,133 @@ class _ListViewportElement extends VirtualViewportElement<ListViewport> {
...
@@ -186,3 +184,133 @@ class _ListViewportElement extends VirtualViewportElement<ListViewport> {
}
}
}
}
}
}
class
ListViewport
extends
_VirtualListViewport
with
VirtualViewportIterableMixin
{
ListViewport
({
ExtentsChangedCallback
onExtentsChanged
,
double
startOffset:
0.0
,
Axis
scrollDirection:
Axis
.
vertical
,
double
itemExtent
,
bool
itemsWrap:
false
,
EdgeDims
padding
,
Painter
overlayPainter
,
this
.
children
})
:
super
(
onExtentsChanged
,
startOffset
,
scrollDirection
,
itemExtent
,
itemsWrap
,
padding
,
overlayPainter
);
final
Iterable
<
Widget
>
children
;
}
/// An optimized scrollable widget for a large number of children that are all
/// the same size (extent) in the scrollDirection. For example for
/// ScrollDirection.vertical itemExtent is the height of each item. Use this
/// widget when you have a large number of children or when you are concerned
// about offscreen widgets consuming resources.
class
ScrollableLazyList
extends
Scrollable
{
ScrollableLazyList
({
Key
key
,
double
initialScrollOffset
,
Axis
scrollDirection:
Axis
.
vertical
,
ScrollListener
onScroll
,
SnapOffsetCallback
snapOffsetCallback
,
double
snapAlignmentOffset:
0.0
,
this
.
itemExtent
,
this
.
itemCount
,
this
.
itemBuilder
,
this
.
padding
,
this
.
scrollableListPainter
})
:
super
(
key:
key
,
initialScrollOffset:
initialScrollOffset
,
scrollDirection:
scrollDirection
,
onScroll:
onScroll
,
snapOffsetCallback:
snapOffsetCallback
,
snapAlignmentOffset:
snapAlignmentOffset
)
{
assert
(
itemExtent
!=
null
);
assert
(
itemBuilder
!=
null
);
}
final
double
itemExtent
;
final
int
itemCount
;
final
ItemListBuilder
itemBuilder
;
final
EdgeDims
padding
;
final
ScrollableListPainter
scrollableListPainter
;
ScrollableState
createState
()
=>
new
_ScrollableLazyListState
();
}
class
_ScrollableLazyListState
extends
ScrollableState
<
ScrollableLazyList
>
{
ScrollBehavior
createScrollBehavior
()
=>
new
OverscrollBehavior
();
ExtentScrollBehavior
get
scrollBehavior
=>
super
.
scrollBehavior
;
void
_handleExtentsChanged
(
double
contentExtent
,
double
containerExtent
)
{
config
.
scrollableListPainter
?.
contentExtent
=
contentExtent
;
setState
(()
{
scrollTo
(
scrollBehavior
.
updateExtents
(
contentExtent:
contentExtent
,
containerExtent:
containerExtent
,
scrollOffset:
scrollOffset
));
});
}
void
dispatchOnScrollStart
()
{
super
.
dispatchOnScrollStart
();
config
.
scrollableListPainter
?.
scrollStarted
();
}
void
dispatchOnScroll
()
{
super
.
dispatchOnScroll
();
config
.
scrollableListPainter
?.
scrollOffset
=
scrollOffset
;
}
void
dispatchOnScrollEnd
()
{
super
.
dispatchOnScrollEnd
();
config
.
scrollableListPainter
?.
scrollEnded
();
}
Widget
buildContent
(
BuildContext
context
)
{
return
new
LazyListViewport
(
onExtentsChanged:
_handleExtentsChanged
,
startOffset:
scrollOffset
,
scrollDirection:
config
.
scrollDirection
,
itemExtent:
config
.
itemExtent
,
itemCount:
config
.
itemCount
,
itemBuilder:
config
.
itemBuilder
,
padding:
config
.
padding
,
overlayPainter:
config
.
scrollableListPainter
);
}
}
class
LazyListViewport
extends
_VirtualListViewport
with
VirtualViewportLazyMixin
{
LazyListViewport
({
ExtentsChangedCallback
onExtentsChanged
,
double
startOffset:
0.0
,
Axis
scrollDirection:
Axis
.
vertical
,
double
itemExtent
,
EdgeDims
padding
,
Painter
overlayPainter
,
this
.
itemCount
,
this
.
itemBuilder
})
:
super
(
onExtentsChanged
,
startOffset
,
scrollDirection
,
itemExtent
,
false
,
// Don't support wrapping yet.
padding
,
overlayPainter
);
final
int
itemCount
;
final
ItemListBuilder
itemBuilder
;
}
packages/flutter/lib/src/widgets/virtual_viewport.dart
View file @
68f33d30
...
@@ -14,7 +14,15 @@ typedef void ExtentsChangedCallback(double contentExtent, double containerExtent
...
@@ -14,7 +14,15 @@ typedef void ExtentsChangedCallback(double contentExtent, double containerExtent
abstract
class
VirtualViewport
extends
RenderObjectWidget
{
abstract
class
VirtualViewport
extends
RenderObjectWidget
{
double
get
startOffset
;
double
get
startOffset
;
Axis
get
scrollDirection
;
Axis
get
scrollDirection
;
Iterable
<
Widget
>
get
children
;
_WidgetProvider
_createWidgetProvider
();
}
abstract
class
_WidgetProvider
{
void
didUpdateWidget
(
VirtualViewport
oldWidget
,
VirtualViewport
newWidget
);
int
get
virtualChildCount
;
void
prepareChildren
(
VirtualViewportElement
context
,
int
base
,
int
count
);
Widget
getChild
(
int
i
);
}
}
abstract
class
VirtualViewportElement
<
T
extends
VirtualViewport
>
extends
RenderObjectElement
<
T
>
{
abstract
class
VirtualViewportElement
<
T
extends
VirtualViewport
>
extends
RenderObjectElement
<
T
>
{
...
@@ -38,10 +46,12 @@ abstract class VirtualViewportElement<T extends VirtualViewport> extends RenderO
...
@@ -38,10 +46,12 @@ abstract class VirtualViewportElement<T extends VirtualViewport> extends RenderO
visitor
(
child
);
visitor
(
child
);
}
}
_WidgetProvider
_widgetProvider
;
void
mount
(
Element
parent
,
dynamic
newSlot
)
{
void
mount
(
Element
parent
,
dynamic
newSlot
)
{
_widgetProvider
=
widget
.
_createWidgetProvider
();
_widgetProvider
.
didUpdateWidget
(
null
,
widget
);
super
.
mount
(
parent
,
newSlot
);
super
.
mount
(
parent
,
newSlot
);
_iterator
=
null
;
_widgets
=
<
Widget
>[];
renderObject
.
callback
=
layout
;
renderObject
.
callback
=
layout
;
updateRenderObject
(
null
);
updateRenderObject
(
null
);
}
}
...
@@ -52,11 +62,8 @@ abstract class VirtualViewportElement<T extends VirtualViewport> extends RenderO
...
@@ -52,11 +62,8 @@ abstract class VirtualViewportElement<T extends VirtualViewport> extends RenderO
}
}
void
update
(
T
newWidget
)
{
void
update
(
T
newWidget
)
{
if
(
widget
.
children
!=
newWidget
.
children
)
{
_iterator
=
null
;
_widgets
=
<
Widget
>[];
}
T
oldWidget
=
widget
;
T
oldWidget
=
widget
;
_widgetProvider
.
didUpdateWidget
(
oldWidget
,
newWidget
);
super
.
update
(
newWidget
);
super
.
update
(
newWidget
);
updateRenderObject
(
oldWidget
);
updateRenderObject
(
oldWidget
);
if
(!
renderObject
.
needsLayout
)
if
(!
renderObject
.
needsLayout
)
...
@@ -75,7 +82,7 @@ abstract class VirtualViewportElement<T extends VirtualViewport> extends RenderO
...
@@ -75,7 +82,7 @@ abstract class VirtualViewportElement<T extends VirtualViewport> extends RenderO
}
}
void
updateRenderObject
(
T
oldWidget
)
{
void
updateRenderObject
(
T
oldWidget
)
{
renderObject
.
virtualChildCount
=
widget
.
children
.
length
;
renderObject
.
virtualChildCount
=
_widgetProvider
.
virtualChildCount
;
if
(
startOffsetBase
!=
null
)
{
if
(
startOffsetBase
!=
null
)
{
_updatePaintOffset
();
_updatePaintOffset
();
...
@@ -111,37 +118,16 @@ abstract class VirtualViewportElement<T extends VirtualViewport> extends RenderO
...
@@ -111,37 +118,16 @@ abstract class VirtualViewportElement<T extends VirtualViewport> extends RenderO
BuildableElement
.
lockState
(
_materializeChildren
,
building:
true
);
BuildableElement
.
lockState
(
_materializeChildren
,
building:
true
);
}
}
Iterator
<
Widget
>
_iterator
;
List
<
Widget
>
_widgets
;
void
_populateWidgets
(
int
limit
)
{
if
(
limit
<=
_widgets
.
length
)
return
;
if
(
widget
.
children
is
List
<
Widget
>)
{
_widgets
=
widget
.
children
;
return
;
}
_iterator
??=
widget
.
children
.
iterator
;
while
(
_widgets
.
length
<
limit
)
{
bool
moved
=
_iterator
.
moveNext
();
assert
(
moved
);
Widget
current
=
_iterator
.
current
;
assert
(
current
!=
null
);
_widgets
.
add
(
current
);
}
}
void
_materializeChildren
()
{
void
_materializeChildren
()
{
int
base
=
materializedChildBase
;
int
base
=
materializedChildBase
;
int
count
=
materializedChildCount
;
int
count
=
materializedChildCount
;
int
length
=
renderObject
.
virtualChildCount
;
assert
(
base
!=
null
);
assert
(
base
!=
null
);
assert
(
count
!=
null
);
assert
(
count
!=
null
);
_
populateWidgets
(
base
<
0
?
length
:
math
.
min
(
length
,
base
+
count
)
);
_
widgetProvider
.
prepareChildren
(
this
,
base
,
count
);
List
<
Widget
>
newWidgets
=
new
List
<
Widget
>(
count
);
List
<
Widget
>
newWidgets
=
new
List
<
Widget
>(
count
);
for
(
int
i
=
0
;
i
<
count
;
++
i
)
{
for
(
int
i
=
0
;
i
<
count
;
++
i
)
{
int
childIndex
=
base
+
i
;
int
childIndex
=
base
+
i
;
Widget
child
=
_widget
s
[(
childIndex
%
length
).
abs
()]
;
Widget
child
=
_widget
Provider
.
getChild
(
childIndex
)
;
Key
key
=
new
ValueKey
(
child
.
key
??
childIndex
);
Key
key
=
new
ValueKey
(
child
.
key
??
childIndex
);
newWidgets
[
i
]
=
new
RepaintBoundary
(
key:
key
,
child:
child
);
newWidgets
[
i
]
=
new
RepaintBoundary
(
key:
key
,
child:
child
);
}
}
...
@@ -162,3 +148,84 @@ abstract class VirtualViewportElement<T extends VirtualViewport> extends RenderO
...
@@ -162,3 +148,84 @@ abstract class VirtualViewportElement<T extends VirtualViewport> extends RenderO
renderObject
.
remove
(
child
);
renderObject
.
remove
(
child
);
}
}
}
}
abstract
class
VirtualViewportIterableMixin
extends
VirtualViewport
{
Iterable
<
Widget
>
get
children
;
_IterableWidgetProvider
_createWidgetProvider
()
=>
new
_IterableWidgetProvider
();
}
class
_IterableWidgetProvider
extends
_WidgetProvider
{
int
_length
;
Iterator
<
Widget
>
_iterator
;
List
<
Widget
>
_widgets
;
void
didUpdateWidget
(
VirtualViewportIterableMixin
oldWidget
,
VirtualViewportIterableMixin
newWidget
)
{
if
(
oldWidget
==
null
||
newWidget
.
children
!=
oldWidget
.
children
)
{
_iterator
=
null
;
_widgets
=
<
Widget
>[];
_length
=
newWidget
.
children
.
length
;
}
}
int
get
virtualChildCount
=>
_length
;
void
prepareChildren
(
VirtualViewportElement
context
,
int
base
,
int
count
)
{
int
limit
=
base
<
0
?
_length
:
math
.
min
(
_length
,
base
+
count
);
if
(
limit
<=
_widgets
.
length
)
return
;
VirtualViewportIterableMixin
widget
=
context
.
widget
;
if
(
widget
.
children
is
List
<
Widget
>)
{
_widgets
=
widget
.
children
;
return
;
}
_iterator
??=
widget
.
children
.
iterator
;
while
(
_widgets
.
length
<
limit
)
{
bool
moved
=
_iterator
.
moveNext
();
assert
(
moved
);
Widget
current
=
_iterator
.
current
;
assert
(
current
!=
null
);
_widgets
.
add
(
current
);
}
}
Widget
getChild
(
int
i
)
=>
_widgets
[(
i
%
_length
).
abs
()];
}
typedef
List
<
Widget
>
ItemListBuilder
(
BuildContext
context
,
int
start
,
int
count
);
abstract
class
VirtualViewportLazyMixin
extends
VirtualViewport
{
int
get
itemCount
;
ItemListBuilder
get
itemBuilder
;
_LazyWidgetProvider
_createWidgetProvider
()
=>
new
_LazyWidgetProvider
();
}
class
_LazyWidgetProvider
extends
_WidgetProvider
{
int
_length
;
int
_base
;
List
<
Widget
>
_widgets
;
void
didUpdateWidget
(
VirtualViewportLazyMixin
oldWidget
,
VirtualViewportLazyMixin
newWidget
)
{
if
(
_length
!=
newWidget
.
itemCount
||
oldWidget
?.
itemBuilder
!=
newWidget
.
itemBuilder
)
{
_length
=
newWidget
.
itemCount
;
_base
=
null
;
_widgets
=
null
;
}
}
int
get
virtualChildCount
=>
_length
;
void
prepareChildren
(
VirtualViewportElement
context
,
int
base
,
int
count
)
{
if
(
_widgets
!=
null
&&
_widgets
.
length
==
count
&&
_base
==
base
)
return
;
VirtualViewportLazyMixin
widget
=
context
.
widget
;
_base
=
base
;
_widgets
=
widget
.
itemBuilder
(
context
,
base
,
count
);
}
Widget
getChild
(
int
i
)
{
int
n
=
_length
??
_widgets
.
length
;
return
_widgets
[(
i
%
n
).
abs
()];
}
}
packages/flutter/lib/widgets.dart
View file @
68f33d30
...
@@ -18,7 +18,6 @@ export 'src/widgets/framework.dart';
...
@@ -18,7 +18,6 @@ export 'src/widgets/framework.dart';
export
'src/widgets/gesture_detector.dart'
;
export
'src/widgets/gesture_detector.dart'
;
export
'src/widgets/gridpaper.dart'
;
export
'src/widgets/gridpaper.dart'
;
export
'src/widgets/heroes.dart'
;
export
'src/widgets/heroes.dart'
;
export
'src/widgets/homogeneous_viewport.dart'
;
export
'src/widgets/implicit_animations.dart'
;
export
'src/widgets/implicit_animations.dart'
;
export
'src/widgets/locale_query.dart'
;
export
'src/widgets/locale_query.dart'
;
export
'src/widgets/media_query.dart'
;
export
'src/widgets/media_query.dart'
;
...
...
packages/flutter/test/widget/remember_scroll_position_test.dart
View file @
68f33d30
...
@@ -6,26 +6,20 @@ import 'package:flutter_test/flutter_test.dart';
...
@@ -6,26 +6,20 @@ import 'package:flutter_test/flutter_test.dart';
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
import
'package:test/test.dart'
;
import
'package:test/test.dart'
;
class
ThePositiveNumbers
extends
ScrollableWidgetList
{
class
ThePositiveNumbers
extends
StatelessComponent
{
ThePositiveNumbers
()
:
super
(
itemExtent:
100.0
);
Widget
build
(
BuildContext
context
)
{
ThePositiveNumbersState
createState
()
=>
new
ThePositiveNumbersState
();
return
new
ScrollableLazyList
(
}
itemExtent:
100.0
,
itemBuilder:
(
BuildContext
context
,
int
start
,
int
count
)
{
class
ThePositiveNumbersState
extends
ScrollableWidgetListState
<
ThePositiveNumbers
>
{
List
<
Widget
>
result
=
new
List
<
Widget
>();
for
(
int
index
=
start
;
index
<
start
+
count
;
index
+=
1
)
ScrollBehavior
createScrollBehavior
()
=>
new
UnboundedBehavior
();
result
.
add
(
new
Text
(
'
$index
'
,
key:
new
ValueKey
<
int
>(
index
)));
return
result
;
int
get
itemCount
=>
null
;
}
);
List
<
Widget
>
buildItems
(
BuildContext
context
,
int
start
,
int
count
)
{
List
<
Widget
>
result
=
new
List
<
Widget
>();
for
(
int
index
=
start
;
index
<
start
+
count
;
index
+=
1
)
result
.
add
(
new
Text
(
'
$index
'
,
key:
new
ValueKey
<
int
>(
index
)));
return
result
;
}
}
}
}
void
main
(
)
{
void
main
(
)
{
test
(
'whether we remember our scroll position'
,
()
{
test
(
'whether we remember our scroll position'
,
()
{
testWidgets
((
WidgetTester
tester
)
{
testWidgets
((
WidgetTester
tester
)
{
...
@@ -53,8 +47,8 @@ void main() {
...
@@ -53,8 +47,8 @@ void main() {
expect
(
tester
.
findText
(
'10'
),
isNull
);
expect
(
tester
.
findText
(
'10'
),
isNull
);
expect
(
tester
.
findText
(
'100'
),
isNull
);
expect
(
tester
.
findText
(
'100'
),
isNull
);
StatefulComponentElement
<
ThePositiveNumbers
,
ThePositiveNumbersState
>
target
=
StatefulComponentElement
<
ScrollableLazyList
,
ScrollableState
<
ScrollableLazyList
>
>
target
=
tester
.
findElement
((
Element
element
)
=>
element
.
widget
is
ThePositiveNumbers
);
tester
.
findElement
((
Element
element
)
=>
element
.
widget
is
ScrollableLazyList
);
target
.
state
.
scrollTo
(
1000.0
);
target
.
state
.
scrollTo
(
1000.0
);
tester
.
pump
(
new
Duration
(
seconds:
1
));
tester
.
pump
(
new
Duration
(
seconds:
1
));
...
...
packages/flutter/test/widget/
homogeneous_viewpor
t_test.dart
→
packages/flutter/test/widget/
scrollable_lazy_lis
t_test.dart
View file @
68f33d30
...
@@ -18,8 +18,8 @@ void main() {
...
@@ -18,8 +18,8 @@ void main() {
Widget
builder
()
{
Widget
builder
()
{
return
new
FlipComponent
(
return
new
FlipComponent
(
left:
new
HomogeneousViewpor
t
(
left:
new
ScrollableLazyLis
t
(
b
uilder:
(
BuildContext
context
,
int
start
,
int
count
)
{
itemB
uilder:
(
BuildContext
context
,
int
start
,
int
count
)
{
List
<
Widget
>
result
=
<
Widget
>[];
List
<
Widget
>
result
=
<
Widget
>[];
for
(
int
index
=
start
;
index
<
start
+
count
;
index
+=
1
)
{
for
(
int
index
=
start
;
index
<
start
+
count
;
index
+=
1
)
{
callbackTracker
.
add
(
index
);
callbackTracker
.
add
(
index
);
...
@@ -31,7 +31,6 @@ void main() {
...
@@ -31,7 +31,6 @@ void main() {
}
}
return
result
;
return
result
;
},
},
startOffset:
0.0
,
itemExtent:
100.0
itemExtent:
100.0
),
),
right:
new
Text
(
'Not Today'
)
right:
new
Text
(
'Not Today'
)
...
@@ -67,9 +66,7 @@ void main() {
...
@@ -67,9 +66,7 @@ void main() {
// so if our widget is 200 pixels tall, it should fit exactly 3 times.
// so if our widget is 200 pixels tall, it should fit exactly 3 times.
// but if we are offset by 300 pixels, there will be 4, numbered 1-4.
// but if we are offset by 300 pixels, there will be 4, numbered 1-4.
double
offset
=
300.0
;
ItemListBuilder
itemBuilder
=
(
BuildContext
context
,
int
start
,
int
count
)
{
ListBuilder
itemBuilder
=
(
BuildContext
context
,
int
start
,
int
count
)
{
List
<
Widget
>
result
=
<
Widget
>[];
List
<
Widget
>
result
=
<
Widget
>[];
for
(
int
index
=
start
;
index
<
start
+
count
;
index
+=
1
)
{
for
(
int
index
=
start
;
index
<
start
+
count
;
index
+=
1
)
{
callbackTracker
.
add
(
index
);
callbackTracker
.
add
(
index
);
...
@@ -83,28 +80,27 @@ void main() {
...
@@ -83,28 +80,27 @@ void main() {
return
result
;
return
result
;
};
};
FlipComponent
testComponent
;
GlobalKey
<
ScrollableState
<
ScrollableLazyList
>>
scrollableKey
=
new
GlobalKey
<
ScrollableState
<
ScrollableLazyList
>>();
Widget
builder
()
{
FlipComponent
testComponent
=
new
FlipComponent
(
testComponent
=
new
FlipComponent
(
left:
new
ScrollableLazyList
(
left:
new
HomogeneousViewport
(
key:
scrollableKey
,
builder:
itemBuilder
,
itemBuilder:
itemBuilder
,
startOffset:
offset
,
itemExtent:
200.0
,
itemExtent:
200.0
initialScrollOffset:
300.0
),
),
right:
new
Text
(
'Not Today'
)
right:
new
Text
(
'Not Today'
)
);
);
return
testComponent
;
}
tester
.
pumpWidget
(
builder
()
);
tester
.
pumpWidget
(
testComponent
);
expect
(
callbackTracker
,
equals
([
1
,
2
,
3
,
4
]));
expect
(
callbackTracker
,
equals
([
1
,
2
,
3
,
4
]));
callbackTracker
.
clear
();
callbackTracker
.
clear
();
offset
=
400.0
;
// now only 3 should fit, numbered 2-4.
scrollableKey
.
currentState
.
scrollTo
(
400.0
);
// now only 3 should fit, numbered 2-4.
tester
.
pumpWidget
(
builder
()
);
tester
.
pumpWidget
(
testComponent
);
expect
(
callbackTracker
,
equals
([
2
,
3
,
4
]));
expect
(
callbackTracker
,
equals
([
2
,
3
,
4
]));
...
@@ -120,9 +116,7 @@ void main() {
...
@@ -120,9 +116,7 @@ void main() {
// so if our widget is 200 pixels wide, it should fit exactly 4 times.
// so if our widget is 200 pixels wide, it should fit exactly 4 times.
// but if we are offset by 300 pixels, there will be 5, numbered 1-5.
// but if we are offset by 300 pixels, there will be 5, numbered 1-5.
double
offset
=
300.0
;
ItemListBuilder
itemBuilder
=
(
BuildContext
context
,
int
start
,
int
count
)
{
ListBuilder
itemBuilder
=
(
BuildContext
context
,
int
start
,
int
count
)
{
List
<
Widget
>
result
=
<
Widget
>[];
List
<
Widget
>
result
=
<
Widget
>[];
for
(
int
index
=
start
;
index
<
start
+
count
;
index
+=
1
)
{
for
(
int
index
=
start
;
index
<
start
+
count
;
index
+=
1
)
{
callbackTracker
.
add
(
index
);
callbackTracker
.
add
(
index
);
...
@@ -136,29 +130,28 @@ void main() {
...
@@ -136,29 +130,28 @@ void main() {
return
result
;
return
result
;
};
};
FlipComponent
testComponent
;
GlobalKey
<
ScrollableState
<
ScrollableLazyList
>>
scrollableKey
=
new
GlobalKey
<
ScrollableState
<
ScrollableLazyList
>>();
Widget
builder
()
{
FlipComponent
testComponent
=
new
FlipComponent
(
testComponent
=
new
FlipComponent
(
left:
new
ScrollableLazyList
(
left:
new
HomogeneousViewport
(
key:
scrollableKey
,
builder:
itemBuilder
,
itemBuilder:
itemBuilder
,
startOffset:
offset
,
itemExtent:
200.0
,
itemExtent:
200.0
,
initialScrollOffset:
300.0
,
direction:
Axis
.
horizontal
scrollDirection:
Axis
.
horizontal
),
),
right:
new
Text
(
'Not Today'
)
right:
new
Text
(
'Not Today'
)
);
);
return
testComponent
;
}
tester
.
pumpWidget
(
builder
()
);
tester
.
pumpWidget
(
testComponent
);
expect
(
callbackTracker
,
equals
([
1
,
2
,
3
,
4
,
5
]));
expect
(
callbackTracker
,
equals
([
1
,
2
,
3
,
4
,
5
]));
callbackTracker
.
clear
();
callbackTracker
.
clear
();
offset
=
400.0
;
// now only 4 should fit, numbered 2-5.
scrollableKey
.
currentState
.
scrollTo
(
400.0
);
// now only 4 should fit, numbered 2-5.
tester
.
pumpWidget
(
builder
()
);
tester
.
pumpWidget
(
testComponent
);
expect
(
callbackTracker
,
equals
([
2
,
3
,
4
,
5
]));
expect
(
callbackTracker
,
equals
([
2
,
3
,
4
,
5
]));
...
...
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