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
fa174b23
Unverified
Commit
fa174b23
authored
Oct 28, 2022
by
chunhtai
Committed by
GitHub
Oct 28, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
SingleChildScrollView does not clip semantics child (#114194)
parent
0dea659f
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
141 additions
and
188 deletions
+141
-188
single_child_scroll_view.dart
...ges/flutter/lib/src/widgets/single_child_scroll_view.dart
+22
-22
tabs_test.dart
packages/flutter/test/material/tabs_test.dart
+4
-3
scrollable_semantics_traversal_order_test.dart
...st/widgets/scrollable_semantics_traversal_order_test.dart
+20
-66
single_child_scroll_view_test.dart
...s/flutter/test/widgets/single_child_scroll_view_test.dart
+95
-97
No files found.
packages/flutter/lib/src/widgets/single_child_scroll_view.dart
View file @
fa174b23
...
...
@@ -326,16 +326,13 @@ class _RenderSingleChildViewport extends RenderBox with RenderObjectWithChildMix
_RenderSingleChildViewport
({
AxisDirection
axisDirection
=
AxisDirection
.
down
,
required
ViewportOffset
offset
,
double
cacheExtent
=
RenderAbstractViewport
.
defaultCacheExtent
,
RenderBox
?
child
,
required
Clip
clipBehavior
,
})
:
assert
(
axisDirection
!=
null
),
assert
(
offset
!=
null
),
assert
(
cacheExtent
!=
null
),
assert
(
clipBehavior
!=
null
),
_axisDirection
=
axisDirection
,
_offset
=
offset
,
_cacheExtent
=
cacheExtent
,
_clipBehavior
=
clipBehavior
{
this
.
child
=
child
;
}
...
...
@@ -370,18 +367,6 @@ class _RenderSingleChildViewport extends RenderBox with RenderObjectWithChildMix
markNeedsLayout
();
}
/// {@macro flutter.rendering.RenderViewportBase.cacheExtent}
double
get
cacheExtent
=>
_cacheExtent
;
double
_cacheExtent
;
set
cacheExtent
(
double
value
)
{
assert
(
value
!=
null
);
if
(
value
==
_cacheExtent
)
{
return
;
}
_cacheExtent
=
value
;
markNeedsLayout
();
}
/// {@macro flutter.material.Material.clipBehavior}
///
/// Defaults to [Clip.none], and must not be null.
...
...
@@ -700,19 +685,34 @@ class _RenderSingleChildViewport extends RenderBox with RenderObjectWithChildMix
@override
Rect
describeSemanticsClip
(
RenderObject
child
)
{
assert
(
axis
!=
null
);
switch
(
axis
)
{
case
Axis
.
vertical
:
final
double
remainingOffset
=
_maxScrollExtent
-
offset
.
pixels
;
switch
(
axisDirection
)
{
case
AxisDirection
.
up
:
return
Rect
.
fromLTRB
(
semanticBounds
.
left
,
semanticBounds
.
top
-
cacheExten
t
,
semanticBounds
.
top
-
remainingOffse
t
,
semanticBounds
.
right
,
semanticBounds
.
bottom
+
cacheExtent
,
semanticBounds
.
bottom
+
offset
.
pixels
,
);
case
Axis
.
horizontal
:
case
AxisDirection
.
right
:
return
Rect
.
fromLTRB
(
semanticBounds
.
left
-
offset
.
pixels
,
semanticBounds
.
top
,
semanticBounds
.
right
+
remainingOffset
,
semanticBounds
.
bottom
,
);
case
AxisDirection
.
down
:
return
Rect
.
fromLTRB
(
semanticBounds
.
left
,
semanticBounds
.
top
-
offset
.
pixels
,
semanticBounds
.
right
,
semanticBounds
.
bottom
+
remainingOffset
,
);
case
AxisDirection
.
left
:
return
Rect
.
fromLTRB
(
semanticBounds
.
left
-
cacheExten
t
,
semanticBounds
.
left
-
remainingOffse
t
,
semanticBounds
.
top
,
semanticBounds
.
right
+
cacheExtent
,
semanticBounds
.
right
+
offset
.
pixels
,
semanticBounds
.
bottom
,
);
}
...
...
packages/flutter/test/material/tabs_test.dart
View file @
fa174b23
...
...
@@ -2995,14 +2995,15 @@ void main() {
const
String
tab0title
=
'This is a very wide tab #0
\n
Tab 1 of 20'
;
const
String
tab10title
=
'This is a very wide tab #10
\n
Tab 11 of 20'
;
const
List
<
SemanticsFlag
>
hiddenFlags
=
<
SemanticsFlag
>[
SemanticsFlag
.
isHidden
,
SemanticsFlag
.
isFocusable
];
expect
(
semantics
,
includesNodeWith
(
actions:
<
SemanticsAction
>[
SemanticsAction
.
scrollLeft
]));
expect
(
semantics
,
includesNodeWith
(
label:
tab0title
));
expect
(
semantics
,
i
sNot
(
includesNodeWith
(
label:
tab10title
)
));
expect
(
semantics
,
i
ncludesNodeWith
(
label:
tab10title
,
flags:
hiddenFlags
));
controller
.
index
=
10
;
await
tester
.
pumpAndSettle
();
expect
(
semantics
,
i
sNot
(
includesNodeWith
(
label:
tab0title
)
));
expect
(
semantics
,
i
ncludesNodeWith
(
label:
tab0title
,
flags:
hiddenFlags
));
expect
(
semantics
,
includesNodeWith
(
actions:
<
SemanticsAction
>[
SemanticsAction
.
scrollLeft
,
SemanticsAction
.
scrollRight
]));
expect
(
semantics
,
includesNodeWith
(
label:
tab10title
));
...
...
@@ -3016,7 +3017,7 @@ void main() {
expect
(
semantics
,
includesNodeWith
(
actions:
<
SemanticsAction
>[
SemanticsAction
.
scrollLeft
]));
expect
(
semantics
,
includesNodeWith
(
label:
tab0title
));
expect
(
semantics
,
i
sNot
(
includesNodeWith
(
label:
tab10title
)
));
expect
(
semantics
,
i
ncludesNodeWith
(
label:
tab10title
,
flags:
hiddenFlags
));
semantics
.
dispose
();
});
...
...
packages/flutter/test/widgets/scrollable_semantics_traversal_order_test.dart
View file @
fa174b23
...
...
@@ -624,6 +624,25 @@ void main() {
),
);
final
List
<
TestSemantics
>
children
=
<
TestSemantics
>[];
for
(
int
index
=
0
;
index
<
30
;
index
+=
1
)
{
final
bool
isHidden
=
index
<
15
||
index
>
17
;
children
.
add
(
TestSemantics
(
flags:
isHidden
?
<
SemanticsFlag
>[
SemanticsFlag
.
isHidden
]
:
0
,
label:
'Item
${index}
a'
,
textDirection:
TextDirection
.
ltr
,
),
);
children
.
add
(
TestSemantics
(
flags:
isHidden
?
<
SemanticsFlag
>[
SemanticsFlag
.
isHidden
]
:
0
,
label:
'item
${index}
b'
,
textDirection:
TextDirection
.
ltr
,
),
);
}
expect
(
semantics
,
hasSemantics
(
TestSemantics
.
root
(
children:
<
TestSemantics
>[
...
...
@@ -638,72 +657,7 @@ void main() {
SemanticsAction
.
scrollUp
,
SemanticsAction
.
scrollDown
,
],
children:
<
TestSemantics
>[
TestSemantics
(
flags:
<
SemanticsFlag
>[
SemanticsFlag
.
isHidden
],
label:
'Item 13a'
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
flags:
<
SemanticsFlag
>[
SemanticsFlag
.
isHidden
],
label:
'item 13b'
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
flags:
<
SemanticsFlag
>[
SemanticsFlag
.
isHidden
],
label:
'Item 14a'
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
flags:
<
SemanticsFlag
>[
SemanticsFlag
.
isHidden
],
label:
'item 14b'
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
label:
'Item 15a'
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
label:
'item 15b'
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
label:
'Item 16a'
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
label:
'item 16b'
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
label:
'Item 17a'
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
label:
'item 17b'
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
flags:
<
SemanticsFlag
>[
SemanticsFlag
.
isHidden
],
label:
'Item 18a'
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
flags:
<
SemanticsFlag
>[
SemanticsFlag
.
isHidden
],
label:
'item 18b'
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
flags:
<
SemanticsFlag
>[
SemanticsFlag
.
isHidden
],
label:
'Item 19a'
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
flags:
<
SemanticsFlag
>[
SemanticsFlag
.
isHidden
],
label:
'item 19b'
,
textDirection:
TextDirection
.
ltr
,
),
],
children:
children
,
),
],
),
...
...
packages/flutter/test/widgets/single_child_scroll_view_test.dart
View file @
fa174b23
...
...
@@ -305,6 +305,19 @@ void main() {
),
);
List
<
TestSemantics
>
generateSemanticsChildren
({
int
startHidden
=
-
1
,
int
endHidden
=
30
})
{
final
List
<
TestSemantics
>
children
=
<
TestSemantics
>[];
for
(
int
index
=
0
;
index
<
30
;
index
+=
1
)
{
final
bool
isHidden
=
index
<=
startHidden
||
index
>=
endHidden
;
children
.
add
(
TestSemantics
(
label:
'Tile
$index
'
,
textDirection:
TextDirection
.
ltr
,
flags:
isHidden
?
const
<
SemanticsFlag
>[
SemanticsFlag
.
isHidden
]
:
0
,
));
}
return
children
;
}
expect
(
semantics
,
hasSemantics
(
TestSemantics
(
children:
<
TestSemantics
>[
...
...
@@ -315,33 +328,7 @@ void main() {
actions:
<
SemanticsAction
>[
SemanticsAction
.
scrollUp
,
],
children:
<
TestSemantics
>[
TestSemantics
(
label:
r'Tile 0'
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
label:
r'Tile 1'
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
label:
r'Tile 2'
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
flags:
<
SemanticsFlag
>[
SemanticsFlag
.
isHidden
,
],
label:
r'Tile 3'
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
flags:
<
SemanticsFlag
>[
SemanticsFlag
.
isHidden
,],
label:
r'Tile 4'
,
textDirection:
TextDirection
.
ltr
,
),
],
children:
generateSemanticsChildren
(
endHidden:
3
),
),
],
),
...
...
@@ -362,48 +349,7 @@ void main() {
SemanticsAction
.
scrollUp
,
SemanticsAction
.
scrollDown
,
],
children:
<
TestSemantics
>[
TestSemantics
(
flags:
<
SemanticsFlag
>[
SemanticsFlag
.
isHidden
,
],
label:
r'Tile 13'
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
flags:
<
SemanticsFlag
>[
SemanticsFlag
.
isHidden
,
],
label:
r'Tile 14'
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
label:
r'Tile 15'
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
label:
r'Tile 16'
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
label:
r'Tile 17'
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
flags:
<
SemanticsFlag
>[
SemanticsFlag
.
isHidden
,
],
label:
r'Tile 18'
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
flags:
<
SemanticsFlag
>[
SemanticsFlag
.
isHidden
,
],
label:
r'Tile 19'
,
textDirection:
TextDirection
.
ltr
,
),
],
children:
generateSemanticsChildren
(
startHidden:
14
,
endHidden:
18
),
),
],
),
...
...
@@ -423,34 +369,7 @@ void main() {
actions:
<
SemanticsAction
>[
SemanticsAction
.
scrollDown
,
],
children:
<
TestSemantics
>[
TestSemantics
(
flags:
<
SemanticsFlag
>[
SemanticsFlag
.
isHidden
,
],
label:
r'Tile 25'
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
flags:
<
SemanticsFlag
>[
SemanticsFlag
.
isHidden
,
],
label:
r'Tile 26'
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
label:
r'Tile 27'
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
label:
r'Tile 28'
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
label:
r'Tile 29'
,
textDirection:
TextDirection
.
ltr
,
),
],
children:
generateSemanticsChildren
(
startHidden:
26
),
),
],
),
...
...
@@ -460,6 +379,85 @@ void main() {
semantics
.
dispose
();
});
testWidgets
(
'SingleChildScrollView semantics clips cover entire child vertical'
,
(
WidgetTester
tester
)
async
{
final
ScrollController
controller
=
ScrollController
();
final
UniqueKey
scrollView
=
UniqueKey
();
final
UniqueKey
childBox
=
UniqueKey
();
const
double
length
=
10000
;
await
tester
.
pumpWidget
(
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
SingleChildScrollView
(
key:
scrollView
,
controller:
controller
,
child:
SizedBox
(
key:
childBox
,
height:
length
),
),
),
);
final
RenderObject
scrollRenderObject
=
tester
.
renderObject
(
find
.
byKey
(
scrollView
));
RenderAbstractViewport
?
viewport
;
void
findsRenderViewPort
(
RenderObject
child
)
{
if
(
viewport
!=
null
)
{
return
;
}
if
(
child
is
RenderAbstractViewport
)
{
viewport
=
child
;
return
;
}
child
.
visitChildren
(
findsRenderViewPort
);
}
scrollRenderObject
.
visitChildren
(
findsRenderViewPort
);
expect
(
viewport
,
isNotNull
);
final
RenderObject
childRenderObject
=
tester
.
renderObject
(
find
.
byKey
(
childBox
));
Rect
semanticsClip
=
viewport
!.
describeSemanticsClip
(
childRenderObject
)!;
expect
(
semanticsClip
.
size
.
height
,
length
);
controller
.
jumpTo
(
2000
);
await
tester
.
pump
();
semanticsClip
=
viewport
!.
describeSemanticsClip
(
childRenderObject
)!;
expect
(
semanticsClip
.
size
.
height
,
length
);
});
testWidgets
(
'SingleChildScrollView semantics clips cover entire child'
,
(
WidgetTester
tester
)
async
{
final
ScrollController
controller
=
ScrollController
();
final
UniqueKey
scrollView
=
UniqueKey
();
final
UniqueKey
childBox
=
UniqueKey
();
const
double
length
=
10000
;
await
tester
.
pumpWidget
(
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
SingleChildScrollView
(
key:
scrollView
,
scrollDirection:
Axis
.
horizontal
,
controller:
controller
,
child:
SizedBox
(
key:
childBox
,
width:
length
),
),
),
);
final
RenderObject
scrollRenderObject
=
tester
.
renderObject
(
find
.
byKey
(
scrollView
));
RenderAbstractViewport
?
viewport
;
void
findsRenderViewPort
(
RenderObject
child
)
{
if
(
viewport
!=
null
)
{
return
;
}
if
(
child
is
RenderAbstractViewport
)
{
viewport
=
child
;
return
;
}
child
.
visitChildren
(
findsRenderViewPort
);
}
scrollRenderObject
.
visitChildren
(
findsRenderViewPort
);
expect
(
viewport
,
isNotNull
);
final
RenderObject
childRenderObject
=
tester
.
renderObject
(
find
.
byKey
(
childBox
));
Rect
semanticsClip
=
viewport
!.
describeSemanticsClip
(
childRenderObject
)!;
expect
(
semanticsClip
.
size
.
width
,
length
);
controller
.
jumpTo
(
2000
);
await
tester
.
pump
();
semanticsClip
=
viewport
!.
describeSemanticsClip
(
childRenderObject
)!;
expect
(
semanticsClip
.
size
.
width
,
length
);
});
testWidgets
(
'SingleChildScrollView getOffsetToReveal - down'
,
(
WidgetTester
tester
)
async
{
List
<
Widget
>
children
;
await
tester
.
pumpWidget
(
...
...
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