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
3c3b003f
Commit
3c3b003f
authored
Apr 26, 2017
by
Hans Muller
Committed by
GitHub
Apr 26, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Handle ListView item size changes that cause underflow (#9586)
parent
b7ec8201
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
105 additions
and
1 deletion
+105
-1
sliver_list.dart
packages/flutter/lib/src/rendering/sliver_list.dart
+27
-1
list_view_correction_test.dart
packages/flutter/test/widgets/list_view_correction_test.dart
+78
-0
No files found.
packages/flutter/lib/src/rendering/sliver_list.dart
View file @
3c3b003f
...
...
@@ -97,6 +97,7 @@ class RenderSliverList extends RenderSliverMultiBoxAdaptor {
earliestScrollOffset
=
childScrollOffset
(
earliestUsefulChild
))
{
// We have to add children before the earliestUsefulChild.
earliestUsefulChild
=
insertAndLayoutLeadingChild
(
childConstraints
,
parentUsesSize:
true
);
if
(
earliestUsefulChild
==
null
)
{
// We ran out of children before reaching the scroll offset.
// We must inform our parent that this sliver cannot fulfill
...
...
@@ -108,8 +109,33 @@ class RenderSliverList extends RenderSliverMultiBoxAdaptor {
childParentData
.
layoutOffset
=
0.0
;
return
;
}
final
double
firstChildScrollOffset
=
earliestScrollOffset
-
paintExtentOf
(
firstChild
);
if
(
firstChildScrollOffset
<
0.0
)
{
// The first child doesn't fit within the viewport (underflow) and
// there may be additional children above it. Find the real first child
// and then correct the scroll position so that there's room for all and
// so that the trailing edge of the original firstChild appears where it
// was before the scroll offset correction.
// TODO(hansmuller): do this work incrementally, instead of all at once,
// i.e. find a way to avoid visiting ALL of the children whose offset
// is < 0 before returning for the scroll correction.
double
correction
=
0.0
;
while
(
earliestUsefulChild
!=
null
)
{
assert
(
firstChild
==
earliestUsefulChild
);
correction
+=
paintExtentOf
(
firstChild
);
earliestUsefulChild
=
insertAndLayoutLeadingChild
(
childConstraints
,
parentUsesSize:
true
);
}
geometry
=
new
SliverGeometry
(
scrollOffsetCorrection:
correction
-
earliestScrollOffset
,
);
final
SliverMultiBoxAdaptorParentData
childParentData
=
firstChild
.
parentData
;
childParentData
.
layoutOffset
=
0.0
;
return
;
}
final
SliverMultiBoxAdaptorParentData
childParentData
=
earliestUsefulChild
.
parentData
;
childParentData
.
layoutOffset
=
earliestScrollOffset
-
paintExtentOf
(
firstChild
)
;
childParentData
.
layoutOffset
=
firstChildScrollOffset
;
assert
(
earliestUsefulChild
==
firstChild
);
leadingChildWithLayout
=
earliestUsefulChild
;
trailingChildWithLayout
??=
earliestUsefulChild
;
...
...
packages/flutter/test/widgets/list_view_correction_test.dart
View file @
3c3b003f
...
...
@@ -53,4 +53,82 @@ void main() {
expect
(
tester
.
getTopLeft
(
find
.
text
(
'2'
)).
dy
,
equals
(
200.0
));
});
testWidgets
(
'ListView can handle inserts at 0'
,
(
WidgetTester
tester
)
async
{
final
ScrollController
controller
=
new
ScrollController
();
await
tester
.
pumpWidget
(
new
ListView
(
controller:
controller
,
children:
<
Widget
>[
new
Container
(
height:
400.0
,
child:
const
Text
(
'0'
)),
new
Container
(
height:
400.0
,
child:
const
Text
(
'1'
)),
new
Container
(
height:
400.0
,
child:
const
Text
(
'2'
)),
new
Container
(
height:
400.0
,
child:
const
Text
(
'3'
)),
],
));
expect
(
find
.
text
(
'0'
),
findsOneWidget
);
expect
(
find
.
text
(
'1'
),
findsOneWidget
);
expect
(
find
.
text
(
'2'
),
findsNothing
);
expect
(
find
.
text
(
'3'
),
findsNothing
);
final
Finder
findItemA
=
find
.
descendant
(
of:
find
.
byType
(
Container
),
matching:
find
.
text
(
'A'
));
final
Finder
findItemB
=
find
.
descendant
(
of:
find
.
byType
(
Container
),
matching:
find
.
text
(
'B'
));
await
tester
.
pumpWidget
(
new
ListView
(
controller:
controller
,
children:
<
Widget
>[
new
Container
(
height:
10.0
,
child:
const
Text
(
'A'
)),
new
Container
(
height:
10.0
,
child:
const
Text
(
'B'
)),
new
Container
(
height:
400.0
,
child:
const
Text
(
'0'
)),
new
Container
(
height:
400.0
,
child:
const
Text
(
'1'
)),
new
Container
(
height:
400.0
,
child:
const
Text
(
'2'
)),
new
Container
(
height:
400.0
,
child:
const
Text
(
'3'
)),
],
));
expect
(
find
.
text
(
'A'
),
findsOneWidget
);
expect
(
find
.
text
(
'B'
),
findsOneWidget
);
expect
(
tester
.
getTopLeft
(
findItemA
).
dy
,
0.0
);
expect
(
tester
.
getBottomRight
(
findItemA
).
dy
,
10.0
);
expect
(
tester
.
getTopLeft
(
findItemB
).
dy
,
10.0
);
expect
(
tester
.
getBottomRight
(
findItemB
).
dy
,
20.0
);
controller
.
jumpTo
(
1200.0
);
await
tester
.
pump
();
expect
(
find
.
text
(
'A'
),
findsNothing
);
expect
(
find
.
text
(
'B'
),
findsNothing
);
await
tester
.
pumpWidget
(
new
ListView
(
controller:
controller
,
children:
<
Widget
>[
new
Container
(
height:
200.0
,
child:
const
Text
(
'A'
)),
new
Container
(
height:
200.0
,
child:
const
Text
(
'B'
)),
new
Container
(
height:
400.0
,
child:
const
Text
(
'0'
)),
new
Container
(
height:
400.0
,
child:
const
Text
(
'1'
)),
new
Container
(
height:
400.0
,
child:
const
Text
(
'2'
)),
new
Container
(
height:
400.0
,
child:
const
Text
(
'3'
)),
],
));
expect
(
find
.
text
(
'A'
),
findsNothing
);
expect
(
find
.
text
(
'B'
),
findsNothing
);
// Scrolling to 0 causes items A and B to underflow (extend below
// scrollOffset 0) because their heights have grown from 10 - 200.
// RenderSliver list corrects the scroll offset in this case. Only item
// B will become visible and item B's bottom edge will still appear
// where it was when its height was 10.0.
controller
.
jumpTo
(
0.0
);
await
tester
.
pump
();
expect
(
find
.
text
(
'B'
),
findsOneWidget
);
expect
(
controller
.
offset
,
greaterThan
(
0.0
));
// RenderSliverList corrected the offset.
expect
(
tester
.
getTopLeft
(
findItemB
).
dy
,
-
180.0
);
expect
(
tester
.
getBottomRight
(
findItemB
).
dy
,
20.0
);
controller
.
jumpTo
(
0.0
);
await
tester
.
pump
();
expect
(
find
.
text
(
'A'
),
findsOneWidget
);
expect
(
find
.
text
(
'B'
),
findsOneWidget
);
expect
(
tester
.
getTopLeft
(
findItemA
).
dy
,
0.0
);
expect
(
tester
.
getBottomRight
(
findItemA
).
dy
,
200.0
);
expect
(
tester
.
getTopLeft
(
findItemB
).
dy
,
200.0
);
expect
(
tester
.
getBottomRight
(
findItemB
).
dy
,
400.0
);
});
}
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