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 { ...@@ -696,6 +696,11 @@ class MaterialApp extends StatefulWidget {
/// When using the desktop platform, if the [Scrollable] widget scrolls in the /// When using the desktop platform, if the [Scrollable] widget scrolls in the
/// [Axis.vertical], a [Scrollbar] is applied. /// [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: /// See also:
/// ///
/// * [ScrollBehavior], the default scrolling behavior extended by this class. /// * [ScrollBehavior], the default scrolling behavior extended by this class.
...@@ -703,9 +708,17 @@ class MaterialScrollBehavior extends ScrollBehavior { ...@@ -703,9 +708,17 @@ class MaterialScrollBehavior extends ScrollBehavior {
/// Creates a MaterialScrollBehavior that decorates [Scrollable]s with /// Creates a MaterialScrollBehavior that decorates [Scrollable]s with
/// [GlowingOverscrollIndicator]s and [Scrollbar]s based on the current /// [GlowingOverscrollIndicator]s and [Scrollbar]s based on the current
/// platform and provided [ScrollableDetails]. /// 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({ const MaterialScrollBehavior({
AndroidOverscrollIndicator? androidOverscrollIndicator, AndroidOverscrollIndicator? androidOverscrollIndicator,
}) : super(androidOverscrollIndicator: androidOverscrollIndicator); }) : _androidOverscrollIndicator = androidOverscrollIndicator,
super(androidOverscrollIndicator: androidOverscrollIndicator);
final AndroidOverscrollIndicator? _androidOverscrollIndicator;
@override @override
TargetPlatform getPlatform(BuildContext context) => Theme.of(context).platform; TargetPlatform getPlatform(BuildContext context) => Theme.of(context).platform;
...@@ -738,6 +751,9 @@ class MaterialScrollBehavior extends ScrollBehavior { ...@@ -738,6 +751,9 @@ class MaterialScrollBehavior extends ScrollBehavior {
Widget buildOverscrollIndicator(BuildContext context, Widget child, ScrollableDetails details) { Widget buildOverscrollIndicator(BuildContext context, Widget child, ScrollableDetails details) {
// When modifying this function, consider modifying the implementation in // When modifying this function, consider modifying the implementation in
// the base class as well. // the base class as well.
final AndroidOverscrollIndicator indicator = _androidOverscrollIndicator
?? Theme.of(context).androidOverscrollIndicator
?? androidOverscrollIndicator;
switch (getPlatform(context)) { switch (getPlatform(context)) {
case TargetPlatform.iOS: case TargetPlatform.iOS:
case TargetPlatform.linux: case TargetPlatform.linux:
...@@ -745,7 +761,7 @@ class MaterialScrollBehavior extends ScrollBehavior { ...@@ -745,7 +761,7 @@ class MaterialScrollBehavior extends ScrollBehavior {
case TargetPlatform.windows: case TargetPlatform.windows:
return child; return child;
case TargetPlatform.android: case TargetPlatform.android:
switch (androidOverscrollIndicator) { switch (indicator) {
case AndroidOverscrollIndicator.stretch: case AndroidOverscrollIndicator.stretch:
return StretchingOverscrollIndicator( return StretchingOverscrollIndicator(
axisDirection: details.direction, axisDirection: details.direction,
......
...@@ -346,6 +346,7 @@ class ThemeData with Diagnosticable { ...@@ -346,6 +346,7 @@ class ThemeData with Diagnosticable {
'This feature was deprecated after v1.23.0-4.0.pre.', 'This feature was deprecated after v1.23.0-4.0.pre.',
) )
bool? useTextSelectionTheme, bool? useTextSelectionTheme,
AndroidOverscrollIndicator? androidOverscrollIndicator,
}) { }) {
assert(colorScheme?.brightness == null || brightness == null || colorScheme!.brightness == brightness); assert(colorScheme?.brightness == null || brightness == null || colorScheme!.brightness == brightness);
final Brightness _brightness = brightness ?? colorScheme?.brightness ?? Brightness.light; final Brightness _brightness = brightness ?? colorScheme?.brightness ?? Brightness.light;
...@@ -561,6 +562,7 @@ class ThemeData with Diagnosticable { ...@@ -561,6 +562,7 @@ class ThemeData with Diagnosticable {
progressIndicatorTheme: progressIndicatorTheme, progressIndicatorTheme: progressIndicatorTheme,
fixTextFieldOutlineLabel: fixTextFieldOutlineLabel, fixTextFieldOutlineLabel: fixTextFieldOutlineLabel,
useTextSelectionTheme: useTextSelectionTheme, useTextSelectionTheme: useTextSelectionTheme,
androidOverscrollIndicator: androidOverscrollIndicator,
); );
} }
...@@ -701,6 +703,7 @@ class ThemeData with Diagnosticable { ...@@ -701,6 +703,7 @@ class ThemeData with Diagnosticable {
'This feature was deprecated after v1.23.0-4.0.pre.', 'This feature was deprecated after v1.23.0-4.0.pre.',
) )
required this.useTextSelectionTheme, required this.useTextSelectionTheme,
required this.androidOverscrollIndicator,
}) : assert(visualDensity != null), }) : assert(visualDensity != null),
assert(primaryColor != null), assert(primaryColor != null),
assert(primaryColorBrightness != null), assert(primaryColorBrightness != null),
...@@ -1358,6 +1361,20 @@ class ThemeData with Diagnosticable { ...@@ -1358,6 +1361,20 @@ class ThemeData with Diagnosticable {
) )
final bool useTextSelectionTheme; 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. /// Creates a copy of this theme but with the given fields replaced with the new values.
/// ///
/// The [brightness] value is applied to the [colorScheme]. /// The [brightness] value is applied to the [colorScheme].
...@@ -1489,6 +1506,7 @@ class ThemeData with Diagnosticable { ...@@ -1489,6 +1506,7 @@ class ThemeData with Diagnosticable {
'This feature was deprecated after v1.23.0-4.0.pre.', 'This feature was deprecated after v1.23.0-4.0.pre.',
) )
bool? useTextSelectionTheme, bool? useTextSelectionTheme,
AndroidOverscrollIndicator? androidOverscrollIndicator,
}) { }) {
cupertinoOverrideTheme = cupertinoOverrideTheme?.noDefault(); cupertinoOverrideTheme = cupertinoOverrideTheme?.noDefault();
return ThemeData.raw( return ThemeData.raw(
...@@ -1570,6 +1588,7 @@ class ThemeData with Diagnosticable { ...@@ -1570,6 +1588,7 @@ class ThemeData with Diagnosticable {
progressIndicatorTheme: progressIndicatorTheme ?? this.progressIndicatorTheme, progressIndicatorTheme: progressIndicatorTheme ?? this.progressIndicatorTheme,
fixTextFieldOutlineLabel: fixTextFieldOutlineLabel ?? this.fixTextFieldOutlineLabel, fixTextFieldOutlineLabel: fixTextFieldOutlineLabel ?? this.fixTextFieldOutlineLabel,
useTextSelectionTheme: useTextSelectionTheme ?? this.useTextSelectionTheme, useTextSelectionTheme: useTextSelectionTheme ?? this.useTextSelectionTheme,
androidOverscrollIndicator: androidOverscrollIndicator ?? this.androidOverscrollIndicator,
); );
} }
...@@ -1729,6 +1748,7 @@ class ThemeData with Diagnosticable { ...@@ -1729,6 +1748,7 @@ class ThemeData with Diagnosticable {
progressIndicatorTheme: ProgressIndicatorThemeData.lerp(a.progressIndicatorTheme, b.progressIndicatorTheme, t)!, progressIndicatorTheme: ProgressIndicatorThemeData.lerp(a.progressIndicatorTheme, b.progressIndicatorTheme, t)!,
fixTextFieldOutlineLabel: t < 0.5 ? a.fixTextFieldOutlineLabel : b.fixTextFieldOutlineLabel, fixTextFieldOutlineLabel: t < 0.5 ? a.fixTextFieldOutlineLabel : b.fixTextFieldOutlineLabel,
useTextSelectionTheme: t < 0.5 ? a.useTextSelectionTheme : b.useTextSelectionTheme, useTextSelectionTheme: t < 0.5 ? a.useTextSelectionTheme : b.useTextSelectionTheme,
androidOverscrollIndicator: t < 0.5 ? a.androidOverscrollIndicator : b.androidOverscrollIndicator,
); );
} }
...@@ -1815,7 +1835,8 @@ class ThemeData with Diagnosticable { ...@@ -1815,7 +1835,8 @@ class ThemeData with Diagnosticable {
&& other.switchTheme == switchTheme && other.switchTheme == switchTheme
&& other.progressIndicatorTheme == progressIndicatorTheme && other.progressIndicatorTheme == progressIndicatorTheme
&& other.fixTextFieldOutlineLabel == fixTextFieldOutlineLabel && other.fixTextFieldOutlineLabel == fixTextFieldOutlineLabel
&& other.useTextSelectionTheme == useTextSelectionTheme; && other.useTextSelectionTheme == useTextSelectionTheme
&& other.androidOverscrollIndicator == androidOverscrollIndicator;
} }
@override @override
...@@ -1902,6 +1923,7 @@ class ThemeData with Diagnosticable { ...@@ -1902,6 +1923,7 @@ class ThemeData with Diagnosticable {
progressIndicatorTheme, progressIndicatorTheme,
fixTextFieldOutlineLabel, fixTextFieldOutlineLabel,
useTextSelectionTheme, useTextSelectionTheme,
androidOverscrollIndicator,
]; ];
return hashList(values); return hashList(values);
} }
...@@ -1984,6 +2006,7 @@ class ThemeData with Diagnosticable { ...@@ -1984,6 +2006,7 @@ class ThemeData with Diagnosticable {
properties.add(DiagnosticsProperty<RadioThemeData>('radioTheme', radioTheme, defaultValue: defaultData.radioTheme, level: DiagnosticLevel.debug)); 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<SwitchThemeData>('switchTheme', switchTheme, defaultValue: defaultData.switchTheme, level: DiagnosticLevel.debug));
properties.add(DiagnosticsProperty<ProgressIndicatorThemeData>('progressIndicatorTheme', progressIndicatorTheme, defaultValue: defaultData.progressIndicatorTheme, 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 { ...@@ -65,7 +65,14 @@ class ScrollBehavior {
AndroidOverscrollIndicator? androidOverscrollIndicator, AndroidOverscrollIndicator? androidOverscrollIndicator,
}): _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; AndroidOverscrollIndicator get androidOverscrollIndicator => _androidOverscrollIndicator ?? _kDefaultAndroidOverscrollIndicator;
final AndroidOverscrollIndicator? _androidOverscrollIndicator; final AndroidOverscrollIndicator? _androidOverscrollIndicator;
......
...@@ -1106,6 +1106,45 @@ void main() { ...@@ -1106,6 +1106,45 @@ void main() {
expect(find.byType(GlowingOverscrollIndicator), findsNothing); expect(find.byType(GlowingOverscrollIndicator), findsNothing);
}, variant: TargetPlatformVariant.only(TargetPlatform.android)); }, 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 { testWidgets('When `useInheritedMediaQuery` is true an existing MediaQuery is used if one is available', (WidgetTester tester) async {
late BuildContext capturedContext; late BuildContext capturedContext;
final UniqueKey uniqueKey = UniqueKey(); final UniqueKey uniqueKey = UniqueKey();
......
...@@ -346,6 +346,7 @@ void main() { ...@@ -346,6 +346,7 @@ void main() {
progressIndicatorTheme: const ProgressIndicatorThemeData(), progressIndicatorTheme: const ProgressIndicatorThemeData(),
fixTextFieldOutlineLabel: false, fixTextFieldOutlineLabel: false,
useTextSelectionTheme: false, useTextSelectionTheme: false,
androidOverscrollIndicator: null,
); );
final SliderThemeData otherSliderTheme = SliderThemeData.fromPrimaryColors( final SliderThemeData otherSliderTheme = SliderThemeData.fromPrimaryColors(
...@@ -440,6 +441,7 @@ void main() { ...@@ -440,6 +441,7 @@ void main() {
progressIndicatorTheme: const ProgressIndicatorThemeData(), progressIndicatorTheme: const ProgressIndicatorThemeData(),
fixTextFieldOutlineLabel: true, fixTextFieldOutlineLabel: true,
useTextSelectionTheme: true, useTextSelectionTheme: true,
androidOverscrollIndicator: AndroidOverscrollIndicator.stretch,
); );
final ThemeData themeDataCopy = theme.copyWith( 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