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
362a5573
Unverified
Commit
362a5573
authored
May 14, 2020
by
Nicolas Schneider
Committed by
GitHub
May 14, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
allow changing the paint offset of a GlowingOverscrollIndicator (#55829)
parent
93d7af73
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
139 additions
and
2 deletions
+139
-2
AUTHORS
AUTHORS
+1
-0
overscroll_indicator.dart
packages/flutter/lib/src/widgets/overscroll_indicator.dart
+76
-2
overscroll_indicator_test.dart
packages/flutter/test/widgets/overscroll_indicator_test.dart
+62
-0
No files found.
AUTHORS
View file @
362a5573
...
...
@@ -54,4 +54,5 @@ Cédric Wyss <cedi.wyss@gmail.com>
Michel Feinstein <michel@feinstein.com.br>
Michael Lee <ckmichael8@gmail.com>
Katarina Sheremet <katarina@sheremet.ch>
Nicolas Schneider <nioncode+git@gmail.com>
Mikhail Zotyev <mbixjkee1392@gmail.com>
packages/flutter/lib/src/widgets/overscroll_indicator.dart
View file @
362a5573
...
...
@@ -33,14 +33,53 @@ import 'ticker_provider.dart';
///
/// In a [MaterialApp], the edge glow color is the [ThemeData.accentColor].
///
/// ## Customizing the Glow Position for Advanced Scroll Views
///
/// When building a [CustomScrollView] with a [GlowingOverscrollIndicator], the
/// indicator will apply to the entire scrollable area, regardless of what
/// slivers the CustomScrollView contains.
///
/// For example, if your CustomScrollView contains a SliverAppBar in the first
/// position, the GlowingOverscrollIndicator will overlay the SliverAppBar. To
/// manipulate the position of the GlowingOverscrollIndicator in this case, use
/// a [NestedScrollView].
/// manipulate the position of the GlowingOverscrollIndicator in this case,
/// you can either make use of a [NotificationListener] and provide a
/// [OverscrollIndicatorNotification.paintOffset] to the
/// notification, or use a [NestedScrollView].
///
/// {@tool dartpad --template=stateless_widget_scaffold}
///
/// This example demonstrates how to use a [NotificationListener] to manipulate
/// the placement of a [GlowingOverscrollIndicator] when building a
/// [CustomScrollView]. Drag the scrollable to see the bounds of the overscroll
/// indicator.
///
/// ```dart
/// Widget build(BuildContext context) {
/// double leadingPaintOffset = MediaQuery.of(context).padding.top + AppBar().preferredSize.height;
/// return NotificationListener<OverscrollIndicatorNotification>(
/// onNotification: (notification) {
/// if (notification.leading) {
/// notification.paintOffset = leadingPaintOffset;
/// }
/// return false;
/// },
/// child: CustomScrollView(
/// slivers: [
/// SliverAppBar(title: Text('Custom PaintOffset')),
/// SliverToBoxAdapter(
/// child: Container(
/// color: Colors.amberAccent,
/// height: 100,
/// child: Center(child: Text('Glow all day!')),
/// ),
/// ),
/// SliverFillRemaining(child: FlutterLogo()),
/// ],
/// ),
/// );
/// }
/// ```
/// {@end-tool}
///
/// {@tool dartpad --template=stateless_widget_scaffold}
///
...
...
@@ -73,6 +112,13 @@ import 'ticker_provider.dart';
/// }
/// ```
/// {@end-tool}
///
/// See also:
///
/// * [OverscrollIndicatorNotification], which can be used to manipulate the
/// glow position or prevent the glow from being painted at all
/// * [NotificationListener], to listen for the
/// [OverscrollIndicatorNotification]
class
GlowingOverscrollIndicator
extends
StatefulWidget
{
/// Creates a visual indication that a scroll view has overscrolled.
///
...
...
@@ -199,6 +245,16 @@ class _GlowingOverscrollIndicatorState extends State<GlowingOverscrollIndicator>
bool
_handleScrollNotification
(
ScrollNotification
notification
)
{
if
(!
widget
.
notificationPredicate
(
notification
))
return
false
;
// Update the paint offset with the current scroll position. This makes
// sure that the glow effect correctly scrolls in line with the current
// scroll, e.g. when scrolling in the opposite direction again to hide
// the glow. Otherwise, the glow would always stay in a fixed position,
// even if the top of the content already scrolled away.
_leadingController
.
_paintOffsetScrollPixels
=
-
notification
.
metrics
.
pixels
;
_trailingController
.
_paintOffsetScrollPixels
=
-(
notification
.
metrics
.
maxScrollExtent
-
notification
.
metrics
.
pixels
);
if
(
notification
is
OverscrollNotification
)
{
_GlowController
controller
;
if
(
notification
.
overscroll
<
0.0
)
{
...
...
@@ -213,6 +269,9 @@ class _GlowingOverscrollIndicatorState extends State<GlowingOverscrollIndicator>
final
OverscrollIndicatorNotification
confirmationNotification
=
OverscrollIndicatorNotification
(
leading:
isLeading
);
confirmationNotification
.
dispatch
(
context
);
_accepted
[
isLeading
]
=
confirmationNotification
.
_accepted
;
if
(
_accepted
[
isLeading
])
{
controller
.
_paintOffset
=
confirmationNotification
.
paintOffset
;
}
}
assert
(
controller
!=
null
);
assert
(
notification
.
metrics
.
axis
==
widget
.
axis
);
...
...
@@ -309,6 +368,8 @@ class _GlowController extends ChangeNotifier {
_GlowState
_state
=
_GlowState
.
idle
;
AnimationController
_glowController
;
Timer
_pullRecedeTimer
;
double
_paintOffset
=
0.0
;
double
_paintOffsetScrollPixels
=
0.0
;
// animation values
final
Tween
<
double
>
_glowOpacityTween
=
Tween
<
double
>(
begin:
0.0
,
end:
0.0
);
...
...
@@ -490,6 +551,7 @@ class _GlowController extends ChangeNotifier {
final
Offset
center
=
Offset
((
size
.
width
/
2.0
)
*
(
0.5
+
_displacement
),
height
-
radius
);
final
Paint
paint
=
Paint
()..
color
=
color
.
withOpacity
(
_glowOpacity
.
value
);
canvas
.
save
();
canvas
.
translate
(
0.0
,
_paintOffset
+
_paintOffsetScrollPixels
);
canvas
.
scale
(
1.0
,
scaleY
);
canvas
.
clipRect
(
rect
);
canvas
.
drawCircle
(
center
,
radius
,
paint
);
...
...
@@ -588,6 +650,18 @@ class OverscrollIndicatorNotification extends Notification with ViewportNotifica
/// view.
final
bool
leading
;
/// Controls at which offset the glow should be drawn.
///
/// A positive offset will move the glow away from its edge,
/// i.e. for a vertical, [leading] indicator, a [paintOffset] of 100.0 will
/// draw the indicator 100.0 pixels from the top of the edge.
/// For a vertical indicator with [leading] set to `false`, a [paintOffset]
/// of 100.0 will draw the indicator 100.0 pixels from the bottom instead.
///
/// A negative [paintOffset] is generally not useful, since the glow will be
/// clipped.
double
paintOffset
=
0.0
;
bool
_accepted
=
true
;
/// Call this method if the glow should be prevented.
...
...
packages/flutter/test/widgets/overscroll_indicator_test.dart
View file @
362a5573
...
...
@@ -320,6 +320,68 @@ void main() {
expect
(
painter
,
paints
..
rotate
(
angle:
math
.
pi
/
2.0
)..
circle
(
color:
const
Color
(
0x0A0000FF
))..
saveRestore
());
expect
(
painter
,
isNot
(
paints
..
circle
()..
circle
()));
});
group
(
'Modify glow position'
,
()
{
testWidgets
(
'Leading'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
NotificationListener
<
OverscrollIndicatorNotification
>(
onNotification:
(
OverscrollIndicatorNotification
notification
)
{
if
(
notification
.
leading
)
{
notification
.
paintOffset
=
50.0
;
}
return
false
;
},
child:
const
CustomScrollView
(
slivers:
<
Widget
>[
SliverToBoxAdapter
(
child:
SizedBox
(
height:
2000.0
)),
],
),
),
),
);
final
RenderObject
painter
=
tester
.
renderObject
(
find
.
byType
(
CustomPaint
));
await
slowDrag
(
tester
,
const
Offset
(
200.0
,
200.0
),
const
Offset
(
0.0
,
5.0
));
expect
(
painter
,
paints
..
save
()..
translate
(
y:
50.0
)..
scale
()..
circle
());
// Reverse scroll direction.
await
tester
.
dragFrom
(
const
Offset
(
200.0
,
200.0
),
const
Offset
(
0.0
,
-
30.0
));
await
tester
.
pump
();
// The painter should follow the scroll direction.
expect
(
painter
,
paints
..
save
()..
translate
(
y:
50.0
-
30.0
)..
scale
()..
circle
());
});
testWidgets
(
'Trailing'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
NotificationListener
<
OverscrollIndicatorNotification
>(
onNotification:
(
OverscrollIndicatorNotification
notification
)
{
if
(!
notification
.
leading
)
{
notification
.
paintOffset
=
50.0
;
}
return
false
;
},
child:
const
CustomScrollView
(
slivers:
<
Widget
>[
SliverToBoxAdapter
(
child:
SizedBox
(
height:
2000.0
)),
],
),
),
),
);
final
RenderObject
painter
=
tester
.
renderObject
(
find
.
byType
(
CustomPaint
));
await
tester
.
dragFrom
(
const
Offset
(
200.0
,
200.0
),
const
Offset
(
200.0
,
-
10000.0
));
await
tester
.
pump
();
await
slowDrag
(
tester
,
const
Offset
(
200.0
,
200.0
),
const
Offset
(
0.0
,
-
5.0
));
expect
(
painter
,
paints
..
scale
(
y:
-
1.0
)..
save
()..
translate
(
y:
50.0
)..
scale
()..
circle
());
// Reverse scroll direction.
await
tester
.
dragFrom
(
const
Offset
(
200.0
,
200.0
),
const
Offset
(
0.0
,
30.0
));
await
tester
.
pump
();
// The painter should follow the scroll direction.
expect
(
painter
,
paints
..
scale
(
y:
-
1.0
)..
save
()..
translate
(
y:
50.0
-
30.0
)..
scale
()..
circle
());
});
});
}
class
TestScrollBehavior1
extends
ScrollBehavior
{
...
...
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