Exposing ScrollBehaviors for app-wide settings (#76739)
This commit is contained in:
parent
aee756ff1e
commit
38fd5af5f1
@ -168,6 +168,7 @@ class CupertinoApp extends StatefulWidget {
|
||||
this.shortcuts,
|
||||
this.actions,
|
||||
this.restorationScopeId,
|
||||
this.scrollBehavior,
|
||||
}) : assert(routes != null),
|
||||
assert(navigatorObservers != null),
|
||||
assert(title != null),
|
||||
@ -207,6 +208,7 @@ class CupertinoApp extends StatefulWidget {
|
||||
this.shortcuts,
|
||||
this.actions,
|
||||
this.restorationScopeId,
|
||||
this.scrollBehavior,
|
||||
}) : assert(title != null),
|
||||
assert(showPerformanceOverlay != null),
|
||||
assert(checkerboardRasterCacheImages != null),
|
||||
@ -393,6 +395,16 @@ class CupertinoApp extends StatefulWidget {
|
||||
/// {@macro flutter.widgets.widgetsApp.restorationScopeId}
|
||||
final String? restorationScopeId;
|
||||
|
||||
/// {@macro flutter.material.materialApp.scrollBehavior}
|
||||
///
|
||||
/// When null, defaults to [CupertinoScrollBehavior].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [ScrollConfiguration], which controls how [Scrollable] widgets behave
|
||||
/// in a subtree.
|
||||
final ScrollBehavior? scrollBehavior;
|
||||
|
||||
@override
|
||||
_CupertinoAppState createState() => _CupertinoAppState();
|
||||
|
||||
@ -403,7 +415,18 @@ class CupertinoApp extends StatefulWidget {
|
||||
HeroController(); // Linear tweening.
|
||||
}
|
||||
|
||||
class _AlwaysCupertinoScrollBehavior extends ScrollBehavior {
|
||||
/// Describes how [Scrollable] widgets behave for [CupertinoApp]s.
|
||||
///
|
||||
/// {@macro flutter.widgets.scrollBehavior}
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [ScrollBehavior], the default scrolling behavior extended by this class.
|
||||
class CupertinoScrollBehavior extends ScrollBehavior {
|
||||
@override
|
||||
Widget buildViewportChrome(BuildContext context, Widget child, AxisDirection axisDirection) {
|
||||
// Never build any overscroll glow indicators.
|
||||
@ -521,7 +544,7 @@ class _CupertinoAppState extends State<CupertinoApp> {
|
||||
final CupertinoThemeData effectiveThemeData = widget.theme ?? const CupertinoThemeData();
|
||||
|
||||
return ScrollConfiguration(
|
||||
behavior: _AlwaysCupertinoScrollBehavior(),
|
||||
behavior: widget.scrollBehavior ?? CupertinoScrollBehavior(),
|
||||
child: CupertinoUserInterfaceLevel(
|
||||
data: CupertinoUserInterfaceLevelData.base,
|
||||
child: CupertinoTheme(
|
||||
|
@ -196,6 +196,7 @@ class MaterialApp extends StatefulWidget {
|
||||
this.shortcuts,
|
||||
this.actions,
|
||||
this.restorationScopeId,
|
||||
this.scrollBehavior,
|
||||
}) : assert(routes != null),
|
||||
assert(navigatorObservers != null),
|
||||
assert(title != null),
|
||||
@ -242,6 +243,7 @@ class MaterialApp extends StatefulWidget {
|
||||
this.shortcuts,
|
||||
this.actions,
|
||||
this.restorationScopeId,
|
||||
this.scrollBehavior,
|
||||
}) : assert(routeInformationParser != null),
|
||||
assert(routerDelegate != null),
|
||||
assert(title != null),
|
||||
@ -632,6 +634,23 @@ class MaterialApp extends StatefulWidget {
|
||||
/// {@macro flutter.widgets.widgetsApp.restorationScopeId}
|
||||
final String? restorationScopeId;
|
||||
|
||||
/// {@template flutter.material.materialApp.scrollBehavior}
|
||||
/// The default [ScrollBehavior] for the application.
|
||||
///
|
||||
/// [ScrollBehavior]s describe how [Scrollable] widgets behave. Providing
|
||||
/// a [ScrollBehavior] can set the default [ScrollPhysics] across
|
||||
/// an application, and manage [Scrollable] decorations like [Scrollbar]s and
|
||||
/// [GlowingOverscrollIndicator]s.
|
||||
/// {@endtemplate}
|
||||
///
|
||||
/// When null, defaults to [MaterialScrollBehavior].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [ScrollConfiguration], which controls how [Scrollable] widgets behave
|
||||
/// in a subtree.
|
||||
final ScrollBehavior? scrollBehavior;
|
||||
|
||||
/// Turns on a [GridPaper] overlay that paints a baseline grid
|
||||
/// Material apps.
|
||||
///
|
||||
@ -657,7 +676,18 @@ class MaterialApp extends StatefulWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _MaterialScrollBehavior extends ScrollBehavior {
|
||||
/// Describes how [Scrollable] widgets behave for [MaterialApp]s.
|
||||
///
|
||||
/// {@macro flutter.widgets.scrollBehavior}
|
||||
///
|
||||
/// Setting a [MaterialScrollBehavior] will apply a
|
||||
/// [GlowingOverscrollIndicator] to [Scrollable] descendants when executing on
|
||||
/// [TargetPlatform.android] and [TargetPlatform.fuchsia].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [ScrollBehavior], the default scrolling behavior extended by this class.
|
||||
class MaterialScrollBehavior extends ScrollBehavior {
|
||||
@override
|
||||
TargetPlatform getPlatform(BuildContext context) {
|
||||
return Theme.of(context).platform;
|
||||
@ -850,7 +880,7 @@ class _MaterialAppState extends State<MaterialApp> {
|
||||
}());
|
||||
|
||||
return ScrollConfiguration(
|
||||
behavior: _MaterialScrollBehavior(),
|
||||
behavior: widget.scrollBehavior ?? MaterialScrollBehavior(),
|
||||
child: HeroControllerScope(
|
||||
controller: _heroController,
|
||||
child: result,
|
||||
|
@ -14,8 +14,21 @@ const Color _kDefaultGlowColor = Color(0xFFFFFFFF);
|
||||
|
||||
/// Describes how [Scrollable] widgets should behave.
|
||||
///
|
||||
/// {@template flutter.widgets.scrollBehavior}
|
||||
/// Used by [ScrollConfiguration] to configure the [Scrollable] widgets in a
|
||||
/// subtree.
|
||||
///
|
||||
/// 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.
|
||||
/// {@endtemplate}
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [ScrollConfiguration], the inherited widget that controls how
|
||||
/// [Scrollable] widgets behave in a subtree.
|
||||
@immutable
|
||||
class ScrollBehavior {
|
||||
/// Creates a description of how [Scrollable] widgets should behave.
|
||||
@ -33,7 +46,7 @@ class ScrollBehavior {
|
||||
/// overscrolls.
|
||||
Widget buildViewportChrome(BuildContext context, Widget child, AxisDirection axisDirection) {
|
||||
// When modifying this function, consider modifying the implementation in
|
||||
// _MaterialScrollBehavior as well.
|
||||
// MaterialScrollBehavior as well.
|
||||
switch (getPlatform(context)) {
|
||||
case TargetPlatform.iOS:
|
||||
case TargetPlatform.linux:
|
||||
|
@ -178,6 +178,44 @@ void main() {
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('popped'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('CupertinoApp has correct default ScrollBehavior', (WidgetTester tester) async {
|
||||
late BuildContext capturedContext;
|
||||
await tester.pumpWidget(
|
||||
CupertinoApp(
|
||||
home: Builder(
|
||||
builder: (BuildContext context) {
|
||||
capturedContext = context;
|
||||
return const Placeholder();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
expect(ScrollConfiguration.of(capturedContext).runtimeType, CupertinoScrollBehavior);
|
||||
});
|
||||
|
||||
testWidgets('A ScrollBehavior can be set for CupertinoApp', (WidgetTester tester) async {
|
||||
late BuildContext capturedContext;
|
||||
await tester.pumpWidget(
|
||||
CupertinoApp(
|
||||
scrollBehavior: MockScrollBehavior(),
|
||||
home: Builder(
|
||||
builder: (BuildContext context) {
|
||||
capturedContext = context;
|
||||
return const Placeholder();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
final ScrollBehavior scrollBehavior = ScrollConfiguration.of(capturedContext);
|
||||
expect(scrollBehavior.runtimeType, MockScrollBehavior);
|
||||
expect(scrollBehavior.getScrollPhysics(capturedContext).runtimeType, NeverScrollableScrollPhysics);
|
||||
});
|
||||
}
|
||||
|
||||
class MockScrollBehavior extends ScrollBehavior {
|
||||
@override
|
||||
ScrollPhysics getScrollPhysics(BuildContext context) => const NeverScrollableScrollPhysics();
|
||||
}
|
||||
|
||||
typedef SimpleRouterDelegateBuilder = Widget Function(BuildContext, RouteInformation);
|
||||
|
@ -1026,6 +1026,44 @@ void main() {
|
||||
));
|
||||
expect(builderChild, isNull);
|
||||
});
|
||||
|
||||
testWidgets('MaterialApp has correct default ScrollBehavior', (WidgetTester tester) async {
|
||||
late BuildContext capturedContext;
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Builder(
|
||||
builder: (BuildContext context) {
|
||||
capturedContext = context;
|
||||
return const Placeholder();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
expect(ScrollConfiguration.of(capturedContext).runtimeType, MaterialScrollBehavior);
|
||||
});
|
||||
|
||||
testWidgets('A ScrollBehavior can be set for MaterialApp', (WidgetTester tester) async {
|
||||
late BuildContext capturedContext;
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
scrollBehavior: MockScrollBehavior(),
|
||||
home: Builder(
|
||||
builder: (BuildContext context) {
|
||||
capturedContext = context;
|
||||
return const Placeholder();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
final ScrollBehavior scrollBehavior = ScrollConfiguration.of(capturedContext);
|
||||
expect(scrollBehavior.runtimeType, MockScrollBehavior);
|
||||
expect(scrollBehavior.getScrollPhysics(capturedContext).runtimeType, NeverScrollableScrollPhysics);
|
||||
});
|
||||
}
|
||||
|
||||
class MockScrollBehavior extends ScrollBehavior {
|
||||
@override
|
||||
ScrollPhysics getScrollPhysics(BuildContext context) => const NeverScrollableScrollPhysics();
|
||||
}
|
||||
|
||||
class MockAccessibilityFeature implements AccessibilityFeatures {
|
||||
|
@ -308,6 +308,25 @@ void main() {
|
||||
));
|
||||
expect(find.text('/'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('WidgetsApp has correct default ScrollBehavior', (WidgetTester tester) async {
|
||||
late BuildContext capturedContext;
|
||||
await tester.pumpWidget(
|
||||
WidgetsApp(
|
||||
builder: (BuildContext context, Widget? child) {
|
||||
capturedContext = context;
|
||||
return const Placeholder();
|
||||
},
|
||||
color: const Color(0xFF123456),
|
||||
),
|
||||
);
|
||||
expect(ScrollConfiguration.of(capturedContext).runtimeType, ScrollBehavior);
|
||||
});
|
||||
}
|
||||
|
||||
class MockScrollBehavior extends ScrollBehavior {
|
||||
@override
|
||||
ScrollPhysics getScrollPhysics(BuildContext context) => const NeverScrollableScrollPhysics();
|
||||
}
|
||||
|
||||
typedef SimpleRouterDelegateBuilder = Widget Function(BuildContext, RouteInformation);
|
||||
|
Loading…
x
Reference in New Issue
Block a user