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
7d6ffc7c
Unverified
Commit
7d6ffc7c
authored
Aug 24, 2020
by
LongCatIsLooong
Committed by
GitHub
Aug 24, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add rect logic to getOffsetToReveal when onlySlivers is true (#64295)
parent
e30e795a
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
158 additions
and
81 deletions
+158
-81
viewport.dart
packages/flutter/lib/src/rendering/viewport.dart
+103
-65
viewport_test.dart
packages/flutter/test/rendering/viewport_test.dart
+55
-16
No files found.
packages/flutter/lib/src/rendering/viewport.dart
View file @
7d6ffc7c
...
...
@@ -692,10 +692,24 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix
@override
RevealedOffset
getOffsetToReveal
(
RenderObject
target
,
double
alignment
,
{
Rect
rect
})
{
double
leadingScrollOffset
=
0.0
;
double
targetMainAxisExtent
;
rect
??=
target
.
paintBounds
;
// Steps to convert `rect` (from a RenderBox coordinate system) to its
// scroll offset within this viewport (not in the exact order):
//
// 1. Pick the outmost RenderBox (between which, and the viewport, there is
// nothing but RenderSlivers) as an intermediate reference frame
// (the `pivot`), convert `rect` to that coordinate space.
//
// 2. Convert `rect` from the `pivot` coordinate space to its sliver
// parent's sliver coordinate system (i.e., to a scroll offset), based on
// the axis direction and growth direction of the parent.
//
// 3. Convert the scroll offset to its sliver parent's coordinate space
// using `childScrollOffset`, until we reach the viewport.
//
// 4. Make the final conversion from the outmost sliver to the viewport
// using `scrollOffsetOf`.
double
leadingScrollOffset
=
0.0
;
// Starting at `target` and walking towards the root:
// - `child` will be the last object before we reach this viewport, and
// - `pivot` will be the last RenderBox before we reach this viewport.
...
...
@@ -717,89 +731,116 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix
child
=
parent
;
}
// `rect` in the new intermediate coordinate system.
Rect
rectLocal
;
// Our new reference frame render object's main axis extent.
double
pivotExtent
;
GrowthDirection
growthDirection
;
// `leadingScrollOffset` is currently the scrollOffset of our new reference
// frame (`pivot` or `target`), within `child`.
if
(
pivot
!=
null
)
{
assert
(
pivot
.
parent
!=
null
);
assert
(
pivot
.
parent
!=
this
);
assert
(
pivot
!=
this
);
assert
(
pivot
.
parent
is
RenderSliver
);
// TODO(abarth): Support other kinds of render objects besides slivers.
final
RenderSliver
pivotParent
=
pivot
.
parent
as
RenderSliver
;
final
Matrix4
transform
=
target
.
getTransformTo
(
pivot
);
final
Rect
bounds
=
MatrixUtils
.
transformRect
(
transform
,
rect
);
final
GrowthDirection
growthDirection
=
pivotParent
.
constraints
.
growthDirection
;
switch
(
applyGrowthDirectionToAxisDirection
(
axisDirection
,
growthDirection
))
{
case
AxisDirection
.
up
:
double
offset
;
switch
(
growthDirection
)
{
case
GrowthDirection
.
forward
:
offset
=
bounds
.
bottom
;
break
;
case
GrowthDirection
.
reverse
:
offset
=
bounds
.
top
;
break
;
}
leadingScrollOffset
+=
pivot
.
size
.
height
-
offset
;
targetMainAxisExtent
=
bounds
.
height
;
break
;
case
AxisDirection
.
right
:
double
offset
;
switch
(
growthDirection
)
{
case
GrowthDirection
.
forward
:
offset
=
bounds
.
left
;
break
;
case
GrowthDirection
.
reverse
:
offset
=
bounds
.
right
;
break
;
}
leadingScrollOffset
+=
offset
;
targetMainAxisExtent
=
bounds
.
width
;
break
;
case
AxisDirection
.
down
:
double
offset
;
switch
(
growthDirection
)
{
case
GrowthDirection
.
forward
:
offset
=
bounds
.
top
;
growthDirection
=
pivotParent
.
constraints
.
growthDirection
;
switch
(
axis
)
{
case
Axis
.
horizontal
:
pivotExtent
=
pivot
.
size
.
width
;
break
;
case
GrowthDirection
.
reverse
:
offset
=
bounds
.
bottom
;
case
Axis
.
vertical
:
pivotExtent
=
pivot
.
size
.
height
;
break
;
}
leadingScrollOffset
+=
offset
;
targetMainAxisExtent
=
bounds
.
height
;
break
;
case
AxisDirection
.
left
:
double
offset
;
switch
(
growthDirection
)
{
case
GrowthDirection
.
forward
:
offset
=
bounds
.
right
;
rect
??=
target
.
paintBounds
;
rectLocal
=
MatrixUtils
.
transformRect
(
target
.
getTransformTo
(
pivot
),
rect
);
}
else
if
(
onlySlivers
)
{
// `pivot` does not exist. We'll have to make up one from `target`, the
// innermost sliver.
final
RenderSliver
targetSliver
=
target
as
RenderSliver
;
growthDirection
=
targetSliver
.
constraints
.
growthDirection
;
// TODO(LongCatIsLooong): make sure this works if `targetSliver` is a
// persistent header, when #56413 relands.
pivotExtent
=
targetSliver
.
geometry
.
scrollExtent
;
if
(
rect
==
null
)
{
switch
(
axis
)
{
case
Axis
.
horizontal
:
rect
=
Rect
.
fromLTWH
(
0
,
0
,
targetSliver
.
geometry
.
scrollExtent
,
targetSliver
.
constraints
.
crossAxisExtent
,
);
break
;
case
GrowthDirection
.
reverse
:
offset
=
bounds
.
left
;
case
Axis
.
vertical
:
rect
=
Rect
.
fromLTWH
(
0
,
0
,
targetSliver
.
constraints
.
crossAxisExtent
,
targetSliver
.
geometry
.
scrollExtent
,
);
break
;
}
leadingScrollOffset
+=
pivot
.
size
.
width
-
offset
;
targetMainAxisExtent
=
bounds
.
width
;
break
;
}
}
else
if
(
onlySlivers
)
{
final
RenderSliver
targetSliver
=
target
as
RenderSliver
;
targetMainAxisExtent
=
targetSliver
.
geometry
.
scrollExtent
;
rectLocal
=
rect
;
}
else
{
return
RevealedOffset
(
offset:
offset
.
pixels
,
rect:
rect
);
}
assert
(
pivotExtent
!=
null
);
assert
(
rect
!=
null
);
assert
(
rectLocal
!=
null
);
assert
(
growthDirection
!=
null
);
assert
(
child
.
parent
==
this
);
assert
(
child
is
RenderSliver
);
final
RenderSliver
sliver
=
child
as
RenderSliver
;
final
double
extentOfPinnedSlivers
=
maxScrollObstructionExtentBefore
(
sliver
);
double
targetMainAxisExtent
;
// The scroll offset within `child` to `rect`.
switch
(
applyGrowthDirectionToAxisDirection
(
axisDirection
,
growthDirection
))
{
case
AxisDirection
.
up
:
leadingScrollOffset
+=
pivotExtent
-
rectLocal
.
bottom
;
targetMainAxisExtent
=
rectLocal
.
height
;
break
;
case
AxisDirection
.
right
:
leadingScrollOffset
+=
rectLocal
.
left
;
targetMainAxisExtent
=
rectLocal
.
width
;
break
;
case
AxisDirection
.
down
:
leadingScrollOffset
+=
rectLocal
.
top
;
targetMainAxisExtent
=
rectLocal
.
height
;
break
;
case
AxisDirection
.
left
:
leadingScrollOffset
+=
pivotExtent
-
rectLocal
.
right
;
targetMainAxisExtent
=
rectLocal
.
width
;
break
;
}
// The scroll offset in the viewport to `rect`.
leadingScrollOffset
=
scrollOffsetOf
(
sliver
,
leadingScrollOffset
);
// This step assumes the viewport's layout is up-to-date, i.e., if
// offset.pixels is changed after the last performLayout, the new scroll
// position will not be accounted for.
final
Matrix4
transform
=
target
.
getTransformTo
(
this
);
Rect
targetRect
=
MatrixUtils
.
transformRect
(
transform
,
rect
);
final
double
extentOfPinnedSlivers
=
maxScrollObstructionExtentBefore
(
sliver
);
switch
(
sliver
.
constraints
.
growthDirection
)
{
case
GrowthDirection
.
forward
:
leadingScrollOffset
-=
extentOfPinnedSlivers
;
break
;
case
GrowthDirection
.
reverse
:
// Nothing to do.
// If child's growth direction is reverse, when viewport.offset is
// `leadingScrollOffset`, it is positioned just outside of the leading
// edge of the viewport.
switch
(
axis
)
{
case
Axis
.
vertical
:
leadingScrollOffset
-=
targetRect
.
height
;
break
;
case
Axis
.
horizontal
:
leadingScrollOffset
-=
targetRect
.
width
;
break
;
}
break
;
}
...
...
@@ -816,9 +857,6 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix
final
double
targetOffset
=
leadingScrollOffset
-
(
mainAxisExtent
-
targetMainAxisExtent
)
*
alignment
;
final
double
offsetDifference
=
offset
.
pixels
-
targetOffset
;
final
Matrix4
transform
=
target
.
getTransformTo
(
this
);
Rect
targetRect
=
MatrixUtils
.
transformRect
(
transform
,
rect
);
switch
(
axisDirection
)
{
case
AxisDirection
.
down
:
targetRect
=
targetRect
.
translate
(
0.0
,
offsetDifference
);
...
...
packages/flutter/test/rendering/viewport_test.dart
View file @
7d6ffc7c
...
...
@@ -220,7 +220,7 @@ void main() {
);
children
.
add
(
sliver
);
return
SliverPadding
(
padding:
const
EdgeInsets
.
all
(
22
.0
),
padding:
const
EdgeInsets
.
only
(
top:
22.0
,
bottom:
23
.0
),
sliver:
sliver
,
);
}),
...
...
@@ -234,10 +234,16 @@ void main() {
final
RenderObject
target
=
tester
.
renderObject
(
find
.
byWidget
(
children
[
5
],
skipOffstage:
false
));
RevealedOffset
revealed
=
viewport
.
getOffsetToReveal
(
target
,
0.0
);
expect
(
revealed
.
offset
,
5
*
(
100
+
22
+
2
2
)
+
22
);
expect
(
revealed
.
offset
,
5
*
(
100
+
22
+
2
3
)
+
22
);
revealed
=
viewport
.
getOffsetToReveal
(
target
,
1.0
);
expect
(
revealed
.
offset
,
5
*
(
100
+
22
+
22
)
+
22
-
100
);
expect
(
revealed
.
offset
,
5
*
(
100
+
22
+
23
)
+
22
-
100
);
// With rect specified.
revealed
=
viewport
.
getOffsetToReveal
(
target
,
0.0
,
rect:
const
Rect
.
fromLTRB
(
1
,
2
,
3
,
4
));
expect
(
revealed
.
offset
,
5
*
(
100
+
22
+
23
)
+
22
+
2
);
revealed
=
viewport
.
getOffsetToReveal
(
target
,
1.0
,
rect:
const
Rect
.
fromLTRB
(
1
,
2
,
3
,
4
));
expect
(
revealed
.
offset
,
5
*
(
100
+
22
+
23
)
+
22
-
(
200
-
4
));
});
testWidgets
(
'Viewport getOffsetToReveal Sliver - right'
,
(
WidgetTester
tester
)
async
{
...
...
@@ -261,7 +267,7 @@ void main() {
);
children
.
add
(
sliver
);
return
SliverPadding
(
padding:
const
EdgeInsets
.
all
(
22
.0
),
padding:
const
EdgeInsets
.
only
(
left:
22.0
,
right:
23
.0
),
sliver:
sliver
,
);
}),
...
...
@@ -275,10 +281,16 @@ void main() {
final
RenderObject
target
=
tester
.
renderObject
(
find
.
byWidget
(
children
[
5
],
skipOffstage:
false
));
RevealedOffset
revealed
=
viewport
.
getOffsetToReveal
(
target
,
0.0
);
expect
(
revealed
.
offset
,
5
*
(
100
+
22
+
2
2
)
+
22
);
expect
(
revealed
.
offset
,
5
*
(
100
+
22
+
2
3
)
+
22
);
revealed
=
viewport
.
getOffsetToReveal
(
target
,
1.0
);
expect
(
revealed
.
offset
,
5
*
(
100
+
22
+
22
)
+
22
-
100
);
expect
(
revealed
.
offset
,
5
*
(
100
+
22
+
23
)
+
22
-
100
);
// With rect specified.
revealed
=
viewport
.
getOffsetToReveal
(
target
,
0.0
,
rect:
const
Rect
.
fromLTRB
(
1
,
2
,
3
,
4
));
expect
(
revealed
.
offset
,
5
*
(
100
+
22
+
23
)
+
22
+
1
);
revealed
=
viewport
.
getOffsetToReveal
(
target
,
1.0
,
rect:
const
Rect
.
fromLTRB
(
1
,
2
,
3
,
4
));
expect
(
revealed
.
offset
,
5
*
(
100
+
22
+
23
)
+
22
-
(
200
-
3
));
});
testWidgets
(
'Viewport getOffsetToReveal Sliver - up'
,
(
WidgetTester
tester
)
async
{
...
...
@@ -302,7 +314,7 @@ void main() {
);
children
.
add
(
sliver
);
return
SliverPadding
(
padding:
const
EdgeInsets
.
all
(
22
.0
),
padding:
const
EdgeInsets
.
only
(
top:
22.0
,
bottom:
23
.0
),
sliver:
sliver
,
);
}),
...
...
@@ -316,17 +328,25 @@ void main() {
final
RenderObject
target
=
tester
.
renderObject
(
find
.
byWidget
(
children
[
5
],
skipOffstage:
false
));
RevealedOffset
revealed
=
viewport
.
getOffsetToReveal
(
target
,
0.0
);
expect
(
revealed
.
offset
,
5
*
(
100
+
22
+
22
)
+
22
);
// Does not include the bottom padding of children[5] thus + 23 instead of + 22.
expect
(
revealed
.
offset
,
5
*
(
100
+
22
+
23
)
+
23
);
revealed
=
viewport
.
getOffsetToReveal
(
target
,
1.0
);
expect
(
revealed
.
offset
,
5
*
(
100
+
22
+
22
)
+
22
-
100
);
expect
(
revealed
.
offset
,
5
*
(
100
+
22
+
23
)
+
23
-
100
);
// With rect specified.
revealed
=
viewport
.
getOffsetToReveal
(
target
,
0.0
,
rect:
const
Rect
.
fromLTRB
(
1
,
2
,
3
,
4
));
expect
(
revealed
.
offset
,
5
*
(
100
+
22
+
23
)
+
23
+
(
100
-
4
));
revealed
=
viewport
.
getOffsetToReveal
(
target
,
1.0
,
rect:
const
Rect
.
fromLTRB
(
1
,
2
,
3
,
4
));
expect
(
revealed
.
offset
,
-
200
+
6
*
(
100
+
22
+
23
)
-
22
-
2
);
});
testWidgets
(
'Viewport getOffsetToReveal Sliver - up - reverse growth'
,
(
WidgetTester
tester
)
async
{
const
Key
centerKey
=
ValueKey
<
String
>(
'center'
);
const
EdgeInsets
padding
=
EdgeInsets
.
only
(
top:
22.0
,
bottom:
23.0
);
final
Widget
centerSliver
=
SliverPadding
(
key:
centerKey
,
padding:
const
EdgeInsets
.
all
(
22.0
)
,
padding:
padding
,
sliver:
SliverToBoxAdapter
(
child:
Container
(
height:
100.0
,
...
...
@@ -339,7 +359,7 @@ void main() {
child:
const
Text
(
'Tile lower'
),
);
final
Widget
lowerSliver
=
SliverPadding
(
padding:
const
EdgeInsets
.
all
(
22.0
)
,
padding:
padding
,
sliver:
SliverToBoxAdapter
(
child:
lowerItem
,
),
...
...
@@ -370,13 +390,20 @@ void main() {
revealed
=
viewport
.
getOffsetToReveal
(
target
,
1.0
);
expect
(
revealed
.
offset
,
-
100
-
22
-
100
);
// With rect specified.
revealed
=
viewport
.
getOffsetToReveal
(
target
,
0.0
,
rect:
const
Rect
.
fromLTRB
(
1
,
2
,
3
,
4
));
expect
(
revealed
.
offset
,
-
22
-
4
);
revealed
=
viewport
.
getOffsetToReveal
(
target
,
1.0
,
rect:
const
Rect
.
fromLTRB
(
1
,
2
,
3
,
4
));
expect
(
revealed
.
offset
,
-
200
-
22
-
2
);
});
testWidgets
(
'Viewport getOffsetToReveal Sliver - left - reverse growth'
,
(
WidgetTester
tester
)
async
{
const
Key
centerKey
=
ValueKey
<
String
>(
'center'
);
const
EdgeInsets
padding
=
EdgeInsets
.
only
(
left:
22.0
,
right:
23.0
);
final
Widget
centerSliver
=
SliverPadding
(
key:
centerKey
,
padding:
const
EdgeInsets
.
all
(
22.0
)
,
padding:
padding
,
sliver:
SliverToBoxAdapter
(
child:
Container
(
width:
100.0
,
...
...
@@ -389,7 +416,7 @@ void main() {
child:
const
Text
(
'Tile lower'
),
);
final
Widget
lowerSliver
=
SliverPadding
(
padding:
const
EdgeInsets
.
all
(
22.0
)
,
padding:
padding
,
sliver:
SliverToBoxAdapter
(
child:
lowerItem
,
),
...
...
@@ -421,6 +448,12 @@ void main() {
revealed
=
viewport
.
getOffsetToReveal
(
target
,
1.0
);
expect
(
revealed
.
offset
,
-
100
-
22
-
200
);
// With rect specified.
revealed
=
viewport
.
getOffsetToReveal
(
target
,
0.0
,
rect:
const
Rect
.
fromLTRB
(
1
,
2
,
3
,
4
));
expect
(
revealed
.
offset
,
-
22
-
3
);
revealed
=
viewport
.
getOffsetToReveal
(
target
,
1.0
,
rect:
const
Rect
.
fromLTRB
(
1
,
2
,
3
,
4
));
expect
(
revealed
.
offset
,
-
300
-
22
-
1
);
});
testWidgets
(
'Viewport getOffsetToReveal Sliver - left'
,
(
WidgetTester
tester
)
async
{
...
...
@@ -445,7 +478,7 @@ void main() {
);
children
.
add
(
sliver
);
return
SliverPadding
(
padding:
const
EdgeInsets
.
all
(
22
.0
),
padding:
const
EdgeInsets
.
only
(
left:
22.0
,
right:
23
.0
),
sliver:
sliver
,
);
}),
...
...
@@ -459,10 +492,16 @@ void main() {
final
RenderObject
target
=
tester
.
renderObject
(
find
.
byWidget
(
children
[
5
],
skipOffstage:
false
));
RevealedOffset
revealed
=
viewport
.
getOffsetToReveal
(
target
,
0.0
);
expect
(
revealed
.
offset
,
5
*
(
100
+
22
+
2
2
)
+
22
);
expect
(
revealed
.
offset
,
5
*
(
100
+
22
+
2
3
)
+
23
);
revealed
=
viewport
.
getOffsetToReveal
(
target
,
1.0
);
expect
(
revealed
.
offset
,
5
*
(
100
+
22
+
22
)
+
22
-
100
);
expect
(
revealed
.
offset
,
5
*
(
100
+
22
+
23
)
+
23
-
100
);
// With rect specified.
revealed
=
viewport
.
getOffsetToReveal
(
target
,
0.0
,
rect:
const
Rect
.
fromLTRB
(
1
,
2
,
3
,
4
));
expect
(
revealed
.
offset
,
6
*
(
100
+
22
+
23
)
-
22
-
3
);
revealed
=
viewport
.
getOffsetToReveal
(
target
,
1.0
,
rect:
const
Rect
.
fromLTRB
(
1
,
2
,
3
,
4
));
expect
(
revealed
.
offset
,
-
200
+
6
*
(
100
+
22
+
23
)
-
22
-
1
);
});
testWidgets
(
'Nested Viewports showOnScreen'
,
(
WidgetTester
tester
)
async
{
...
...
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