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
37f9c541
Unverified
Commit
37f9c541
authored
Nov 27, 2019
by
LongCatIsLooong
Committed by
GitHub
Nov 27, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Use RenderSliverPadding to inset SliverFillViewport (#45432)
parent
1374a413
Changes
7
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
378 additions
and
176 deletions
+378
-176
sliver_fill.dart
packages/flutter/lib/src/rendering/sliver_fill.dart
+0
-35
sliver_fixed_extent_list.dart
...s/flutter/lib/src/rendering/sliver_fixed_extent_list.dart
+1
-1
sliver_padding.dart
packages/flutter/lib/src/rendering/sliver_padding.dart
+110
-84
page_view.dart
packages/flutter/lib/src/widgets/page_view.dart
+19
-2
sliver.dart
packages/flutter/lib/src/widgets/sliver.dart
+103
-4
page_view_test.dart
packages/flutter/test/widgets/page_view_test.dart
+84
-2
sliver_fill_viewport_test.dart
packages/flutter/test/widgets/sliver_fill_viewport_test.dart
+61
-48
No files found.
packages/flutter/lib/src/rendering/sliver_fill.dart
View file @
37f9c541
...
...
@@ -57,41 +57,6 @@ class RenderSliverFillViewport extends RenderSliverFixedExtentBoxAdaptor {
_viewportFraction
=
value
;
markNeedsLayout
();
}
double
get
_padding
=>
(
1.0
-
viewportFraction
)
*
constraints
.
viewportMainAxisExtent
*
0.5
;
@override
double
indexToLayoutOffset
(
double
itemExtent
,
int
index
)
{
return
_padding
+
super
.
indexToLayoutOffset
(
itemExtent
,
index
);
}
@override
int
getMinChildIndexForScrollOffset
(
double
scrollOffset
,
double
itemExtent
)
{
return
super
.
getMinChildIndexForScrollOffset
(
math
.
max
(
scrollOffset
-
_padding
,
0.0
),
itemExtent
);
}
@override
int
getMaxChildIndexForScrollOffset
(
double
scrollOffset
,
double
itemExtent
)
{
return
super
.
getMaxChildIndexForScrollOffset
(
math
.
max
(
scrollOffset
-
_padding
,
0.0
),
itemExtent
);
}
@override
double
estimateMaxScrollOffset
(
SliverConstraints
constraints
,
{
int
firstIndex
,
int
lastIndex
,
double
leadingScrollOffset
,
double
trailingScrollOffset
,
})
{
final
double
padding
=
_padding
;
return
childManager
.
estimateMaxScrollOffset
(
constraints
,
firstIndex:
firstIndex
,
lastIndex:
lastIndex
,
leadingScrollOffset:
leadingScrollOffset
-
padding
,
trailingScrollOffset:
trailingScrollOffset
-
padding
,
)
+
padding
+
padding
;
}
}
/// A sliver that contains a single box child that fills the remaining space in
...
...
packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart
View file @
37f9c541
...
...
@@ -195,7 +195,7 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda
if
(
firstChild
==
null
)
{
if
(!
addInitialChild
(
index:
firstIndex
,
layoutOffset:
indexToLayoutOffset
(
itemExtent
,
firstIndex
)))
{
// There are either no children, or we are past the end of all our children.
// If it is the later, we will need to find the first available child.
// If it is the lat
t
er, we will need to find the first available child.
double
max
;
if
(
childManager
.
childCount
!=
null
)
{
max
=
computeMaxScrollOffset
(
constraints
,
itemExtent
);
...
...
packages/flutter/lib/src/rendering/sliver_padding.dart
View file @
37f9c541
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/widgets/page_view.dart
View file @
37f9c541
...
...
@@ -345,8 +345,16 @@ class _PagePosition extends ScrollPositionWithSingleContext implements PageMetri
forcePixels
(
getPixelsFromPage
(
oldPage
));
}
// The amount of offset that will be added to [minScrollExtent] and subtracted
// from [maxScrollExtent], such that every page will properly snap to the center
// of the viewport when viewportFraction is greater than 1.
//
// The value is 0 if viewportFraction is less than or equal to 1, larger than 0
// otherwise.
double
get
_initialPageOffset
=>
math
.
max
(
0
,
viewportDimension
*
(
viewportFraction
-
1
)
/
2
);
double
getPageFromPixels
(
double
pixels
,
double
viewportDimension
)
{
final
double
actual
=
math
.
max
(
0.0
,
pixels
)
/
math
.
max
(
1.0
,
viewportDimension
*
viewportFraction
);
final
double
actual
=
math
.
max
(
0.0
,
pixels
-
_initialPageOffset
)
/
math
.
max
(
1.0
,
viewportDimension
*
viewportFraction
);
final
double
round
=
actual
.
roundToDouble
();
if
((
actual
-
round
).
abs
()
<
precisionErrorTolerance
)
{
return
round
;
...
...
@@ -355,7 +363,7 @@ class _PagePosition extends ScrollPositionWithSingleContext implements PageMetri
}
double
getPixelsFromPage
(
double
page
)
{
return
page
*
viewportDimension
*
viewportFraction
;
return
page
*
viewportDimension
*
viewportFraction
+
_initialPageOffset
;
}
@override
...
...
@@ -396,6 +404,15 @@ class _PagePosition extends ScrollPositionWithSingleContext implements PageMetri
return
result
;
}
@override
bool
applyContentDimensions
(
double
minScrollExtent
,
double
maxScrollExtent
)
{
final
double
newMinScrollExtent
=
minScrollExtent
+
_initialPageOffset
;
return
super
.
applyContentDimensions
(
newMinScrollExtent
,
math
.
max
(
newMinScrollExtent
,
maxScrollExtent
-
_initialPageOffset
),
);
}
@override
PageMetrics
copyWith
({
double
minScrollExtent
,
...
...
packages/flutter/lib/src/widgets/sliver.dart
View file @
37f9c541
...
...
@@ -725,6 +725,7 @@ abstract class SliverMultiBoxAdaptorWidget extends SliverWithKeepAliveWidget {
})
:
assert
(
delegate
!=
null
),
super
(
key:
key
);
/// {@template flutter.widgets.sliverMultiBoxAdaptor.delegate}
/// The delegate that provides the children for this widget.
///
/// The children are constructed lazily using this delegate to avoid creating
...
...
@@ -735,6 +736,7 @@ abstract class SliverMultiBoxAdaptorWidget extends SliverWithKeepAliveWidget {
/// * [SliverChildBuilderDelegate] and [SliverChildListDelegate], which are
/// commonly used subclasses of [SliverChildDelegate] that use a builder
/// callback and an explicit child list, respectively.
/// {@endtemplate}
final
SliverChildDelegate
delegate
;
@override
...
...
@@ -1023,7 +1025,7 @@ class SliverGrid extends SliverMultiBoxAdaptorWidget {
}
}
/// A sliver that contains
a multiple box children that each fill
the viewport.
/// A sliver that contains
multiple box children that each fills
the viewport.
///
/// [SliverFillViewport] places its children in a linear array along the main
/// axis. Each child is sized to fill the viewport, both in the main and cross
...
...
@@ -1038,15 +1040,15 @@ class SliverGrid extends SliverMultiBoxAdaptorWidget {
/// the main axis extent of each item.
/// * [SliverList], which does not require its children to have the same
/// extent in the main axis.
class
SliverFillViewport
extends
S
liverMultiBoxAdaptor
Widget
{
class
SliverFillViewport
extends
S
tateless
Widget
{
/// Creates a sliver whose box children that each fill the viewport.
const
SliverFillViewport
({
Key
key
,
@required
SliverChildDelegate
delegate
,
@required
this
.
delegate
,
this
.
viewportFraction
=
1.0
,
})
:
assert
(
viewportFraction
!=
null
),
assert
(
viewportFraction
>
0.0
),
super
(
key:
key
,
delegate:
delegate
);
super
(
key:
key
);
/// The fraction of the viewport that each child should fill in the main axis.
///
...
...
@@ -1055,6 +1057,32 @@ class SliverFillViewport extends SliverMultiBoxAdaptorWidget {
/// the viewport in the main axis.
final
double
viewportFraction
;
/// {@macro flutter.widgets.sliverMultiBoxAdaptor.delegate}
final
SliverChildDelegate
delegate
;
@override
Widget
build
(
BuildContext
context
)
{
return
_SliverFractionalPadding
(
viewportFraction:
(
1
-
viewportFraction
).
clamp
(
0
,
1
)
/
2
,
sliver:
_SliverFillViewportRenderObjectWidget
(
viewportFraction:
viewportFraction
,
delegate:
delegate
,
),
);
}
}
class
_SliverFillViewportRenderObjectWidget
extends
SliverMultiBoxAdaptorWidget
{
const
_SliverFillViewportRenderObjectWidget
({
Key
key
,
@required
SliverChildDelegate
delegate
,
this
.
viewportFraction
=
1.0
,
})
:
assert
(
viewportFraction
!=
null
),
assert
(
viewportFraction
>
0.0
),
super
(
key:
key
,
delegate:
delegate
);
final
double
viewportFraction
;
@override
RenderSliverFillViewport
createRenderObject
(
BuildContext
context
)
{
final
SliverMultiBoxAdaptorElement
element
=
context
;
...
...
@@ -1067,6 +1095,77 @@ class SliverFillViewport extends SliverMultiBoxAdaptorWidget {
}
}
class
_SliverFractionalPadding
extends
SingleChildRenderObjectWidget
{
const
_SliverFractionalPadding
({
this
.
viewportFraction
=
0
,
Widget
sliver
,
})
:
assert
(
viewportFraction
!=
null
),
assert
(
viewportFraction
>=
0
),
assert
(
viewportFraction
<=
0.5
),
super
(
child:
sliver
);
final
double
viewportFraction
;
@override
RenderObject
createRenderObject
(
BuildContext
context
)
=>
_RenderSliverFractionalPadding
(
viewportFraction:
viewportFraction
);
@override
void
updateRenderObject
(
BuildContext
context
,
_RenderSliverFractionalPadding
renderObject
)
{
renderObject
.
viewportFraction
=
viewportFraction
;
}
}
class
_RenderSliverFractionalPadding
extends
RenderSliverEdgeInsetsPadding
{
_RenderSliverFractionalPadding
({
double
viewportFraction
=
0
,
})
:
assert
(
viewportFraction
!=
null
),
assert
(
viewportFraction
<=
0.5
),
assert
(
viewportFraction
>=
0
),
_viewportFraction
=
viewportFraction
;
double
get
viewportFraction
=>
_viewportFraction
;
double
_viewportFraction
;
set
viewportFraction
(
double
newValue
)
{
assert
(
newValue
!=
null
);
if
(
_viewportFraction
==
newValue
)
return
;
_viewportFraction
=
newValue
;
_markNeedsResolution
();
}
@override
EdgeInsets
get
resolvedPadding
=>
_resolvedPadding
;
EdgeInsets
_resolvedPadding
;
void
_markNeedsResolution
()
{
_resolvedPadding
=
null
;
markNeedsLayout
();
}
void
_resolve
()
{
if
(
_resolvedPadding
!=
null
)
return
;
assert
(
constraints
.
axis
!=
null
);
final
double
paddingValue
=
constraints
.
viewportMainAxisExtent
*
viewportFraction
;
switch
(
constraints
.
axis
)
{
case
Axis
.
horizontal
:
_resolvedPadding
=
EdgeInsets
.
symmetric
(
horizontal:
paddingValue
);
break
;
case
Axis
.
vertical
:
_resolvedPadding
=
EdgeInsets
.
symmetric
(
vertical:
paddingValue
);
break
;
}
return
;
}
@override
void
performLayout
()
{
_resolve
();
super
.
performLayout
();
}
}
/// An element that lazily builds children for a [SliverMultiBoxAdaptorWidget].
///
/// Implements [RenderSliverBoxChildManager], which lets this element manage
...
...
packages/flutter/test/widgets/page_view_test.dart
View file @
37f9c541
...
...
@@ -532,8 +532,7 @@ void main() {
});
testWidgets
(
'PageView large viewportFraction'
,
(
WidgetTester
tester
)
async
{
final
PageController
controller
=
PageController
(
viewportFraction:
5
/
4
);
final
PageController
controller
=
PageController
(
viewportFraction:
5
/
4
);
Widget
build
(
PageController
controller
)
{
return
Directionality
(
...
...
@@ -601,6 +600,89 @@ void main() {
expect
(
tester
.
getTopLeft
(
find
.
text
(
'Hawaii'
)),
const
Offset
(-(
4
-
1
)
*
800
/
2
,
0
));
});
testWidgets
(
'PageView large viewportFraction can scroll to the last page and snap'
,
(
WidgetTester
tester
)
async
{
// Regression test for https://github.com/flutter/flutter/issues/45096.
final
PageController
controller
=
PageController
(
viewportFraction:
5
/
4
);
Widget
build
(
PageController
controller
)
{
return
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
PageView
.
builder
(
controller:
controller
,
itemCount:
3
,
itemBuilder:
(
BuildContext
context
,
int
index
)
{
return
Container
(
height:
200.0
,
color:
index
%
2
==
0
?
const
Color
(
0xFF0000FF
)
:
const
Color
(
0xFF00FF00
),
child:
Text
(
index
.
toString
()),
);
},
),
);
}
await
tester
.
pumpWidget
(
build
(
controller
));
expect
(
tester
.
getCenter
(
find
.
text
(
'0'
)),
const
Offset
(
400
,
300
));
controller
.
jumpToPage
(
2
);
await
tester
.
pump
();
await
tester
.
pumpAndSettle
();
expect
(
tester
.
getCenter
(
find
.
text
(
'2'
)),
const
Offset
(
400
,
300
));
});
testWidgets
(
'All visible pages are able to receive touch events'
,
(
WidgetTester
tester
)
async
{
// Regression test for https://github.com/flutter/flutter/issues/23873.
final
PageController
controller
=
PageController
(
viewportFraction:
1
/
4
,
initialPage:
0
);
int
tappedIndex
;
Widget
build
()
{
return
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
PageView
.
builder
(
controller:
controller
,
itemCount:
20
,
itemBuilder:
(
BuildContext
context
,
int
index
)
{
return
GestureDetector
(
onTap:
()
=>
tappedIndex
=
index
,
child:
SizedBox
.
expand
(
child:
Text
(
'
$index
'
)),
);
},
),
);
}
Iterable
<
int
>
visiblePages
=
const
<
int
>
[
0
,
1
,
2
];
await
tester
.
pumpWidget
(
build
());
// The first 3 items should be visible and tappable.
for
(
int
index
in
visiblePages
)
{
expect
(
find
.
text
(
index
.
toString
()),
findsOneWidget
);
// The center of page 2's x-coordinate is 800, so we have to manually
// offset it a bit to make sure the tap lands within the screen.
final
Offset
center
=
tester
.
getCenter
(
find
.
text
(
'
$index
'
))
-
const
Offset
(
3
,
0
);
await
tester
.
tapAt
(
center
);
expect
(
tappedIndex
,
index
);
}
controller
.
jumpToPage
(
19
);
await
tester
.
pump
();
// The last 3 items should be visible and tappable.
visiblePages
=
const
<
int
>
[
17
,
18
,
19
];
for
(
int
index
in
visiblePages
)
{
expect
(
find
.
text
(
'
$index
'
),
findsOneWidget
);
await
tester
.
tap
(
find
.
text
(
'
$index
'
));
expect
(
tappedIndex
,
index
);
}
});
testWidgets
(
'PageView does not report page changed on overscroll'
,
(
WidgetTester
tester
)
async
{
final
PageController
controller
=
PageController
(
initialPage:
kStates
.
length
-
1
,
...
...
packages/flutter/test/widgets/sliver_fill_viewport_test.dart
View file @
37f9c541
...
...
@@ -64,7 +64,7 @@ void main() {
expect
(
viewport
.
toStringDeep
(
minLevel:
DiagnosticLevel
.
info
),
equalsIgnoringHashCodes
(
'
RenderSliverFillViewport
#00000 relayoutBoundary=up1
\n
'
'
_RenderSliverFractionalPadding
#00000 relayoutBoundary=up1
\n
'
' │ needs compositing
\n
'
' │ parentData: paintOffset=Offset(0.0, 0.0) (can use size)
\n
'
' │ constraints: SliverConstraints(AxisDirection.down,
\n
'
...
...
@@ -76,58 +76,71 @@ void main() {
' │ geometry: SliverGeometry(scrollExtent: 12000.0, paintExtent:
\n
'
' │ 600.0, maxPaintExtent: 12000.0, hasVisualOverflow: true,
\n
'
' │ cacheExtent: 850.0)
\n
'
' │ currently live children: 0 to 1
\n
'
' │
\n
'
' ├─child with index 0: RenderRepaintBoundary#00000
\n
'
' │ │ needs compositing
\n
'
' │ │ parentData: index=0; layoutOffset=0.0
\n
'
' │ │ constraints: BoxConstraints(w=800.0, h=600.0)
\n
'
' │ │ layer: OffsetLayer#00000
\n
'
' │ │ size: Size(800.0, 600.0)
\n
'
' │ │ metrics: 66.7% useful (1 bad vs 2 good)
\n
'
' │ │ diagnosis: insufficient data to draw conclusion (less than five
\n
'
' │ │ repaints)
\n
'
' │ │
\n
'
' │ └─child: RenderParagraph#00000
\n
'
' │ │ parentData: <none> (can use size)
\n
'
' │ │ constraints: BoxConstraints(w=800.0, h=600.0)
\n
'
' │ │ semantics node: SemanticsNode#2
\n
'
' │ │ size: Size(800.0, 600.0)
\n
'
' │ │ textAlign: start
\n
'
' │ │ textDirection: ltr
\n
'
' │ │ softWrap: wrapping at box width
\n
'
' │ │ overflow: clip
\n
'
' │ │ maxLines: unlimited
\n
'
' │ ╘═╦══ text ═══
\n
'
' │ ║ TextSpan:
\n
'
' │ ║ <all styles inherited>
\n
'
' │ ║ "0"
\n
'
' │ ╚═══════════
\n
'
' └─child with index 1: RenderRepaintBoundary#00000
\n
'
' └─child: RenderSliverFillViewport#00000 relayoutBoundary=up2
\n
'
' │ needs compositing
\n
'
' │ parentData: index=1; layoutOffset=600.0
\n
'
' │ constraints: BoxConstraints(w=800.0, h=600.0)
\n
'
' │ layer: OffsetLayer#00000 DETACHED
\n
'
' │ size: Size(800.0, 600.0)
\n
'
' │ metrics: 50.0% useful (1 bad vs 1 good)
\n
'
' │ diagnosis: insufficient data to draw conclusion (less than five
\n
'
' │ repaints)
\n
'
' │ parentData: paintOffset=Offset(0.0, 0.0) (can use size)
\n
'
' │ constraints: SliverConstraints(AxisDirection.down,
\n
'
' │ GrowthDirection.forward, ScrollDirection.idle, scrollOffset:
\n
'
' │ 0.0, remainingPaintExtent: 600.0, crossAxisExtent: 800.0,
\n
'
' │ crossAxisDirection: AxisDirection.right,
\n
'
' │ viewportMainAxisExtent: 600.0, remainingCacheExtent: 850.0
\n
'
' │ cacheOrigin: 0.0 )
\n
'
' │ geometry: SliverGeometry(scrollExtent: 12000.0, paintExtent:
\n
'
' │ 600.0, maxPaintExtent: 12000.0, hasVisualOverflow: true,
\n
'
' │ cacheExtent: 850.0)
\n
'
' │ currently live children: 0 to 1
\n
'
' │
\n
'
' └─child: RenderParagraph#00000
\n
'
' │ parentData: <none> (can use size)
\n
'
' ├─child with index 0: RenderRepaintBoundary#00000
\n
'
' │ │ needs compositing
\n
'
' │ │ parentData: index=0; layoutOffset=0.0
\n
'
' │ │ constraints: BoxConstraints(w=800.0, h=600.0)
\n
'
' │ │ layer: OffsetLayer#00000
\n
'
' │ │ size: Size(800.0, 600.0)
\n
'
' │ │ metrics: 66.7% useful (1 bad vs 2 good)
\n
'
' │ │ diagnosis: insufficient data to draw conclusion (less than five
\n
'
' │ │ repaints)
\n
'
' │ │
\n
'
' │ └─child: RenderParagraph#00000
\n
'
' │ │ parentData: <none> (can use size)
\n
'
' │ │ constraints: BoxConstraints(w=800.0, h=600.0)
\n
'
' │ │ semantics node: SemanticsNode#2
\n
'
' │ │ size: Size(800.0, 600.0)
\n
'
' │ │ textAlign: start
\n
'
' │ │ textDirection: ltr
\n
'
' │ │ softWrap: wrapping at box width
\n
'
' │ │ overflow: clip
\n
'
' │ │ maxLines: unlimited
\n
'
' │ ╘═╦══ text ═══
\n
'
' │ ║ TextSpan:
\n
'
' │ ║ <all styles inherited>
\n
'
' │ ║ "0"
\n
'
' │ ╚═══════════
\n
'
' └─child with index 1: RenderRepaintBoundary#00000
\n
'
' │ needs compositing
\n
'
' │ parentData: index=1; layoutOffset=600.0
\n
'
' │ constraints: BoxConstraints(w=800.0, h=600.0)
\n
'
' │
semantics node: SemanticsNode#3
\n
'
' │
layer: OffsetLayer#00000 DETACHED
\n
'
' │ size: Size(800.0, 600.0)
\n
'
' │ textAlign: start
\n
'
' │ textDirection: ltr
\n
'
' │ softWrap: wrapping at box width
\n
'
' │ overflow: clip
\n
'
' │ maxLines: unlimited
\n
'
' ╘═╦══ text ═══
\n
'
' ║ TextSpan:
\n
'
' ║ <all styles inherited>
\n
'
' ║ "1"
\n
'
' ╚═══════════
\n
'
' │ metrics: 50.0% useful (1 bad vs 1 good)
\n
'
' │ diagnosis: insufficient data to draw conclusion (less than five
\n
'
' │ repaints)
\n
'
' │
\n
'
' └─child: RenderParagraph#00000
\n
'
' │ parentData: <none> (can use size)
\n
'
' │ constraints: BoxConstraints(w=800.0, h=600.0)
\n
'
' │ semantics node: SemanticsNode#3
\n
'
' │ size: Size(800.0, 600.0)
\n
'
' │ textAlign: start
\n
'
' │ textDirection: ltr
\n
'
' │ softWrap: wrapping at box width
\n
'
' │ overflow: clip
\n
'
' │ maxLines: unlimited
\n
'
' ╘═╦══ text ═══
\n
'
' ║ TextSpan:
\n
'
' ║ <all styles inherited>
\n
'
' ║ "1"
\n
'
' ╚═══════════
\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