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
8e8a1c8c
Unverified
Commit
8e8a1c8c
authored
Jun 16, 2022
by
Taha Tesser
Committed by
GitHub
Jun 16, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix `StretchingOverscrollIndicator` clipping and add `clipBehavior` parameter (#105303)
parent
3f401a19
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
173 additions
and
3 deletions
+173
-3
app.dart
packages/flutter/lib/src/material/app.dart
+1
-0
overscroll_indicator.dart
packages/flutter/lib/src/widgets/overscroll_indicator.dart
+10
-2
scroll_view.dart
packages/flutter/lib/src/widgets/scroll_view.dart
+1
-0
scrollable.dart
packages/flutter/lib/src/widgets/scrollable.dart
+19
-1
app_test.dart
packages/flutter/test/material/app_test.dart
+78
-0
overscroll_stretch_indicator_test.dart
...utter/test/widgets/overscroll_stretch_indicator_test.dart
+64
-0
No files found.
packages/flutter/lib/src/material/app.dart
View file @
8e8a1c8c
...
...
@@ -819,6 +819,7 @@ class MaterialScrollBehavior extends ScrollBehavior {
case
AndroidOverscrollIndicator
.
stretch
:
return
StretchingOverscrollIndicator
(
axisDirection:
details
.
direction
,
clipBehavior:
details
.
clipBehavior
,
child:
child
,
);
case
AndroidOverscrollIndicator
.
glow
:
...
...
packages/flutter/lib/src/widgets/overscroll_indicator.dart
View file @
8e8a1c8c
...
...
@@ -653,9 +653,11 @@ class StretchingOverscrollIndicator extends StatefulWidget {
super
.
key
,
required
this
.
axisDirection
,
this
.
notificationPredicate
=
defaultScrollNotificationPredicate
,
this
.
clipBehavior
=
Clip
.
hardEdge
,
this
.
child
,
})
:
assert
(
axisDirection
!=
null
),
assert
(
notificationPredicate
!=
null
);
assert
(
notificationPredicate
!=
null
),
assert
(
clipBehavior
!=
null
);
/// {@macro flutter.overscroll.axisDirection}
final
AxisDirection
axisDirection
;
...
...
@@ -666,6 +668,11 @@ class StretchingOverscrollIndicator extends StatefulWidget {
/// {@macro flutter.overscroll.notificationPredicate}
final
ScrollNotificationPredicate
notificationPredicate
;
/// {@macro flutter.material.Material.clipBehavior}
///
/// Defaults to [Clip.hardEdge].
final
Clip
clipBehavior
;
/// The widget below this widget in the tree.
///
/// The overscroll indicator will apply a stretch effect to this child. This
...
...
@@ -806,7 +813,8 @@ class _StretchingOverscrollIndicatorState extends State<StretchingOverscrollIndi
// screen, overflow from transforming the viewport is irrelevant.
return
ClipRect
(
clipBehavior:
stretch
!=
0.0
&&
viewportDimension
!=
mainAxisSize
?
Clip
.
hardEdge
:
Clip
.
none
,
?
widget
.
clipBehavior
:
Clip
.
none
,
child:
transform
,
);
},
...
...
packages/flutter/lib/src/widgets/scroll_view.dart
View file @
8e8a1c8c
...
...
@@ -425,6 +425,7 @@ abstract class ScrollView extends StatelessWidget {
viewportBuilder:
(
BuildContext
context
,
ViewportOffset
offset
)
{
return
buildViewport
(
context
,
offset
,
axisDirection
,
slivers
);
},
clipBehavior:
clipBehavior
,
);
final
Widget
scrollableResult
=
effectivePrimary
&&
scrollController
!=
null
...
...
packages/flutter/lib/src/widgets/scrollable.dart
View file @
8e8a1c8c
...
...
@@ -97,6 +97,7 @@ class Scrollable extends StatefulWidget {
this
.
dragStartBehavior
=
DragStartBehavior
.
start
,
this
.
restorationId
,
this
.
scrollBehavior
,
this
.
clipBehavior
=
Clip
.
hardEdge
,
})
:
assert
(
axisDirection
!=
null
),
assert
(
dragStartBehavior
!=
null
),
assert
(
viewportBuilder
!=
null
),
...
...
@@ -261,6 +262,14 @@ class Scrollable extends StatefulWidget {
/// [ScrollBehavior].
final
ScrollBehavior
?
scrollBehavior
;
/// {@macro flutter.material.Material.clipBehavior}
///
/// Defaults to [Clip.hardEdge].
///
/// Rather than clipping [Scrollable], this is passed to decorators in
/// [ScrollableDetails].
final
Clip
clipBehavior
;
/// The axis along which the scroll view scrolls.
///
/// Determined by the [axisDirection].
...
...
@@ -797,6 +806,7 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin, R
final
ScrollableDetails
details
=
ScrollableDetails
(
direction:
widget
.
axisDirection
,
controller:
_effectiveScrollController
,
clipBehavior:
widget
.
clipBehavior
,
);
result
=
_configuration
.
buildScrollbar
(
...
...
@@ -812,7 +822,7 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin, R
state:
this
,
position:
position
,
registrar:
registrar
,
child:
result
child:
result
,
);
}
...
...
@@ -1313,6 +1323,7 @@ class ScrollableDetails {
const
ScrollableDetails
({
required
this
.
direction
,
required
this
.
controller
,
required
this
.
clipBehavior
,
});
/// The direction in which this widget scrolls.
...
...
@@ -1326,6 +1337,13 @@ class ScrollableDetails {
/// This can be used by [ScrollBehavior] to apply a [Scrollbar] to the associated
/// [Scrollable].
final
ScrollController
controller
;
/// {@macro flutter.material.Material.clipBehavior}
///
/// This can be used by [MaterialScrollBehavior] to clip [StretchingOverscrollIndicator].
///
/// Cannot be null.
final
Clip
clipBehavior
;
}
/// With [_ScrollSemantics] certain child [SemanticsNode]s can be
...
...
packages/flutter/test/material/app_test.dart
View file @
8e8a1c8c
...
...
@@ -11,6 +11,7 @@
import
'package:flutter/cupertino.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
...
...
@@ -1265,6 +1266,83 @@ void main() {
expect
(
find
.
byType
(
GlowingOverscrollIndicator
),
findsNothing
);
},
variant:
TargetPlatformVariant
.
only
(
TargetPlatform
.
android
));
testWidgets
(
'ListView clip behavior updates overscroll indicator clip behavior'
,
(
WidgetTester
tester
)
async
{
Widget
buildFrame
(
Clip
clipBehavior
)
{
return
MaterialApp
(
theme:
ThemeData
(
useMaterial3:
true
),
home:
Column
(
children:
<
Widget
>[
SizedBox
(
height:
300
,
child:
ListView
.
builder
(
itemCount:
20
,
clipBehavior:
clipBehavior
,
itemBuilder:
(
BuildContext
context
,
int
index
){
return
Padding
(
padding:
const
EdgeInsets
.
all
(
10.0
),
child:
Text
(
'Index
$index
'
),
);
},
),
),
Opacity
(
opacity:
0.5
,
child:
Container
(
color:
const
Color
(
0xD0FF0000
),
height:
100
,
),
),
],
),
);
}
// Test default clip behavior.
await
tester
.
pumpWidget
(
buildFrame
(
Clip
.
hardEdge
));
expect
(
find
.
byType
(
StretchingOverscrollIndicator
),
findsOneWidget
);
expect
(
find
.
byType
(
GlowingOverscrollIndicator
),
findsNothing
);
expect
(
find
.
text
(
'Index 1'
),
findsOneWidget
);
RenderClipRect
renderClip
=
tester
.
allRenderObjects
.
whereType
<
RenderClipRect
>().
first
;
// Currently not clipping
expect
(
renderClip
.
clipBehavior
,
equals
(
Clip
.
none
));
TestGesture
gesture
=
await
tester
.
startGesture
(
tester
.
getCenter
(
find
.
text
(
'Index 1'
)));
// Overscroll the start.
await
gesture
.
moveBy
(
const
Offset
(
0.0
,
200.0
));
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'Index 1'
),
findsOneWidget
);
expect
(
tester
.
getCenter
(
find
.
text
(
'Index 1'
)).
dy
,
greaterThan
(
0
));
renderClip
=
tester
.
allRenderObjects
.
whereType
<
RenderClipRect
>().
first
;
// Now clipping
expect
(
renderClip
.
clipBehavior
,
equals
(
Clip
.
hardEdge
));
await
gesture
.
up
();
await
tester
.
pumpAndSettle
();
// Test custom clip behavior.
await
tester
.
pumpWidget
(
buildFrame
(
Clip
.
none
));
renderClip
=
tester
.
allRenderObjects
.
whereType
<
RenderClipRect
>().
first
;
// Currently not clipping
expect
(
renderClip
.
clipBehavior
,
equals
(
Clip
.
none
));
gesture
=
await
tester
.
startGesture
(
tester
.
getCenter
(
find
.
text
(
'Index 1'
)));
// Overscroll the start.
await
gesture
.
moveBy
(
const
Offset
(
0.0
,
200.0
));
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'Index 1'
),
findsOneWidget
);
expect
(
tester
.
getCenter
(
find
.
text
(
'Index 1'
)).
dy
,
greaterThan
(
0
));
renderClip
=
tester
.
allRenderObjects
.
whereType
<
RenderClipRect
>().
first
;
// Now clipping
expect
(
renderClip
.
clipBehavior
,
equals
(
Clip
.
none
));
await
gesture
.
up
();
await
tester
.
pumpAndSettle
();
},
variant:
TargetPlatformVariant
.
only
(
TargetPlatform
.
android
));
testWidgets
(
'When `useInheritedMediaQuery` is true an existing MediaQuery is used if one is available'
,
(
WidgetTester
tester
)
async
{
late
BuildContext
capturedContext
;
final
UniqueKey
uniqueKey
=
UniqueKey
();
...
...
packages/flutter/test/widgets/overscroll_stretch_indicator_test.dart
View file @
8e8a1c8c
...
...
@@ -454,6 +454,70 @@ void main() {
await
tester
.
pumpAndSettle
();
});
testWidgets
(
'clipBehavior parameter updates overscroll clipping behavior'
,
(
WidgetTester
tester
)
async
{
// Regression test for https://github.com/flutter/flutter/issues/103491
Widget
buildFrame
(
Clip
clipBehavior
)
{
return
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
MediaQuery
(
data:
const
MediaQueryData
(
size:
Size
(
800.0
,
600.0
)),
child:
ScrollConfiguration
(
behavior:
const
ScrollBehavior
().
copyWith
(
overscroll:
false
),
child:
Column
(
children:
<
Widget
>[
StretchingOverscrollIndicator
(
axisDirection:
AxisDirection
.
down
,
clipBehavior:
clipBehavior
,
child:
SizedBox
(
height:
300
,
child:
ListView
.
builder
(
itemCount:
20
,
itemBuilder:
(
BuildContext
context
,
int
index
){
return
Padding
(
padding:
const
EdgeInsets
.
all
(
10.0
),
child:
Text
(
'Index
$index
'
),
);
},
),
),
),
Opacity
(
opacity:
0.5
,
child:
Container
(
color:
const
Color
(
0xD0FF0000
),
height:
100
,
),
),
],
),
),
),
);
}
await
tester
.
pumpWidget
(
buildFrame
(
Clip
.
none
));
expect
(
find
.
text
(
'Index 1'
),
findsOneWidget
);
expect
(
tester
.
getCenter
(
find
.
text
(
'Index 1'
)).
dy
,
51.0
);
RenderClipRect
renderClip
=
tester
.
allRenderObjects
.
whereType
<
RenderClipRect
>().
first
;
// Currently not clipping
expect
(
renderClip
.
clipBehavior
,
equals
(
Clip
.
none
));
final
TestGesture
gesture
=
await
tester
.
startGesture
(
tester
.
getCenter
(
find
.
text
(
'Index 1'
)));
// Overscroll the start.
await
gesture
.
moveBy
(
const
Offset
(
0.0
,
200.0
));
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'Index 1'
),
findsOneWidget
);
expect
(
tester
.
getCenter
(
find
.
text
(
'Index 1'
)).
dy
,
greaterThan
(
0
));
renderClip
=
tester
.
allRenderObjects
.
whereType
<
RenderClipRect
>().
first
;
// Now clipping
expect
(
renderClip
.
clipBehavior
,
equals
(
Clip
.
none
));
await
gesture
.
up
();
await
tester
.
pumpAndSettle
();
});
testWidgets
(
'Stretch limit'
,
(
WidgetTester
tester
)
async
{
// Regression test for https://github.com/flutter/flutter/issues/99264
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