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
e40610d6
Unverified
Commit
e40610d6
authored
Apr 02, 2021
by
Kate Lovett
Committed by
GitHub
Apr 02, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Automatically applying Scrollbars on desktop platforms with configurable ScrollBehaviors (#78588)
parent
b083bc14
Changes
27
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
27 changed files
with
725 additions
and
321 deletions
+725
-321
app.dart
packages/flutter/lib/src/cupertino/app.dart
+31
-3
app.dart
packages/flutter/lib/src/material/app.dart
+36
-5
dropdown.dart
packages/flutter/lib/src/material/dropdown.dart
+8
-16
editable_text.dart
packages/flutter/lib/src/widgets/editable_text.dart
+26
-0
list_wheel_scroll_view.dart
packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart
+21
-0
nested_scroll_view.dart
packages/flutter/lib/src/widgets/nested_scroll_view.dart
+28
-3
overscroll_indicator.dart
packages/flutter/lib/src/widgets/overscroll_indicator.dart
+2
-2
page_view.dart
packages/flutter/lib/src/widgets/page_view.dart
+22
-2
scroll_configuration.dart
packages/flutter/lib/src/widgets/scroll_configuration.dart
+149
-7
scroll_context.dart
packages/flutter/lib/src/widgets/scroll_context.dart
+1
-1
scroll_view.dart
packages/flutter/lib/src/widgets/scroll_view.dart
+17
-0
scrollable.dart
packages/flutter/lib/src/widgets/scrollable.dart
+96
-14
scrollbar.dart
packages/flutter/lib/src/widgets/scrollbar.dart
+18
-3
app_test.dart
packages/flutter/test/cupertino/app_test.dart
+3
-1
nav_bar_test.dart
packages/flutter/test/cupertino/nav_bar_test.dart
+0
-1
refresh_test.dart
packages/flutter/test/cupertino/refresh_test.dart
+64
-88
app_test.dart
packages/flutter/test/material/app_test.dart
+3
-1
scrollbar_test.dart
packages/flutter/test/material/scrollbar_test.dart
+55
-68
scrollbar_theme_test.dart
packages/flutter/test/material/scrollbar_theme_test.dart
+59
-42
viewport_test.dart
packages/flutter/test/rendering/viewport_test.dart
+21
-18
app_test.dart
packages/flutter/test/widgets/app_test.dart
+0
-5
draggable_scrollable_sheet_test.dart
...flutter/test/widgets/draggable_scrollable_sheet_test.dart
+29
-26
overscroll_indicator_test.dart
packages/flutter/test/widgets/overscroll_indicator_test.dart
+14
-10
range_maintaining_scroll_physics_test.dart
...r/test/widgets/range_maintaining_scroll_physics_test.dart
+6
-1
scrollable_test.dart
packages/flutter/test/widgets/scrollable_test.dart
+8
-0
slivers_evil_test.dart
packages/flutter/test/widgets/slivers_evil_test.dart
+5
-3
state_setting_in_scrollables_test.dart
...utter/test/widgets/state_setting_in_scrollables_test.dart
+3
-1
No files found.
packages/flutter/lib/src/cupertino/app.dart
View file @
e40610d6
...
...
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/foundation.dart'
;
import
'package:flutter/widgets.dart'
;
import
'button.dart'
;
...
...
@@ -10,6 +11,7 @@ import 'icons.dart';
import
'interface_level.dart'
;
import
'localizations.dart'
;
import
'route.dart'
;
import
'scrollbar.dart'
;
import
'theme.dart'
;
/// An application that uses Cupertino design.
...
...
@@ -422,14 +424,40 @@ class CupertinoApp extends StatefulWidget {
/// Setting a [CupertinoScrollBehavior] will result in descendant [Scrollable] widgets
/// using [BouncingScrollPhysics] by default. No [GlowingOverscrollIndicator] is
/// applied when using a [CupertinoScrollBehavior] either, regardless of platform.
/// When executing on desktop platforms, a [CupertinoScrollbar] is applied to the child.
///
/// See also:
///
/// * [ScrollBehavior], the default scrolling behavior extended by this class.
class
CupertinoScrollBehavior
extends
ScrollBehavior
{
/// Creates a CupertinoScrollBehavior that uses [BouncingScrollPhysics] and
/// adds [CupertinoScrollbar]s on desktop platforms.
const
CupertinoScrollBehavior
();
@override
Widget
buildScrollbar
(
BuildContext
context
,
Widget
child
,
ScrollableDetails
details
)
{
// When modifying this function, consider modifying the implementation in
// the base class as well.
switch
(
getPlatform
(
context
))
{
case
TargetPlatform
.
linux
:
case
TargetPlatform
.
macOS
:
case
TargetPlatform
.
windows
:
return
CupertinoScrollbar
(
child:
child
,
controller:
details
.
controller
,
);
case
TargetPlatform
.
android
:
case
TargetPlatform
.
fuchsia
:
case
TargetPlatform
.
iOS
:
return
child
;
}
}
@override
Widget
buildViewportChrome
(
BuildContext
context
,
Widget
child
,
AxisDirection
axisDirection
)
{
// Never build any overscroll glow indicators.
Widget
buildOverscrollIndicator
(
BuildContext
context
,
Widget
child
,
ScrollableDetails
details
)
{
// No overscroll indicator.
// When modifying this function, consider modifying the implementation in
// the base class as well.
return
child
;
}
...
...
@@ -544,7 +572,7 @@ class _CupertinoAppState extends State<CupertinoApp> {
final
CupertinoThemeData
effectiveThemeData
=
widget
.
theme
??
const
CupertinoThemeData
();
return
ScrollConfiguration
(
behavior:
widget
.
scrollBehavior
??
CupertinoScrollBehavior
(),
behavior:
widget
.
scrollBehavior
??
const
CupertinoScrollBehavior
(),
child:
CupertinoUserInterfaceLevel
(
data:
CupertinoUserInterfaceLevelData
.
base
,
child:
CupertinoTheme
(
...
...
packages/flutter/lib/src/material/app.dart
View file @
e40610d6
...
...
@@ -14,6 +14,7 @@ import 'icons.dart';
import
'material_localizations.dart'
;
import
'page.dart'
;
import
'scaffold.dart'
show
ScaffoldMessenger
,
ScaffoldMessengerState
;
import
'scrollbar.dart'
;
import
'theme.dart'
;
/// [MaterialApp] uses this [TextStyle] as its [DefaultTextStyle] to encourage
...
...
@@ -684,17 +685,47 @@ class MaterialApp extends StatefulWidget {
/// [GlowingOverscrollIndicator] to [Scrollable] descendants when executing on
/// [TargetPlatform.android] and [TargetPlatform.fuchsia].
///
/// When using the desktop platform, if the [Scrollable] widget scrolls in the
/// [Axis.vertical], a [Scrollbar] is applied.
///
/// See also:
///
/// * [ScrollBehavior], the default scrolling behavior extended by this class.
class
MaterialScrollBehavior
extends
ScrollBehavior
{
/// Creates a MaterialScrollBehavior that decorates [Scrollable]s with
/// [GlowingOverscrollIndicator]s and [Scrollbar]s based on the current
/// platform and provided [ScrollableDetails].
const
MaterialScrollBehavior
();
@override
TargetPlatform
getPlatform
(
BuildContext
context
)
=>
Theme
.
of
(
context
).
platform
;
@override
TargetPlatform
getPlatform
(
BuildContext
context
)
{
return
Theme
.
of
(
context
).
platform
;
Widget
buildScrollbar
(
BuildContext
context
,
Widget
child
,
ScrollableDetails
details
)
{
// When modifying this function, consider modifying the implementation in
// the base class as well.
switch
(
axisDirectionToAxis
(
details
.
direction
))
{
case
Axis
.
horizontal
:
return
child
;
case
Axis
.
vertical
:
switch
(
getPlatform
(
context
))
{
case
TargetPlatform
.
linux
:
case
TargetPlatform
.
macOS
:
case
TargetPlatform
.
windows
:
return
Scrollbar
(
child:
child
,
controller:
details
.
controller
,
);
case
TargetPlatform
.
android
:
case
TargetPlatform
.
fuchsia
:
case
TargetPlatform
.
iOS
:
return
child
;
}
}
}
@override
Widget
build
ViewportChrome
(
BuildContext
context
,
Widget
child
,
AxisDirection
axisDirection
)
{
Widget
build
OverscrollIndicator
(
BuildContext
context
,
Widget
child
,
ScrollableDetails
details
)
{
// When modifying this function, consider modifying the implementation in
// the base class as well.
switch
(
getPlatform
(
context
))
{
...
...
@@ -707,7 +738,7 @@ class MaterialScrollBehavior extends ScrollBehavior {
case
TargetPlatform
.
fuchsia
:
return
GlowingOverscrollIndicator
(
child:
child
,
axisDirection:
axisD
irection
,
axisDirection:
details
.
d
irection
,
color:
Theme
.
of
(
context
).
colorScheme
.
secondary
,
);
}
...
...
@@ -880,7 +911,7 @@ class _MaterialAppState extends State<MaterialApp> {
}());
return
ScrollConfiguration
(
behavior:
widget
.
scrollBehavior
??
MaterialScrollBehavior
(),
behavior:
widget
.
scrollBehavior
??
const
MaterialScrollBehavior
(),
child:
HeroControllerScope
(
controller:
_heroController
,
child:
result
,
...
...
packages/flutter/lib/src/material/dropdown.dart
View file @
e40610d6
...
...
@@ -88,21 +88,6 @@ class _DropdownMenuPainter extends CustomPainter {
}
}
// Do not use the platform-specific default scroll configuration.
// Dropdown menus should never overscroll or display an overscroll indicator.
class
_DropdownScrollBehavior
extends
ScrollBehavior
{
const
_DropdownScrollBehavior
();
@override
TargetPlatform
getPlatform
(
BuildContext
context
)
=>
Theme
.
of
(
context
).
platform
;
@override
Widget
buildViewportChrome
(
BuildContext
context
,
Widget
child
,
AxisDirection
axisDirection
)
=>
child
;
@override
ScrollPhysics
getScrollPhysics
(
BuildContext
context
)
=>
const
ClampingScrollPhysics
();
}
// The widget that is the button wrapping the menu items.
class
_DropdownMenuItemButton
<
T
>
extends
StatefulWidget
{
const
_DropdownMenuItemButton
({
...
...
@@ -289,7 +274,14 @@ class _DropdownMenuState<T> extends State<_DropdownMenu<T>> {
type:
MaterialType
.
transparency
,
textStyle:
route
.
style
,
child:
ScrollConfiguration
(
behavior:
const
_DropdownScrollBehavior
(),
// Dropdown menus should never overscroll or display an overscroll indicator.
// The default scrollbar platforms will apply.
// Platform must use Theme and ScrollPhysics must be Clamping.
behavior:
ScrollConfiguration
.
of
(
context
).
copyWith
(
overscroll:
false
,
physics:
const
ClampingScrollPhysics
(),
platform:
Theme
.
of
(
context
).
platform
,
),
child:
PrimaryScrollController
(
controller:
widget
.
route
.
scrollController
!,
child:
Scrollbar
(
...
...
packages/flutter/lib/src/widgets/editable_text.dart
View file @
e40610d6
...
...
@@ -23,6 +23,7 @@ import 'focus_scope.dart';
import
'framework.dart'
;
import
'localizations.dart'
;
import
'media_query.dart'
;
import
'scroll_configuration.dart'
;
import
'scroll_controller.dart'
;
import
'scroll_physics.dart'
;
import
'scrollable.dart'
;
...
...
@@ -493,6 +494,7 @@ class EditableText extends StatefulWidget {
this
.
autofillHints
,
this
.
clipBehavior
=
Clip
.
hardEdge
,
this
.
restorationId
,
this
.
scrollBehavior
,
})
:
assert
(
controller
!=
null
),
assert
(
focusNode
!=
null
),
assert
(
obscuringCharacter
!=
null
&&
obscuringCharacter
.
length
==
1
),
...
...
@@ -1201,6 +1203,10 @@ class EditableText extends StatefulWidget {
///
/// See [Scrollable.physics].
/// {@endtemplate}
///
/// If an explicit [ScrollBehavior] is provided to [scrollBehavior], the
/// [ScrollPhysics] provided by that behavior will take precedence after
/// [scrollPhysics].
final
ScrollPhysics
?
scrollPhysics
;
/// {@template flutter.widgets.editableText.selectionEnabled}
...
...
@@ -1305,6 +1311,23 @@ class EditableText extends StatefulWidget {
/// Flutter.
final
String
?
restorationId
;
/// {@template flutter.widgets.shadow.scrollBehavior}
/// A [ScrollBehavior] that will be applied to this widget individually.
///
/// Defaults to null, wherein the inherited [ScrollBehavior] is copied and
/// modified to alter the viewport decoration, like [Scrollbar]s.
/// {@endtemplate}
///
/// [ScrollBehavior]s also provide [ScrollPhysics]. If an explicit
/// [ScrollPhysics] is provided in [scrollPhysics], it will take precedence,
/// followed by [scrollBehavior], and then the inherited ancestor
/// [ScrollBehavior].
///
/// The [ScrollBehavior] of the inherited [ScrollConfiguration] will be
/// modified by default to only apply a [Scrollbar] if [maxLines] is greater
/// than 1.
final
ScrollBehavior
?
scrollBehavior
;
// Infer the keyboard type of an `EditableText` if it's not specified.
static
TextInputType
_inferKeyboardType
({
required
Iterable
<
String
>?
autofillHints
,
...
...
@@ -2609,6 +2632,9 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
physics:
widget
.
scrollPhysics
,
dragStartBehavior:
widget
.
dragStartBehavior
,
restorationId:
widget
.
restorationId
,
scrollBehavior:
widget
.
scrollBehavior
??
// Remove scrollbars if only single line
(
_isMultiline
?
null
:
ScrollConfiguration
.
of
(
context
).
copyWith
(
scrollbars:
false
)),
viewportBuilder:
(
BuildContext
context
,
ViewportOffset
offset
)
{
return
CompositedTransformTarget
(
link:
_toolbarLayerLink
,
...
...
packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart
View file @
e40610d6
...
...
@@ -12,6 +12,7 @@ import 'package:flutter/scheduler.dart';
import
'basic.dart'
;
import
'framework.dart'
;
import
'notification_listener.dart'
;
import
'scroll_configuration.dart'
;
import
'scroll_context.dart'
;
import
'scroll_controller.dart'
;
import
'scroll_metrics.dart'
;
...
...
@@ -431,6 +432,7 @@ class _FixedExtentScrollable extends Scrollable {
required
this
.
itemExtent
,
required
ViewportBuilder
viewportBuilder
,
String
?
restorationId
,
ScrollBehavior
?
scrollBehavior
,
})
:
super
(
key:
key
,
axisDirection:
axisDirection
,
...
...
@@ -438,6 +440,7 @@ class _FixedExtentScrollable extends Scrollable {
physics:
physics
,
viewportBuilder:
viewportBuilder
,
restorationId:
restorationId
,
scrollBehavior:
scrollBehavior
,
);
final
double
itemExtent
;
...
...
@@ -584,6 +587,7 @@ class ListWheelScrollView extends StatefulWidget {
this
.
renderChildrenOutsideViewport
=
false
,
this
.
clipBehavior
=
Clip
.
hardEdge
,
this
.
restorationId
,
this
.
scrollBehavior
,
required
List
<
Widget
>
children
,
})
:
assert
(
children
!=
null
),
assert
(
diameterRatio
!=
null
),
...
...
@@ -625,6 +629,7 @@ class ListWheelScrollView extends StatefulWidget {
this
.
renderChildrenOutsideViewport
=
false
,
this
.
clipBehavior
=
Clip
.
hardEdge
,
this
.
restorationId
,
this
.
scrollBehavior
,
required
this
.
childDelegate
,
})
:
assert
(
childDelegate
!=
null
),
assert
(
diameterRatio
!=
null
),
...
...
@@ -669,6 +674,10 @@ class ListWheelScrollView extends StatefulWidget {
/// For example, determines how the scroll view continues to animate after the
/// user stops dragging the scroll view.
///
/// If an explicit [ScrollBehavior] is provided to [scrollBehavior], the
/// [ScrollPhysics] provided by that behavior will take precedence after
/// [physics].
///
/// Defaults to matching platform conventions.
final
ScrollPhysics
?
physics
;
...
...
@@ -716,6 +725,17 @@ class ListWheelScrollView extends StatefulWidget {
/// {@macro flutter.widgets.scrollable.restorationId}
final
String
?
restorationId
;
/// {@macro flutter.widgets.shadow.scrollBehavior}
///
/// [ScrollBehavior]s also provide [ScrollPhysics]. If an explicit
/// [ScrollPhysics] is provided in [physics], it will take precedence,
/// followed by [scrollBehavior], and then the inherited ancestor
/// [ScrollBehavior].
///
/// The [ScrollBehavior] of the inherited [ScrollConfiguration] will be
/// modified by default to not apply a [Scrollbar].
final
ScrollBehavior
?
scrollBehavior
;
@override
_ListWheelScrollViewState
createState
()
=>
_ListWheelScrollViewState
();
}
...
...
@@ -769,6 +789,7 @@ class _ListWheelScrollViewState extends State<ListWheelScrollView> {
physics:
widget
.
physics
,
itemExtent:
widget
.
itemExtent
,
restorationId:
widget
.
restorationId
,
scrollBehavior:
widget
.
scrollBehavior
??
ScrollConfiguration
.
of
(
context
).
copyWith
(
scrollbars:
false
),
viewportBuilder:
(
BuildContext
context
,
ViewportOffset
offset
)
{
return
ListWheelViewport
(
diameterRatio:
widget
.
diameterRatio
,
...
...
packages/flutter/lib/src/widgets/nested_scroll_view.dart
View file @
e40610d6
...
...
@@ -13,6 +13,7 @@ import 'basic.dart';
import
'framework.dart'
;
import
'primary_scroll_controller.dart'
;
import
'scroll_activity.dart'
;
import
'scroll_configuration.dart'
;
import
'scroll_context.dart'
;
import
'scroll_controller.dart'
;
import
'scroll_metrics.dart'
;
...
...
@@ -369,6 +370,7 @@ class NestedScrollView extends StatefulWidget {
this
.
floatHeaderSlivers
=
false
,
this
.
clipBehavior
=
Clip
.
hardEdge
,
this
.
restorationId
,
this
.
scrollBehavior
,
})
:
assert
(
scrollDirection
!=
null
),
assert
(
reverse
!=
null
),
assert
(
headerSliverBuilder
!=
null
),
...
...
@@ -407,6 +409,10 @@ class NestedScrollView extends StatefulWidget {
/// [ScrollPhysics.createBallisticSimulation] allows this particular aspect of
/// the physics to be overridden).
///
/// If an explicit [ScrollBehavior] is provided to [scrollBehavior], the
/// [ScrollPhysics] provided by that behavior will take precedence after
/// [physics].
///
/// Defaults to matching platform conventions.
///
/// The [ScrollPhysics.applyBoundaryConditions] implementation of the provided
...
...
@@ -453,6 +459,20 @@ class NestedScrollView extends StatefulWidget {
/// {@macro flutter.widgets.scrollable.restorationId}
final
String
?
restorationId
;
/// {@macro flutter.widgets.shadow.scrollBehavior}
///
/// [ScrollBehavior]s also provide [ScrollPhysics]. If an explicit
/// [ScrollPhysics] is provided in [physics], it will take precedence,
/// followed by [scrollBehavior], and then the inherited ancestor
/// [ScrollBehavior].
///
/// The [ScrollBehavior] of the inherited [ScrollConfiguration] will be
/// modified by default to not apply a [Scrollbar]. This is because the
/// NestedScrollView cannot assume the configuration of the outer and inner
/// [Scrollable] widgets, particularly whether to treat them as one scrollable,
/// or separate and desirous of unique behaviors.
final
ScrollBehavior
?
scrollBehavior
;
/// Returns the [SliverOverlapAbsorberHandle] of the nearest ancestor
/// [NestedScrollView].
///
...
...
@@ -613,6 +633,10 @@ class NestedScrollViewState extends State<NestedScrollView> {
@override
Widget
build
(
BuildContext
context
)
{
final
ScrollPhysics
_scrollPhysics
=
widget
.
physics
?.
applyTo
(
const
ClampingScrollPhysics
())
??
widget
.
scrollBehavior
?.
getScrollPhysics
(
context
).
applyTo
(
const
ClampingScrollPhysics
())
??
const
ClampingScrollPhysics
();
return
_InheritedNestedScrollView
(
state:
this
,
child:
Builder
(
...
...
@@ -622,9 +646,8 @@ class NestedScrollViewState extends State<NestedScrollView> {
dragStartBehavior:
widget
.
dragStartBehavior
,
scrollDirection:
widget
.
scrollDirection
,
reverse:
widget
.
reverse
,
physics:
widget
.
physics
!=
null
?
widget
.
physics
!.
applyTo
(
const
ClampingScrollPhysics
())
:
const
ClampingScrollPhysics
(),
physics:
_scrollPhysics
,
scrollBehavior:
widget
.
scrollBehavior
??
ScrollConfiguration
.
of
(
context
).
copyWith
(
scrollbars:
false
),
controller:
_coordinator
!.
_outerController
,
slivers:
widget
.
_buildSlivers
(
context
,
...
...
@@ -646,6 +669,7 @@ class _NestedScrollViewCustomScrollView extends CustomScrollView {
required
Axis
scrollDirection
,
required
bool
reverse
,
required
ScrollPhysics
physics
,
required
ScrollBehavior
scrollBehavior
,
required
ScrollController
controller
,
required
List
<
Widget
>
slivers
,
required
this
.
handle
,
...
...
@@ -656,6 +680,7 @@ class _NestedScrollViewCustomScrollView extends CustomScrollView {
scrollDirection:
scrollDirection
,
reverse:
reverse
,
physics:
physics
,
scrollBehavior:
scrollBehavior
,
controller:
controller
,
slivers:
slivers
,
dragStartBehavior:
dragStartBehavior
,
...
...
packages/flutter/lib/src/widgets/overscroll_indicator.dart
View file @
e40610d6
...
...
@@ -27,7 +27,7 @@ import 'ticker_provider.dart';
/// showing the indication, call [OverscrollIndicatorNotification.disallowGlow]
/// on the notification.
///
/// Created automatically by [ScrollBehavior.build
ViewportChrome
] on platforms
/// Created automatically by [ScrollBehavior.build
OverscrollIndicator
] on platforms
/// (e.g., Android) that commonly use this type of overscroll indication.
///
/// In a [MaterialApp], the edge glow color is the overall theme's
...
...
@@ -189,7 +189,7 @@ class GlowingOverscrollIndicator extends StatefulWidget {
/// subtree) should include a source of [ScrollNotification] notifications.
///
/// Typically a [GlowingOverscrollIndicator] is created by a
/// [ScrollBehavior.build
ViewportChrome
] method, in which case
/// [ScrollBehavior.build
OverscrollIndicator
] method, in which case
/// the child is usually the one provided as an argument to that method.
final
Widget
?
child
;
...
...
packages/flutter/lib/src/widgets/page_view.dart
View file @
e40610d6
...
...
@@ -13,6 +13,7 @@ import 'debug.dart';
import
'framework.dart'
;
import
'notification_listener.dart'
;
import
'page_storage.dart'
;
import
'scroll_configuration.dart'
;
import
'scroll_context.dart'
;
import
'scroll_controller.dart'
;
import
'scroll_metrics.dart'
;
...
...
@@ -635,6 +636,7 @@ class PageView extends StatefulWidget {
this
.
allowImplicitScrolling
=
false
,
this
.
restorationId
,
this
.
clipBehavior
=
Clip
.
hardEdge
,
this
.
scrollBehavior
,
})
:
assert
(
allowImplicitScrolling
!=
null
),
assert
(
clipBehavior
!=
null
),
controller
=
controller
??
_defaultPageController
,
...
...
@@ -673,6 +675,7 @@ class PageView extends StatefulWidget {
this
.
allowImplicitScrolling
=
false
,
this
.
restorationId
,
this
.
clipBehavior
=
Clip
.
hardEdge
,
this
.
scrollBehavior
,
})
:
assert
(
allowImplicitScrolling
!=
null
),
assert
(
clipBehavior
!=
null
),
controller
=
controller
??
_defaultPageController
,
...
...
@@ -776,6 +779,7 @@ class PageView extends StatefulWidget {
this
.
allowImplicitScrolling
=
false
,
this
.
restorationId
,
this
.
clipBehavior
=
Clip
.
hardEdge
,
this
.
scrollBehavior
,
})
:
assert
(
childrenDelegate
!=
null
),
assert
(
allowImplicitScrolling
!=
null
),
assert
(
clipBehavior
!=
null
),
...
...
@@ -829,6 +833,10 @@ class PageView extends StatefulWidget {
/// The physics are modified to snap to page boundaries using
/// [PageScrollPhysics] prior to being used.
///
/// If an explicit [ScrollBehavior] is provided to [scrollBehavior], the
/// [ScrollPhysics] provided by that behavior will take precedence after
/// [physics].
///
/// Defaults to matching platform conventions.
final
ScrollPhysics
?
physics
;
...
...
@@ -854,6 +862,17 @@ class PageView extends StatefulWidget {
/// Defaults to [Clip.hardEdge].
final
Clip
clipBehavior
;
/// {@macro flutter.widgets.shadow.scrollBehavior}
///
/// [ScrollBehavior]s also provide [ScrollPhysics]. If an explicit
/// [ScrollPhysics] is provided in [physics], it will take precedence,
/// followed by [scrollBehavior], and then the inherited ancestor
/// [ScrollBehavior].
///
/// The [ScrollBehavior] of the inherited [ScrollConfiguration] will be
/// modified by default to not apply a [Scrollbar].
final
ScrollBehavior
?
scrollBehavior
;
@override
_PageViewState
createState
()
=>
_PageViewState
();
}
...
...
@@ -885,8 +904,8 @@ class _PageViewState extends State<PageView> {
final
ScrollPhysics
physics
=
_ForceImplicitScrollPhysics
(
allowImplicitScrolling:
widget
.
allowImplicitScrolling
,
).
applyTo
(
widget
.
pageSnapping
?
_kPagePhysics
.
applyTo
(
widget
.
physics
)
:
widget
.
physics
);
?
_kPagePhysics
.
applyTo
(
widget
.
physics
??
widget
.
scrollBehavior
?.
getScrollPhysics
(
context
)
)
:
widget
.
physics
??
widget
.
scrollBehavior
?.
getScrollPhysics
(
context
)
);
return
NotificationListener
<
ScrollNotification
>(
onNotification:
(
ScrollNotification
notification
)
{
...
...
@@ -906,6 +925,7 @@ class _PageViewState extends State<PageView> {
controller:
widget
.
controller
,
physics:
physics
,
restorationId:
widget
.
restorationId
,
scrollBehavior:
widget
.
scrollBehavior
??
ScrollConfiguration
.
of
(
context
).
copyWith
(
scrollbars:
false
),
viewportBuilder:
(
BuildContext
context
,
ViewportOffset
position
)
{
return
Viewport
(
// TODO(dnfield): we should provide a way to set cacheExtent
...
...
packages/flutter/lib/src/widgets/scroll_configuration.dart
View file @
e40610d6
...
...
@@ -9,6 +9,8 @@ import 'package:flutter/rendering.dart';
import
'framework.dart'
;
import
'overscroll_indicator.dart'
;
import
'scroll_physics.dart'
;
import
'scrollable.dart'
;
import
'scrollbar.dart'
;
const
Color
_kDefaultGlowColor
=
Color
(
0xFFFFFFFF
);
...
...
@@ -21,8 +23,13 @@ const Color _kDefaultGlowColor = Color(0xFFFFFFFF);
/// This class can be extended to further customize a [ScrollBehavior] for a
/// subtree. For example, overriding [ScrollBehavior.getScrollPhysics] sets the
/// default [ScrollPhysics] for [Scrollable]s that inherit this [ScrollConfiguration].
/// Overriding [ScrollBehavior.buildViewportChrome] can be used to add or change
/// default decorations like [GlowingOverscrollIndicator]s.
/// Overriding [ScrollBehavior.buildOverscrollIndicator] can be used to add or change
/// the default [GlowingOverscrollIndicator] decoration, while
/// [ScrollBehavior.buildScrollbar] can be changed to modify the default [Scrollbar].
///
/// When looking to easily toggle the default decorations, you can use
/// [ScrollBehavior.copyWith] instead of creating your own [ScrollBehavior] class.
/// The `scrollbar` and `overscrollIndicator` flags can turn these decorations off.
/// {@endtemplate}
///
/// See also:
...
...
@@ -34,6 +41,29 @@ class ScrollBehavior {
/// Creates a description of how [Scrollable] widgets should behave.
const
ScrollBehavior
();
/// Creates a copy of this ScrollBehavior, making it possible to
/// easily toggle `scrollbar` and `overscrollIndicator` effects.
///
/// This is used by widgets like [PageView] and [ListWheelScrollView] to
/// override the current [ScrollBehavior] and manage how they are decorated.
/// Widgets such as these have the option to provide a [ScrollBehavior] on
/// the widget level, like [PageView.scrollBehavior], in order to change the
/// default.
ScrollBehavior
copyWith
({
bool
scrollbars
=
true
,
bool
overscroll
=
true
,
ScrollPhysics
?
physics
,
TargetPlatform
?
platform
,
})
{
return
_WrappedScrollBehavior
(
delegate:
this
,
scrollbar:
scrollbars
,
overscrollIndicator:
overscroll
,
physics:
physics
,
platform:
platform
,
);
}
/// The platform whose scroll physics should be implemented.
///
/// Defaults to the current platform.
...
...
@@ -44,9 +74,14 @@ class ScrollBehavior {
/// For example, on Android, this method wraps the given widget with a
/// [GlowingOverscrollIndicator] to provide visual feedback when the user
/// overscrolls.
///
/// This method is deprecated. Use [ScrollBehavior.buildOverscrollIndicator]
/// instead.
@Deprecated
(
'Migrate to buildOverscrollIndicator. '
'This feature was deprecated after v2.1.0-11.0.pre.'
)
Widget
buildViewportChrome
(
BuildContext
context
,
Widget
child
,
AxisDirection
axisDirection
)
{
// When modifying this function, consider modifying the implementation in
// MaterialScrollBehavior as well.
switch
(
getPlatform
(
context
))
{
case
TargetPlatform
.
iOS
:
case
TargetPlatform
.
linux
:
...
...
@@ -55,14 +90,43 @@ class ScrollBehavior {
return
child
;
case
TargetPlatform
.
android
:
case
TargetPlatform
.
fuchsia
:
return
GlowingOverscrollIndicator
(
return
GlowingOverscrollIndicator
(
child:
child
,
axisDirection:
axisDirection
,
color:
_kDefaultGlowColor
,
);
}
}
/// Applies a [RawScrollbar] to the child widget on desktop platforms.
Widget
buildScrollbar
(
BuildContext
context
,
Widget
child
,
ScrollableDetails
details
)
{
// When modifying this function, consider modifying the implementation in
// the Material and Cupertino subclasses as well.
switch
(
getPlatform
(
context
))
{
case
TargetPlatform
.
linux
:
case
TargetPlatform
.
macOS
:
case
TargetPlatform
.
windows
:
return
RawScrollbar
(
child:
child
,
axisDirection:
axisDirection
,
color:
_kDefaultGlowColor
,
controller:
details
.
controller
,
);
case
TargetPlatform
.
android
:
case
TargetPlatform
.
fuchsia
:
case
TargetPlatform
.
iOS
:
return
child
;
}
}
/// Applies a [GlowingOverscrollIndicator] to the child widget on
/// [TargetPlatform.android] and [TargetPlatform.fuchsia].
Widget
buildOverscrollIndicator
(
BuildContext
context
,
Widget
child
,
ScrollableDetails
details
)
{
// TODO(Piinks): Move implementation from buildViewportChrome here after
// deprecation period
// When modifying this function, consider modifying the implementation in
// the Material and Cupertino subclasses as well.
return
buildViewportChrome
(
context
,
child
,
details
.
direction
);
}
/// Specifies the type of velocity tracker to use in the descendant
/// [Scrollable]s' drag gesture recognizers, for estimating the velocity of a
/// drag gesture.
...
...
@@ -129,6 +193,84 @@ class ScrollBehavior {
String
toString
()
=>
objectRuntimeType
(
this
,
'ScrollBehavior'
);
}
class
_WrappedScrollBehavior
implements
ScrollBehavior
{
const
_WrappedScrollBehavior
({
required
this
.
delegate
,
this
.
scrollbar
=
true
,
this
.
overscrollIndicator
=
true
,
this
.
physics
,
this
.
platform
,
});
final
ScrollBehavior
delegate
;
final
bool
scrollbar
;
final
bool
overscrollIndicator
;
final
ScrollPhysics
?
physics
;
final
TargetPlatform
?
platform
;
@override
Widget
buildOverscrollIndicator
(
BuildContext
context
,
Widget
child
,
ScrollableDetails
details
)
{
if
(
overscrollIndicator
)
return
delegate
.
buildOverscrollIndicator
(
context
,
child
,
details
);
return
child
;
}
@override
Widget
buildScrollbar
(
BuildContext
context
,
Widget
child
,
ScrollableDetails
details
)
{
if
(
scrollbar
)
return
delegate
.
buildScrollbar
(
context
,
child
,
details
);
return
child
;
}
@override
Widget
buildViewportChrome
(
BuildContext
context
,
Widget
child
,
AxisDirection
axisDirection
)
{
return
delegate
.
buildViewportChrome
(
context
,
child
,
axisDirection
);
}
@override
ScrollBehavior
copyWith
({
bool
scrollbars
=
true
,
bool
overscroll
=
true
,
ScrollPhysics
?
physics
,
TargetPlatform
?
platform
,
})
{
return
delegate
.
copyWith
(
scrollbars:
scrollbars
,
overscroll:
overscroll
,
physics:
physics
,
platform:
platform
,
);
}
@override
TargetPlatform
getPlatform
(
BuildContext
context
)
{
return
platform
??
delegate
.
getPlatform
(
context
);
}
@override
ScrollPhysics
getScrollPhysics
(
BuildContext
context
)
{
return
physics
??
delegate
.
getScrollPhysics
(
context
);
}
@override
bool
shouldNotify
(
_WrappedScrollBehavior
oldDelegate
)
{
return
oldDelegate
.
delegate
.
runtimeType
!=
delegate
.
runtimeType
||
oldDelegate
.
scrollbar
!=
scrollbar
||
oldDelegate
.
overscrollIndicator
!=
overscrollIndicator
||
oldDelegate
.
physics
!=
physics
||
oldDelegate
.
platform
!=
platform
||
delegate
.
shouldNotify
(
oldDelegate
.
delegate
);
}
@override
GestureVelocityTrackerBuilder
velocityTrackerBuilder
(
BuildContext
context
)
{
return
delegate
.
velocityTrackerBuilder
(
context
);
}
@override
String
toString
()
=>
objectRuntimeType
(
this
,
'_WrappedScrollBehavior'
);
}
/// Controls how [Scrollable] widgets behave in a subtree.
///
/// The scroll configuration determines the [ScrollPhysics] and viewport
...
...
packages/flutter/lib/src/widgets/scroll_context.dart
View file @
e40610d6
...
...
@@ -24,7 +24,7 @@ abstract class ScrollContext {
/// This context is typically different that the context of the scrollable
/// widget itself. For example, [Scrollable] uses a context outside the
/// [Viewport] but inside the widgets created by
/// [ScrollBehavior.build
ViewportChrome
].
/// [ScrollBehavior.build
OverscrollIndicator] and [ScrollBehavior.buildScrollbar
].
BuildContext
?
get
notificationContext
;
/// The [BuildContext] that should be used when searching for a [PageStorage].
...
...
packages/flutter/lib/src/widgets/scroll_view.dart
View file @
e40610d6
...
...
@@ -15,6 +15,7 @@ import 'framework.dart';
import
'media_query.dart'
;
import
'notification_listener.dart'
;
import
'primary_scroll_controller.dart'
;
import
'scroll_configuration.dart'
;
import
'scroll_controller.dart'
;
import
'scroll_notification.dart'
;
import
'scroll_physics.dart'
;
...
...
@@ -83,6 +84,7 @@ abstract class ScrollView extends StatelessWidget {
this
.
controller
,
bool
?
primary
,
ScrollPhysics
?
physics
,
this
.
scrollBehavior
,
this
.
shrinkWrap
=
false
,
this
.
center
,
this
.
anchor
=
0.0
,
...
...
@@ -205,8 +207,20 @@ abstract class ScrollView extends StatelessWidget {
/// inefficient to speculatively create this object each frame to see if the
/// physics should be updated.)
/// {@endtemplate}
///
/// If an explicit [ScrollBehavior] is provided to [scrollBehavior], the
/// [ScrollPhysics] provided by that behavior will take precedence after
/// [physics].
final
ScrollPhysics
?
physics
;
/// {@macro flutter.widgets.shadow.scrollBehavior}
///
/// [ScrollBehavior]s also provide [ScrollPhysics]. If an explicit
/// [ScrollPhysics] is provided in [physics], it will take precedence,
/// followed by [scrollBehavior], and then the inherited ancestor
/// [ScrollBehavior].
final
ScrollBehavior
?
scrollBehavior
;
/// {@template flutter.widgets.scroll_view.shrinkWrap}
/// Whether the extent of the scroll view in the [scrollDirection] should be
/// determined by the contents being viewed.
...
...
@@ -380,6 +394,7 @@ abstract class ScrollView extends StatelessWidget {
axisDirection:
axisDirection
,
controller:
scrollController
,
physics:
physics
,
scrollBehavior:
scrollBehavior
,
semanticChildCount:
semanticChildCount
,
restorationId:
restorationId
,
viewportBuilder:
(
BuildContext
context
,
ViewportOffset
offset
)
{
...
...
@@ -610,6 +625,7 @@ class CustomScrollView extends ScrollView {
ScrollController
?
controller
,
bool
?
primary
,
ScrollPhysics
?
physics
,
ScrollBehavior
?
scrollBehavior
,
bool
shrinkWrap
=
false
,
Key
?
center
,
double
anchor
=
0.0
,
...
...
@@ -627,6 +643,7 @@ class CustomScrollView extends ScrollView {
controller:
controller
,
primary:
primary
,
physics:
physics
,
scrollBehavior:
scrollBehavior
,
shrinkWrap:
shrinkWrap
,
center:
center
,
anchor:
anchor
,
...
...
packages/flutter/lib/src/widgets/scrollable.dart
View file @
e40610d6
...
...
@@ -25,7 +25,6 @@ import 'scroll_controller.dart';
import
'scroll_metrics.dart'
;
import
'scroll_physics.dart'
;
import
'scroll_position.dart'
;
import
'scroll_position_with_single_context.dart'
;
import
'ticker_provider.dart'
;
import
'viewport.dart'
;
...
...
@@ -91,6 +90,7 @@ class Scrollable extends StatefulWidget {
this
.
semanticChildCount
,
this
.
dragStartBehavior
=
DragStartBehavior
.
start
,
this
.
restorationId
,
this
.
scrollBehavior
,
})
:
assert
(
axisDirection
!=
null
),
assert
(
dragStartBehavior
!=
null
),
assert
(
viewportBuilder
!=
null
),
...
...
@@ -135,6 +135,10 @@ class Scrollable extends StatefulWidget {
/// Defaults to matching platform conventions via the physics provided from
/// the ambient [ScrollConfiguration].
///
/// If an explicit [ScrollBehavior] is provided to [scrollBehavior], the
/// [ScrollPhysics] provided by that behavior will take precedence after
/// [physics].
///
/// The physics can be changed dynamically, but new physics will only take
/// effect if the _class_ of the provided object changes. Merely constructing
/// a new instance with a different configuration is insufficient to cause the
...
...
@@ -243,6 +247,14 @@ class Scrollable extends StatefulWidget {
/// {@endtemplate}
final
String
?
restorationId
;
/// {@macro flutter.widgets.shadow.scrollBehavior}
///
/// [ScrollBehavior]s also provide [ScrollPhysics]. If an explicit
/// [ScrollPhysics] is provided in [physics], it will take precedence,
/// followed by [scrollBehavior], and then the inherited ancestor
/// [ScrollBehavior].
final
ScrollBehavior
?
scrollBehavior
;
/// The axis along which the scroll view scrolls.
///
/// Determined by the [axisDirection].
...
...
@@ -385,27 +397,31 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin, R
late
ScrollBehavior
_configuration
;
ScrollPhysics
?
_physics
;
ScrollController
?
_fallbackScrollController
;
ScrollController
get
_effectiveScrollController
=>
widget
.
controller
??
_fallbackScrollController
!;
// Only call this from places that will definitely trigger a rebuild.
void
_updatePosition
()
{
_configuration
=
ScrollConfiguration
.
of
(
context
);
_configuration
=
widget
.
scrollBehavior
??
ScrollConfiguration
.
of
(
context
);
_physics
=
_configuration
.
getScrollPhysics
(
context
);
if
(
widget
.
physics
!=
null
)
if
(
widget
.
physics
!=
null
)
{
_physics
=
widget
.
physics
!.
applyTo
(
_physics
);
final
ScrollController
?
controller
=
widget
.
controller
;
}
else
if
(
widget
.
scrollBehavior
!=
null
)
{
_physics
=
widget
.
scrollBehavior
!.
getScrollPhysics
(
context
).
applyTo
(
_physics
);
}
final
ScrollPosition
?
oldPosition
=
_position
;
if
(
oldPosition
!=
null
)
{
controller
?
.
detach
(
oldPosition
);
_effectiveScrollController
.
detach
(
oldPosition
);
// It's important that we not dispose the old position until after the
// viewport has had a chance to unregister its listeners from the old
// position. So, schedule a microtask to do it.
scheduleMicrotask
(
oldPosition
.
dispose
);
}
_position
=
controller
?.
createScrollPosition
(
_physics
!,
this
,
oldPosition
)
??
ScrollPositionWithSingleContext
(
physics:
_physics
!,
context:
this
,
oldPosition:
oldPosition
);
_position
=
_effectiveScrollController
.
createScrollPosition
(
_physics
!,
this
,
oldPosition
);
assert
(
_position
!=
null
);
controller
?
.
attach
(
position
);
_effectiveScrollController
.
attach
(
position
);
}
@override
...
...
@@ -426,6 +442,13 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin, R
ServicesBinding
.
instance
!.
restorationManager
.
flushData
();
}
@override
void
initState
()
{
if
(
widget
.
controller
==
null
)
_fallbackScrollController
=
ScrollController
();
super
.
initState
();
}
@override
void
didChangeDependencies
()
{
_updatePosition
();
...
...
@@ -433,8 +456,8 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin, R
}
bool
_shouldUpdatePosition
(
Scrollable
oldWidget
)
{
ScrollPhysics
?
newPhysics
=
widget
.
physics
;
ScrollPhysics
?
oldPhysics
=
oldWidget
.
physics
;
ScrollPhysics
?
newPhysics
=
widget
.
physics
??
widget
.
scrollBehavior
?.
getScrollPhysics
(
context
)
;
ScrollPhysics
?
oldPhysics
=
oldWidget
.
physics
??
oldWidget
.
scrollBehavior
?.
getScrollPhysics
(
context
)
;
do
{
if
(
newPhysics
?.
runtimeType
!=
oldPhysics
?.
runtimeType
)
return
true
;
...
...
@@ -450,8 +473,25 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin, R
super
.
didUpdateWidget
(
oldWidget
);
if
(
widget
.
controller
!=
oldWidget
.
controller
)
{
oldWidget
.
controller
?.
detach
(
position
);
widget
.
controller
?.
attach
(
position
);
if
(
oldWidget
.
controller
==
null
)
{
// The old controller was null, meaning the fallback cannot be null.
// Dispose of the fallback.
assert
(
_fallbackScrollController
!=
null
);
assert
(
widget
.
controller
!=
null
);
_fallbackScrollController
!.
detach
(
position
);
_fallbackScrollController
!.
dispose
();
_fallbackScrollController
=
null
;
}
else
{
// The old controller was not null, detach.
oldWidget
.
controller
?.
detach
(
position
);
if
(
widget
.
controller
==
null
)
{
// If the new controller is null, we need to set up the fallback
// ScrollController.
_fallbackScrollController
=
ScrollController
();
}
}
// Attach the updated effective scroll controller.
_effectiveScrollController
.
attach
(
position
);
}
if
(
_shouldUpdatePosition
(
oldWidget
))
...
...
@@ -460,7 +500,13 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin, R
@override
void
dispose
()
{
widget
.
controller
?.
detach
(
position
);
if
(
widget
.
controller
!=
null
)
{
widget
.
controller
!.
detach
(
position
);
}
else
{
_fallbackScrollController
?.
detach
(
position
);
_fallbackScrollController
?.
dispose
();
}
position
.
dispose
();
_persistedScrollOffset
.
dispose
();
super
.
dispose
();
...
...
@@ -717,7 +763,16 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin, R
);
}
return
_configuration
.
buildViewportChrome
(
context
,
result
,
widget
.
axisDirection
);
final
ScrollableDetails
details
=
ScrollableDetails
(
direction:
widget
.
axisDirection
,
controller:
_effectiveScrollController
,
);
return
_configuration
.
buildScrollbar
(
context
,
_configuration
.
buildOverscrollIndicator
(
context
,
result
,
details
),
details
,
);
}
@override
...
...
@@ -731,6 +786,33 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin, R
String
?
get
restorationId
=>
widget
.
restorationId
;
}
/// Describes the aspects of a Scrollable widget to inform inherited widgets
/// like [ScrollBehavior] for decorating.
///
/// Decorations like [GlowingOverscrollIndicator]s and [Scrollbar]s require
/// information about the Scrollable in order to be initialized.
@immutable
class
ScrollableDetails
{
/// Creates a set of details describing the [Scrollable]. The [direction]
/// cannot be null.
const
ScrollableDetails
({
required
this
.
direction
,
required
this
.
controller
,
});
/// The direction in which this widget scrolls.
///
/// Cannot be null.
final
AxisDirection
direction
;
/// A [ScrollController] that can be used to control the position of the
/// [Scrollable] widget.
///
/// This can be used by [ScrollBehavior] to apply a [Scrollbar] to the associated
/// [Scrollable].
final
ScrollController
controller
;
}
/// With [_ScrollSemantics] certain child [SemanticsNode]s can be
/// excluded from the scrollable area for semantics purposes.
///
...
...
packages/flutter/lib/src/widgets/scrollbar.dart
View file @
e40610d6
...
...
@@ -584,7 +584,8 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter {
///
/// If the scrollbar is wrapped around multiple [ScrollView]s, it only responds to
/// the nearest scrollView and shows the corresponding scrollbar thumb by default.
/// Set [notificationPredicate] to something else for more complicated behaviors.
/// The [notificationPredicate] allows the ability to customize which
/// [ScrollNotification]s the Scrollbar should listen to.
///
/// Scrollbars are interactive and will also use the [PrimaryScrollController] if
/// a [controller] is not set. Scrollbar thumbs can be dragged along the main axis
...
...
@@ -596,6 +597,17 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter {
/// painted. In this case, the scrollbar cannot accurately represent the
/// relative location of the visible area, or calculate the accurate delta to
/// apply when dragging on the thumb or tapping on the track.
///
/// Scrollbars are added to most [Scrollable] widgets by default on Desktop
/// platforms in [ScrollBehavior.buildScrollbar] as part of an app's
/// [ScrollConfiguration]. Scrollable widgets that do not have automatically
/// applied Scrollbars include
///
/// * [EditableText]
/// * [ListWheelScrollView]
/// * [PageView]
/// * [NestedScrollView]
/// * [DropdownButton]
/// {@endtemplate}
///
// TODO(Piinks): Add code sample
...
...
@@ -615,8 +627,8 @@ class RawScrollbar extends StatefulWidget {
/// The [child], or a descendant of the [child], should be a source of
/// [ScrollNotification] notifications, typically a [Scrollable] widget.
///
/// The [child], [
thickness], [thumbColor], [isAlwaysShown], [fadeDuration],
///
and [timeToFade] arguments
must not be null.
/// The [child], [
fadeDuration], [pressDuration], and [timeToFade] arguments
/// must not be null.
const
RawScrollbar
({
Key
?
key
,
required
this
.
child
,
...
...
@@ -641,6 +653,9 @@ class RawScrollbar extends StatefulWidget {
///
/// The scrollbar will be stacked on top of this child. This child (and its
/// subtree) should include a source of [ScrollNotification] notifications.
/// Typically a [Scrollbar] is created on desktop platforms by a
/// [ScrollBehavior.buildScrollbar] method, in which case the child is usually
/// the one provided as an argument to that method.
///
/// Typically a [ListView] or [CustomScrollView].
/// {@endtemplate}
...
...
packages/flutter/test/cupertino/app_test.dart
View file @
e40610d6
...
...
@@ -198,7 +198,7 @@ void main() {
late
BuildContext
capturedContext
;
await
tester
.
pumpWidget
(
CupertinoApp
(
scrollBehavior:
MockScrollBehavior
(),
scrollBehavior:
const
MockScrollBehavior
(),
home:
Builder
(
builder:
(
BuildContext
context
)
{
capturedContext
=
context
;
...
...
@@ -214,6 +214,8 @@ void main() {
}
class
MockScrollBehavior
extends
ScrollBehavior
{
const
MockScrollBehavior
();
@override
ScrollPhysics
getScrollPhysics
(
BuildContext
context
)
=>
const
NeverScrollableScrollPhysics
();
}
...
...
packages/flutter/test/cupertino/nav_bar_test.dart
View file @
e40610d6
...
...
@@ -956,7 +956,6 @@ void main() {
},
);
testWidgets
(
'NavBar draws a light system bar for a dark background'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
WidgetsApp
(
...
...
packages/flutter/test/cupertino/refresh_test.dart
View file @
e40610d6
This diff is collapsed.
Click to expand it.
packages/flutter/test/material/app_test.dart
View file @
e40610d6
...
...
@@ -1046,7 +1046,7 @@ void main() {
late
BuildContext
capturedContext
;
await
tester
.
pumpWidget
(
MaterialApp
(
scrollBehavior:
MockScrollBehavior
(),
scrollBehavior:
const
MockScrollBehavior
(),
home:
Builder
(
builder:
(
BuildContext
context
)
{
capturedContext
=
context
;
...
...
@@ -1062,6 +1062,8 @@ void main() {
}
class
MockScrollBehavior
extends
ScrollBehavior
{
const
MockScrollBehavior
();
@override
ScrollPhysics
getScrollPhysics
(
BuildContext
context
)
=>
const
NeverScrollableScrollPhysics
();
}
...
...
packages/flutter/test/material/scrollbar_test.dart
View file @
e40610d6
...
...
@@ -49,11 +49,21 @@ Widget _buildBoilerplate({
textDirection:
textDirection
,
child:
MediaQuery
(
data:
MediaQueryData
(
padding:
padding
),
child:
child
,
child:
ScrollConfiguration
(
behavior:
const
NoScrollbarBehavior
(),
child:
child
,
),
),
);
}
class
NoScrollbarBehavior
extends
MaterialScrollBehavior
{
const
NoScrollbarBehavior
();
@override
Widget
buildScrollbar
(
BuildContext
context
,
Widget
child
,
ScrollableDetails
details
)
=>
child
;
}
void
main
(
)
{
testWidgets
(
"Scrollbar doesn't show when tapping list"
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
...
...
@@ -809,18 +819,11 @@ void main() {
});
testWidgets
(
'Scrollbar thumb color completes a hover animation'
,
(
WidgetTester
tester
)
async
{
final
ScrollController
scrollController
=
ScrollController
();
await
tester
.
pumpWidget
(
MaterialApp
(
home:
PrimaryScrollController
(
controller:
scrollController
,
child:
Scrollbar
(
isAlwaysShown:
true
,
controller:
scrollController
,
child:
const
SingleChildScrollView
(
child:
SizedBox
(
width:
4000.0
,
height:
4000.0
)
),
),
theme:
ThemeData
(
scrollbarTheme:
const
ScrollbarThemeData
(
isAlwaysShown:
true
)),
home:
const
SingleChildScrollView
(
child:
SizedBox
(
width:
4000.0
,
height:
4000.0
)
),
),
);
...
...
@@ -858,24 +861,18 @@ void main() {
TargetPlatform
.
linux
,
TargetPlatform
.
macOS
,
TargetPlatform
.
windows
,
TargetPlatform
.
fuchsia
,
}),
);
testWidgets
(
'Hover animation is not triggered by tap gestures'
,
(
WidgetTester
tester
)
async
{
final
ScrollController
scrollController
=
ScrollController
();
await
tester
.
pumpWidget
(
MaterialApp
(
home:
PrimaryScrollController
(
controller:
scrollController
,
child:
Scrollbar
(
isAlwaysShown:
true
,
showTrackOnHover:
true
,
controller:
scrollController
,
child:
const
SingleChildScrollView
(
child:
SizedBox
(
width:
4000.0
,
height:
4000.0
)
),
),
theme:
ThemeData
(
scrollbarTheme:
const
ScrollbarThemeData
(
isAlwaysShown:
true
,
showTrackOnHover:
true
,
)),
home:
const
SingleChildScrollView
(
child:
SizedBox
(
width:
4000.0
,
height:
4000.0
)
),
),
);
...
...
@@ -936,27 +933,19 @@ void main() {
color:
const
Color
(
0x80000000
),
),
);
},
variant:
const
TargetPlatformVariant
(<
TargetPlatform
>{
TargetPlatform
.
linux
,
}),
variant:
const
TargetPlatformVariant
(<
TargetPlatform
>{
TargetPlatform
.
linux
}),
);
testWidgets
(
'Scrollbar showTrackOnHover'
,
(
WidgetTester
tester
)
async
{
final
ScrollController
scrollController
=
ScrollController
();
await
tester
.
pumpWidget
(
MaterialApp
(
home:
PrimaryScrollController
(
controller:
scrollController
,
child:
Scrollbar
(
isAlwaysShown:
true
,
showTrackOnHover:
true
,
controller:
scrollController
,
child:
const
SingleChildScrollView
(
child:
SizedBox
(
width:
4000.0
,
height:
4000.0
)
),
),
theme:
ThemeData
(
scrollbarTheme:
const
ScrollbarThemeData
(
isAlwaysShown:
true
,
showTrackOnHover:
true
,
)),
home:
const
SingleChildScrollView
(
child:
SizedBox
(
width:
4000.0
,
height:
4000.0
)
),
),
);
...
...
@@ -1006,7 +995,6 @@ void main() {
TargetPlatform
.
linux
,
TargetPlatform
.
macOS
,
TargetPlatform
.
windows
,
TargetPlatform
.
fuchsia
,
}),
);
...
...
@@ -1088,33 +1076,36 @@ void main() {
textDirection:
TextDirection
.
ltr
,
child:
MediaQuery
(
data:
const
MediaQueryData
(),
child:
Scrollbar
(
key:
key2
,
notificationPredicate:
null
,
child:
SingleChildScrollView
(
key:
outerKey
,
child:
SizedBox
(
height:
1000.0
,
width:
double
.
infinity
,
child:
Column
(
children:
<
Widget
>[
Scrollbar
(
key:
key1
,
notificationPredicate:
null
,
child:
SizedBox
(
height:
300.0
,
width:
double
.
infinity
,
child:
SingleChildScrollView
(
key:
innerKey
,
child:
const
SizedBox
(
key:
Key
(
'Inner scrollable'
),
height:
1000.0
,
width:
double
.
infinity
,
child:
ScrollConfiguration
(
behavior:
const
NoScrollbarBehavior
(),
child:
Scrollbar
(
key:
key2
,
notificationPredicate:
null
,
child:
SingleChildScrollView
(
key:
outerKey
,
child:
SizedBox
(
height:
1000.0
,
width:
double
.
infinity
,
child:
Column
(
children:
<
Widget
>[
Scrollbar
(
key:
key1
,
notificationPredicate:
null
,
child:
SizedBox
(
height:
300.0
,
width:
double
.
infinity
,
child:
SingleChildScrollView
(
key:
innerKey
,
child:
const
SizedBox
(
key:
Key
(
'Inner scrollable'
),
height:
1000.0
,
width:
double
.
infinity
,
),
),
),
),
)
,
]
,
]
,
)
,
),
),
),
...
...
@@ -1206,11 +1197,7 @@ void main() {
await
tester
.
pumpAndSettle
();
// The offset should not have changed.
expect
(
scrollController
.
offset
,
scrollAmount
);
},
variant:
const
TargetPlatformVariant
(<
TargetPlatform
>{
TargetPlatform
.
linux
,
TargetPlatform
.
windows
,
TargetPlatform
.
fuchsia
,
}));
},
variant:
const
TargetPlatformVariant
(<
TargetPlatform
>{
TargetPlatform
.
fuchsia
}));
testWidgets
(
'Scrollbar dragging is disabled by default on Android'
,
(
WidgetTester
tester
)
async
{
final
ScrollController
scrollController
=
ScrollController
();
...
...
packages/flutter/test/material/scrollbar_theme_test.dart
View file @
e40610d6
...
...
@@ -29,13 +29,16 @@ void main() {
final
ScrollController
scrollController
=
ScrollController
();
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Scroll
bar
(
isAlwaysShown:
true
,
showTrackOnHover:
true
,
controller:
scrollController
,
child:
SingleChildScrollView
(
home:
Scroll
Configuration
(
behavior:
const
NoScrollbarBehavior
()
,
child:
Scrollbar
(
isAlwaysShown:
true
,
showTrackOnHover:
true
,
controller:
scrollController
,
child:
const
SizedBox
(
width:
4000.0
,
height:
4000.0
)
child:
SingleChildScrollView
(
controller:
scrollController
,
child:
const
SizedBox
(
width:
4000.0
,
height:
4000.0
)
),
),
),
),
...
...
@@ -117,13 +120,18 @@ void main() {
final
ScrollbarThemeData
scrollbarTheme
=
_scrollbarTheme
();
final
ScrollController
scrollController
=
ScrollController
();
await
tester
.
pumpWidget
(
MaterialApp
(
theme:
ThemeData
(
scrollbarTheme:
scrollbarTheme
),
home:
Scrollbar
(
isAlwaysShown:
true
,
controller:
scrollController
,
child:
SingleChildScrollView
(
theme:
ThemeData
(
scrollbarTheme:
scrollbarTheme
,
),
home:
ScrollConfiguration
(
behavior:
const
NoScrollbarBehavior
(),
child:
Scrollbar
(
isAlwaysShown:
true
,
controller:
scrollController
,
child:
const
SizedBox
(
width:
4000.0
,
height:
4000.0
)
child:
SingleChildScrollView
(
controller:
scrollController
,
child:
const
SizedBox
(
width:
4000.0
,
height:
4000.0
)
),
),
),
));
...
...
@@ -245,12 +253,7 @@ void main() {
color:
_kDefaultIdleThumbColor
,
),
);
},
variant:
const
TargetPlatformVariant
(<
TargetPlatform
>{
TargetPlatform
.
linux
,
TargetPlatform
.
macOS
,
TargetPlatform
.
windows
,
TargetPlatform
.
fuchsia
,
}));
},
variant:
const
TargetPlatformVariant
(<
TargetPlatform
>{
TargetPlatform
.
fuchsia
}));
testWidgets
(
'Scrollbar.interactive takes priority over ScrollbarTheme'
,
(
WidgetTester
tester
)
async
{
final
ScrollController
scrollController
=
ScrollController
();
...
...
@@ -298,12 +301,7 @@ void main() {
color:
_kDefaultIdleThumbColor
,
),
);
},
variant:
const
TargetPlatformVariant
(<
TargetPlatform
>{
TargetPlatform
.
linux
,
TargetPlatform
.
macOS
,
TargetPlatform
.
windows
,
TargetPlatform
.
fuchsia
,
}));
},
variant:
const
TargetPlatformVariant
(<
TargetPlatform
>{
TargetPlatform
.
fuchsia
}));
testWidgets
(
'Scrollbar widget properties take priority over theme'
,
(
WidgetTester
tester
)
async
{
const
double
thickness
=
4.0
;
...
...
@@ -314,17 +312,22 @@ void main() {
await
tester
.
pumpWidget
(
MaterialApp
(
theme:
ThemeData
.
from
(
colorScheme:
const
ColorScheme
.
light
()),
home:
Scrollbar
(
thickness:
thickness
,
hoverThickness:
hoverThickness
,
isAlwaysShown:
true
,
showTrackOnHover:
showTrackOnHover
,
radius:
radius
,
controller:
scrollController
,
child:
SingleChildScrollView
(
theme:
ThemeData
(
colorScheme:
const
ColorScheme
.
light
(),
),
home:
ScrollConfiguration
(
behavior:
const
NoScrollbarBehavior
(),
child:
Scrollbar
(
thickness:
thickness
,
hoverThickness:
hoverThickness
,
isAlwaysShown:
true
,
showTrackOnHover:
showTrackOnHover
,
radius:
radius
,
controller:
scrollController
,
child:
const
SizedBox
(
width:
4000.0
,
height:
4000.0
)
child:
SingleChildScrollView
(
controller:
scrollController
,
child:
const
SizedBox
(
width:
4000.0
,
height:
4000.0
)
),
),
),
),
...
...
@@ -408,13 +411,16 @@ void main() {
final
ScrollController
scrollController
=
ScrollController
();
return
MaterialApp
(
theme:
appTheme
,
home:
Scroll
bar
(
isAlwaysShown:
true
,
showTrackOnHover:
true
,
controller:
scrollController
,
child:
SingleChildScrollView
(
home:
Scroll
Configuration
(
behavior:
const
NoScrollbarBehavior
()
,
child:
Scrollbar
(
isAlwaysShown:
true
,
showTrackOnHover:
true
,
controller:
scrollController
,
child:
const
SizedBox
(
width:
4000.0
,
height:
4000.0
)
child:
SingleChildScrollView
(
controller:
scrollController
,
child:
const
SizedBox
(
width:
4000.0
,
height:
4000.0
)
),
),
)
);
...
...
@@ -422,7 +428,9 @@ void main() {
// Scrollbar defaults for light themes:
// - coloring based on ColorScheme.onSurface
await
tester
.
pumpWidget
(
buildFrame
(
ThemeData
.
from
(
colorScheme:
const
ColorScheme
.
light
())));
await
tester
.
pumpWidget
(
buildFrame
(
ThemeData
(
colorScheme:
const
ColorScheme
.
light
(),
)));
await
tester
.
pumpAndSettle
();
// Idle scrollbar behavior
expect
(
...
...
@@ -493,7 +501,9 @@ void main() {
// Scrollbar defaults for dark themes:
// - coloring slightly different based on ColorScheme.onSurface
await
tester
.
pumpWidget
(
buildFrame
(
ThemeData
.
from
(
colorScheme:
const
ColorScheme
.
dark
())));
await
tester
.
pumpWidget
(
buildFrame
(
ThemeData
(
colorScheme:
const
ColorScheme
.
dark
(),
)));
await
tester
.
pumpAndSettle
();
// Theme change animation
// Idle scrollbar behavior
...
...
@@ -617,6 +627,13 @@ void main() {
},
skip:
kIsWeb
);
}
class
NoScrollbarBehavior
extends
ScrollBehavior
{
const
NoScrollbarBehavior
();
@override
Widget
buildScrollbar
(
BuildContext
context
,
Widget
child
,
ScrollableDetails
details
)
=>
child
;
}
ScrollbarThemeData
_scrollbarTheme
(
{
MaterialStateProperty
<
double
?>?
thickness
,
bool
showTrackOnHover
=
true
,
...
...
packages/flutter/test/rendering/viewport_test.dart
View file @
e40610d6
...
...
@@ -1788,24 +1788,27 @@ void main() {
await
tester
.
pumpWidget
(
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
<
Widget
>[
GridView
(
shrinkWrap:
true
,
gridDelegate:
const
SliverGridDelegateWithFixedCrossAxisCount
(
crossAxisCount:
3
,
childAspectRatio:
3
,
mainAxisSpacing:
3
,
crossAxisSpacing:
3
),
children:
const
<
Widget
>[
Text
(
'a'
),
Text
(
'b'
),
Text
(
'c'
),
],
),
],
child:
MediaQuery
(
data:
const
MediaQueryData
(),
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
<
Widget
>[
GridView
(
shrinkWrap:
true
,
gridDelegate:
const
SliverGridDelegateWithFixedCrossAxisCount
(
crossAxisCount:
3
,
childAspectRatio:
3
,
mainAxisSpacing:
3
,
crossAxisSpacing:
3
),
children:
const
<
Widget
>[
Text
(
'a'
),
Text
(
'b'
),
Text
(
'c'
),
],
),
],
),
),
),
);
...
...
packages/flutter/test/widgets/app_test.dart
View file @
e40610d6
...
...
@@ -327,11 +327,6 @@ void main() {
});
}
class
MockScrollBehavior
extends
ScrollBehavior
{
@override
ScrollPhysics
getScrollPhysics
(
BuildContext
context
)
=>
const
NeverScrollableScrollPhysics
();
}
typedef
SimpleRouterDelegateBuilder
=
Widget
Function
(
BuildContext
,
RouteInformation
);
typedef
SimpleNavigatorRouterDelegatePopPage
<
T
>
=
bool
Function
(
Route
<
T
>
route
,
T
result
,
SimpleNavigatorRouterDelegate
delegate
);
...
...
packages/flutter/test/widgets/draggable_scrollable_sheet_test.dart
View file @
e40610d6
...
...
@@ -18,33 +18,36 @@ void main() {
})
{
return
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
Stack
(
children:
<
Widget
>[
TextButton
(
child:
const
Text
(
'TapHere'
),
onPressed:
onButtonPressed
,
),
DraggableScrollableSheet
(
maxChildSize:
maxChildSize
,
minChildSize:
minChildSize
,
initialChildSize:
initialChildSize
,
builder:
(
BuildContext
context
,
ScrollController
scrollController
)
{
return
NotificationListener
<
ScrollNotification
>(
onNotification:
onScrollNotification
,
child:
Container
(
key:
containerKey
,
color:
const
Color
(
0xFFABCDEF
),
child:
ListView
.
builder
(
controller:
scrollController
,
itemExtent:
itemExtent
,
itemCount:
itemCount
,
itemBuilder:
(
BuildContext
context
,
int
index
)
=>
Text
(
'Item
$index
'
),
child:
MediaQuery
(
data:
const
MediaQueryData
(),
child:
Stack
(
children:
<
Widget
>[
TextButton
(
child:
const
Text
(
'TapHere'
),
onPressed:
onButtonPressed
,
),
DraggableScrollableSheet
(
maxChildSize:
maxChildSize
,
minChildSize:
minChildSize
,
initialChildSize:
initialChildSize
,
builder:
(
BuildContext
context
,
ScrollController
scrollController
)
{
return
NotificationListener
<
ScrollNotification
>(
onNotification:
onScrollNotification
,
child:
Container
(
key:
containerKey
,
color:
const
Color
(
0xFFABCDEF
),
child:
ListView
.
builder
(
controller:
scrollController
,
itemExtent:
itemExtent
,
itemCount:
itemCount
,
itemBuilder:
(
BuildContext
context
,
int
index
)
=>
Text
(
'Item
$index
'
),
),
),
)
,
);
}
,
)
,
]
,
)
;
},
)
,
]
,
)
,
),
);
}
...
...
packages/flutter/test/widgets/overscroll_indicator_test.dart
View file @
e40610d6
...
...
@@ -278,11 +278,11 @@ void main() {
RenderObject
painter
;
await
tester
.
pumpWidget
(
Directionality
(
const
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
ScrollConfiguration
(
behavior:
TestScrollBehavior1
(),
child:
const
CustomScrollView
(
child:
CustomScrollView
(
scrollDirection:
Axis
.
horizontal
,
physics:
AlwaysScrollableScrollPhysics
(),
reverse:
true
,
...
...
@@ -300,11 +300,11 @@ void main() {
await
tester
.
pumpAndSettle
(
const
Duration
(
seconds:
1
));
await
tester
.
pumpWidget
(
Directionality
(
const
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
ScrollConfiguration
(
behavior:
TestScrollBehavior2
(),
child:
const
CustomScrollView
(
child:
CustomScrollView
(
scrollDirection:
Axis
.
horizontal
,
physics:
AlwaysScrollableScrollPhysics
(),
slivers:
<
Widget
>[
...
...
@@ -326,7 +326,7 @@ void main() {
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
ScrollConfiguration
(
behavior:
TestScrollBehavior2
(),
behavior:
const
TestScrollBehavior2
(),
child:
CustomScrollView
(
center:
centerKey
,
physics:
const
AlwaysScrollableScrollPhysics
(),
...
...
@@ -365,7 +365,7 @@ void main() {
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
ScrollConfiguration
(
behavior:
TestScrollBehavior2
(),
behavior:
const
TestScrollBehavior2
(),
child:
NotificationListener
<
OverscrollIndicatorNotification
>(
onNotification:
(
OverscrollIndicatorNotification
notification
)
{
if
(
notification
.
leading
)
{
...
...
@@ -534,22 +534,26 @@ void main() {
}
class
TestScrollBehavior1
extends
ScrollBehavior
{
const
TestScrollBehavior1
();
@override
Widget
build
ViewportChrome
(
BuildContext
context
,
Widget
child
,
AxisDirection
axisDirection
)
{
Widget
build
OverscrollIndicator
(
BuildContext
context
,
Widget
child
,
ScrollableDetails
details
)
{
return
GlowingOverscrollIndicator
(
child:
child
,
axisDirection:
axisD
irection
,
axisDirection:
details
.
d
irection
,
color:
const
Color
(
0xFF00FF00
),
);
}
}
class
TestScrollBehavior2
extends
ScrollBehavior
{
const
TestScrollBehavior2
();
@override
Widget
build
ViewportChrome
(
BuildContext
context
,
Widget
child
,
AxisDirection
axisDirection
)
{
Widget
build
OverscrollIndicator
(
BuildContext
context
,
Widget
child
,
ScrollableDetails
details
)
{
return
GlowingOverscrollIndicator
(
child:
child
,
axisDirection:
axisD
irection
,
axisDirection:
details
.
d
irection
,
color:
const
Color
(
0xFF0000FF
),
);
}
...
...
packages/flutter/test/widgets/range_maintaining_scroll_physics_test.dart
View file @
e40610d6
...
...
@@ -304,7 +304,12 @@ class RangeMaintainingTestScrollBehavior extends ScrollBehavior {
TargetPlatform
getPlatform
(
BuildContext
context
)
=>
throw
'should not be called'
;
@override
Widget
buildViewportChrome
(
BuildContext
context
,
Widget
child
,
AxisDirection
axisDirection
)
{
Widget
buildOverscrollIndicator
(
BuildContext
context
,
Widget
child
,
ScrollableDetails
details
)
{
return
child
;
}
@override
Widget
buildScrollbar
(
BuildContext
context
,
Widget
child
,
ScrollableDetails
details
)
{
return
child
;
}
...
...
packages/flutter/test/widgets/scrollable_test.dart
View file @
e40610d6
...
...
@@ -19,6 +19,7 @@ Future<void> pumpTest(
ScrollController
?
controller
,
})
async
{
await
tester
.
pumpWidget
(
MaterialApp
(
scrollBehavior:
const
NoScrollbarBehavior
(),
theme:
ThemeData
(
platform:
platform
,
),
...
...
@@ -34,6 +35,13 @@ Future<void> pumpTest(
await
tester
.
pump
(
const
Duration
(
seconds:
5
));
// to let the theme animate
}
class
NoScrollbarBehavior
extends
MaterialScrollBehavior
{
const
NoScrollbarBehavior
();
@override
Widget
buildScrollbar
(
BuildContext
context
,
Widget
child
,
ScrollableDetails
details
)
=>
child
;
}
// Pump a nested scrollable. The outer scrollable contains a sliver of a
// 300-pixel-long scrollable followed by a 2000-pixel-long content.
Future
<
void
>
pumpDoubleScrollableTest
(
...
...
packages/flutter/test/widgets/slivers_evil_test.dart
View file @
e40610d6
...
...
@@ -32,11 +32,13 @@ class TestSliverPersistentHeaderDelegate extends SliverPersistentHeaderDelegate
}
class
TestBehavior
extends
ScrollBehavior
{
const
TestBehavior
();
@override
Widget
build
ViewportChrome
(
BuildContext
context
,
Widget
child
,
AxisDirection
axisDirection
)
{
Widget
build
OverscrollIndicator
(
BuildContext
context
,
Widget
child
,
ScrollableDetails
details
)
{
return
GlowingOverscrollIndicator
(
child:
child
,
axisDirection:
axisD
irection
,
axisDirection:
details
.
d
irection
,
color:
const
Color
(
0xFFFFFFFF
),
);
}
...
...
@@ -78,7 +80,7 @@ void main() {
child:
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
ScrollConfiguration
(
behavior:
TestBehavior
(),
behavior:
const
TestBehavior
(),
child:
Scrollbar
(
child:
Scrollable
(
axisDirection:
AxisDirection
.
down
,
...
...
packages/flutter/test/widgets/state_setting_in_scrollables_test.dart
View file @
e40610d6
...
...
@@ -19,7 +19,7 @@ class FooState extends State<Foo> {
return
LayoutBuilder
(
builder:
(
BuildContext
context
,
BoxConstraints
constraints
)
{
return
ScrollConfiguration
(
behavior:
FooScrollBehavior
(),
behavior:
const
FooScrollBehavior
(),
child:
ListView
(
controller:
scrollController
,
children:
<
Widget
>[
...
...
@@ -74,6 +74,8 @@ class FooState extends State<Foo> {
}
class
FooScrollBehavior
extends
ScrollBehavior
{
const
FooScrollBehavior
();
@override
bool
shouldNotify
(
FooScrollBehavior
old
)
=>
true
;
}
...
...
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