Unverified Commit e761e649 authored by Kate Lovett's avatar Kate Lovett Committed by GitHub

Add theme support for choosing android overscroll indicator (#88295)

parent 51353b5a
......@@ -696,6 +696,11 @@ class MaterialApp extends StatefulWidget {
/// When using the desktop platform, if the [Scrollable] widget scrolls in the
/// [Axis.vertical], a [Scrollbar] is applied.
///
/// [MaterialScrollBehavior.androidOverscrollIndicator] specifies the
/// overscroll indicator that is used on [TargetPlatform.android]. When null,
/// [ThemeData.androidOverscrollIndicator] is used. If also null, the default
/// overscroll indicator is the [GlowingOverscrollIndicator].
///
/// See also:
///
/// * [ScrollBehavior], the default scrolling behavior extended by this class.
......@@ -703,9 +708,17 @@ 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].
///
/// [MaterialScrollBehavior.androidOverscrollIndicator] specifies the
/// overscroll indicator that is used on [TargetPlatform.android]. When null,
/// [ThemeData.androidOverscrollIndicator] is used. If also null, the default
/// overscroll indicator is the [GlowingOverscrollIndicator].
const MaterialScrollBehavior({
AndroidOverscrollIndicator? androidOverscrollIndicator,
}) : super(androidOverscrollIndicator: androidOverscrollIndicator);
}) : _androidOverscrollIndicator = androidOverscrollIndicator,
super(androidOverscrollIndicator: androidOverscrollIndicator);
final AndroidOverscrollIndicator? _androidOverscrollIndicator;
@override
TargetPlatform getPlatform(BuildContext context) => Theme.of(context).platform;
......@@ -738,6 +751,9 @@ class MaterialScrollBehavior extends ScrollBehavior {
Widget buildOverscrollIndicator(BuildContext context, Widget child, ScrollableDetails details) {
// When modifying this function, consider modifying the implementation in
// the base class as well.
final AndroidOverscrollIndicator indicator = _androidOverscrollIndicator
?? Theme.of(context).androidOverscrollIndicator
?? androidOverscrollIndicator;
switch (getPlatform(context)) {
case TargetPlatform.iOS:
case TargetPlatform.linux:
......@@ -745,7 +761,7 @@ class MaterialScrollBehavior extends ScrollBehavior {
case TargetPlatform.windows:
return child;
case TargetPlatform.android:
switch (androidOverscrollIndicator) {
switch (indicator) {
case AndroidOverscrollIndicator.stretch:
return StretchingOverscrollIndicator(
axisDirection: details.direction,
......
......@@ -346,6 +346,7 @@ class ThemeData with Diagnosticable {
'This feature was deprecated after v1.23.0-4.0.pre.',
)
bool? useTextSelectionTheme,
AndroidOverscrollIndicator? androidOverscrollIndicator,
}) {
assert(colorScheme?.brightness == null || brightness == null || colorScheme!.brightness == brightness);
final Brightness _brightness = brightness ?? colorScheme?.brightness ?? Brightness.light;
......@@ -561,6 +562,7 @@ class ThemeData with Diagnosticable {
progressIndicatorTheme: progressIndicatorTheme,
fixTextFieldOutlineLabel: fixTextFieldOutlineLabel,
useTextSelectionTheme: useTextSelectionTheme,
androidOverscrollIndicator: androidOverscrollIndicator,
);
}
......@@ -701,6 +703,7 @@ class ThemeData with Diagnosticable {
'This feature was deprecated after v1.23.0-4.0.pre.',
)
required this.useTextSelectionTheme,
required this.androidOverscrollIndicator,
}) : assert(visualDensity != null),
assert(primaryColor != null),
assert(primaryColorBrightness != null),
......@@ -1358,6 +1361,20 @@ class ThemeData with Diagnosticable {
)
final bool useTextSelectionTheme;
/// Specifies which overscroll indicator to use on [TargetPlatform.android].
///
/// When null, the default value of
/// [MaterialScrollBehavior.androidOverscrollIndicator] is
/// [AndroidOverscrollIndicator.glow].
///
/// See also:
///
/// * [StretchingOverscrollIndicator], a material design edge effect
/// that transforms the contents of a scrollable when overscrolled.
/// * [GlowingOverscrollIndicator], an edge effect that paints a glow
/// over the contents of a scrollable when overscrolled.
final AndroidOverscrollIndicator? androidOverscrollIndicator;
/// Creates a copy of this theme but with the given fields replaced with the new values.
///
/// The [brightness] value is applied to the [colorScheme].
......@@ -1489,6 +1506,7 @@ class ThemeData with Diagnosticable {
'This feature was deprecated after v1.23.0-4.0.pre.',
)
bool? useTextSelectionTheme,
AndroidOverscrollIndicator? androidOverscrollIndicator,
}) {
cupertinoOverrideTheme = cupertinoOverrideTheme?.noDefault();
return ThemeData.raw(
......@@ -1570,6 +1588,7 @@ class ThemeData with Diagnosticable {
progressIndicatorTheme: progressIndicatorTheme ?? this.progressIndicatorTheme,
fixTextFieldOutlineLabel: fixTextFieldOutlineLabel ?? this.fixTextFieldOutlineLabel,
useTextSelectionTheme: useTextSelectionTheme ?? this.useTextSelectionTheme,
androidOverscrollIndicator: androidOverscrollIndicator ?? this.androidOverscrollIndicator,
);
}
......@@ -1729,6 +1748,7 @@ class ThemeData with Diagnosticable {
progressIndicatorTheme: ProgressIndicatorThemeData.lerp(a.progressIndicatorTheme, b.progressIndicatorTheme, t)!,
fixTextFieldOutlineLabel: t < 0.5 ? a.fixTextFieldOutlineLabel : b.fixTextFieldOutlineLabel,
useTextSelectionTheme: t < 0.5 ? a.useTextSelectionTheme : b.useTextSelectionTheme,
androidOverscrollIndicator: t < 0.5 ? a.androidOverscrollIndicator : b.androidOverscrollIndicator,
);
}
......@@ -1815,7 +1835,8 @@ class ThemeData with Diagnosticable {
&& other.switchTheme == switchTheme
&& other.progressIndicatorTheme == progressIndicatorTheme
&& other.fixTextFieldOutlineLabel == fixTextFieldOutlineLabel
&& other.useTextSelectionTheme == useTextSelectionTheme;
&& other.useTextSelectionTheme == useTextSelectionTheme
&& other.androidOverscrollIndicator == androidOverscrollIndicator;
}
@override
......@@ -1902,6 +1923,7 @@ class ThemeData with Diagnosticable {
progressIndicatorTheme,
fixTextFieldOutlineLabel,
useTextSelectionTheme,
androidOverscrollIndicator,
];
return hashList(values);
}
......@@ -1984,6 +2006,7 @@ class ThemeData with Diagnosticable {
properties.add(DiagnosticsProperty<RadioThemeData>('radioTheme', radioTheme, defaultValue: defaultData.radioTheme, level: DiagnosticLevel.debug));
properties.add(DiagnosticsProperty<SwitchThemeData>('switchTheme', switchTheme, defaultValue: defaultData.switchTheme, level: DiagnosticLevel.debug));
properties.add(DiagnosticsProperty<ProgressIndicatorThemeData>('progressIndicatorTheme', progressIndicatorTheme, defaultValue: defaultData.progressIndicatorTheme, level: DiagnosticLevel.debug));
properties.add(EnumProperty<AndroidOverscrollIndicator>('androidOverscrollIndicator', androidOverscrollIndicator, defaultValue: null, level: DiagnosticLevel.debug));
}
}
......
......@@ -65,7 +65,14 @@ class ScrollBehavior {
AndroidOverscrollIndicator? androidOverscrollIndicator,
}): _androidOverscrollIndicator = androidOverscrollIndicator;
/// Specifies which overscroll indicatpr to use on [TargetPlatform.android].
/// Specifies which overscroll indicator to use on [TargetPlatform.android].
///
/// Cannot be null. Defaults to [AndroidOverscrollIndicator.glow].
///
/// See also:
///
/// * [MaterialScrollBehavior], which supports setting this property
/// using [ThemeData].
AndroidOverscrollIndicator get androidOverscrollIndicator => _androidOverscrollIndicator ?? _kDefaultAndroidOverscrollIndicator;
final AndroidOverscrollIndicator? _androidOverscrollIndicator;
......
......@@ -1106,6 +1106,45 @@ void main() {
expect(find.byType(GlowingOverscrollIndicator), findsNothing);
}, variant: TargetPlatformVariant.only(TargetPlatform.android));
testWidgets('Overscroll indicator can be set by theme', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
// The current default is glowing, setting via the theme should override.
theme: ThemeData().copyWith(androidOverscrollIndicator: AndroidOverscrollIndicator.stretch),
home: ListView(
children: const <Widget>[
SizedBox(
height: 1000.0,
width: 1000.0,
child: Text('Test'),
)
]
)
));
expect(find.byType(StretchingOverscrollIndicator), findsOneWidget);
expect(find.byType(GlowingOverscrollIndicator), findsNothing);
}, variant: TargetPlatformVariant.only(TargetPlatform.android));
testWidgets('Overscroll indicator in MaterialScrollBehavior takes precedence over theme', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
// MaterialScrollBehavior.androidOverscrollIndicator takes precedence over theme.
scrollBehavior: const MaterialScrollBehavior(androidOverscrollIndicator: AndroidOverscrollIndicator.stretch),
theme: ThemeData().copyWith(androidOverscrollIndicator: AndroidOverscrollIndicator.glow),
home: ListView(
children: const <Widget>[
SizedBox(
height: 1000.0,
width: 1000.0,
child: Text('Test'),
)
]
)
));
expect(find.byType(StretchingOverscrollIndicator), findsOneWidget);
expect(find.byType(GlowingOverscrollIndicator), findsNothing);
}, 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();
......
......@@ -346,6 +346,7 @@ void main() {
progressIndicatorTheme: const ProgressIndicatorThemeData(),
fixTextFieldOutlineLabel: false,
useTextSelectionTheme: false,
androidOverscrollIndicator: null,
);
final SliderThemeData otherSliderTheme = SliderThemeData.fromPrimaryColors(
......@@ -440,6 +441,7 @@ void main() {
progressIndicatorTheme: const ProgressIndicatorThemeData(),
fixTextFieldOutlineLabel: true,
useTextSelectionTheme: true,
androidOverscrollIndicator: AndroidOverscrollIndicator.stretch,
);
final ThemeData themeDataCopy = theme.copyWith(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment