Unverified Commit bbc68cd2 authored by Hans Muller's avatar Hans Muller Committed by GitHub

Added TabBar.splashFactory, TabBarTheme.splashFactory,overlayColor (#96252)

parent 16123105
......@@ -5,6 +5,8 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'ink_well.dart';
import 'material_state.dart';
import 'tabs.dart';
import 'theme.dart';
......@@ -33,6 +35,8 @@ class TabBarTheme with Diagnosticable {
this.labelStyle,
this.unselectedLabelColor,
this.unselectedLabelStyle,
this.overlayColor,
this.splashFactory,
});
/// Default value for [TabBar.indicator].
......@@ -60,6 +64,12 @@ class TabBarTheme with Diagnosticable {
/// Default value for [TabBar.unselectedLabelStyle].
final TextStyle? unselectedLabelStyle;
/// Default value for [TabBar.overlayColor].
final MaterialStateProperty<Color?>? overlayColor;
/// Default value for [TabBar.splashFactory].
final InteractiveInkFeatureFactory? splashFactory;
/// Creates a copy of this object but with the given fields replaced with the
/// new values.
TabBarTheme copyWith({
......@@ -70,6 +80,8 @@ class TabBarTheme with Diagnosticable {
TextStyle? labelStyle,
Color? unselectedLabelColor,
TextStyle? unselectedLabelStyle,
MaterialStateProperty<Color?>? overlayColor,
InteractiveInkFeatureFactory? splashFactory,
}) {
return TabBarTheme(
indicator: indicator ?? this.indicator,
......@@ -79,6 +91,8 @@ class TabBarTheme with Diagnosticable {
labelStyle: labelStyle ?? this.labelStyle,
unselectedLabelColor: unselectedLabelColor ?? this.unselectedLabelColor,
unselectedLabelStyle: unselectedLabelStyle ?? this.unselectedLabelStyle,
overlayColor: overlayColor ?? this.overlayColor,
splashFactory: splashFactory ?? this.splashFactory,
);
}
......@@ -104,6 +118,8 @@ class TabBarTheme with Diagnosticable {
labelStyle: TextStyle.lerp(a.labelStyle, b.labelStyle, t),
unselectedLabelColor: Color.lerp(a.unselectedLabelColor, b.unselectedLabelColor, t),
unselectedLabelStyle: TextStyle.lerp(a.unselectedLabelStyle, b.unselectedLabelStyle, t),
overlayColor: _LerpColors(a.overlayColor, b.overlayColor, t),
splashFactory: t < 0.5 ? a.splashFactory : b.splashFactory,
);
}
......@@ -117,6 +133,8 @@ class TabBarTheme with Diagnosticable {
labelStyle,
unselectedLabelColor,
unselectedLabelStyle,
overlayColor,
splashFactory,
);
}
......@@ -133,6 +151,42 @@ class TabBarTheme with Diagnosticable {
&& other.labelPadding == labelPadding
&& other.labelStyle == labelStyle
&& other.unselectedLabelColor == unselectedLabelColor
&& other.unselectedLabelStyle == unselectedLabelStyle;
&& other.unselectedLabelStyle == unselectedLabelStyle
&& other.overlayColor == overlayColor
&& other.splashFactory == splashFactory;
}
}
@immutable
class _LerpColors implements MaterialStateProperty<Color?> {
const _LerpColors(this.a, this.b, this.t);
final MaterialStateProperty<Color?>? a;
final MaterialStateProperty<Color?>? b;
final double t;
@override
Color? resolve(Set<MaterialState> states) {
final Color? resolvedA = a?.resolve(states);
final Color? resolvedB = b?.resolve(states);
return Color.lerp(resolvedA, resolvedB, t);
}
@override
int get hashCode {
return hashValues(a, b, t);
}
@override
bool operator ==(Object other) {
if (identical(this, other))
return true;
if (other.runtimeType != runtimeType)
return false;
return other is _LerpColors
&& other.a == a
&& other.b == b
&& other.t == t;
}
}
......@@ -643,6 +643,7 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget {
this.enableFeedback,
this.onTap,
this.physics,
this.splashFactory,
}) : assert(tabs != null),
assert(isScrollable != null),
assert(dragStartBehavior != null),
......@@ -786,14 +787,11 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget {
/// [MaterialState.hovered], and [MaterialState.pressed].
///
/// [MaterialState.pressed] triggers a ripple (an ink splash), per
/// the current Material Design spec. The [overlayColor] doesn't map
/// a state to [InkResponse.highlightColor] because a separate highlight
/// is not used by the current design guidelines. See
/// https://material.io/design/interaction/states.html#pressed
/// the current Material Design spec.
///
/// If the overlay color is null or resolves to null, then the default values
/// for [InkResponse.focusColor], [InkResponse.hoverColor], [InkResponse.splashColor]
/// will be used instead.
/// for [InkResponse.focusColor], [InkResponse.hoverColor], [InkResponse.splashColor],
/// and [InkResponse.highlightColor] will be used instead.
final MaterialStateProperty<Color?>? overlayColor;
/// {@macro flutter.widgets.scrollable.dragStartBehavior}
......@@ -832,6 +830,25 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget {
/// Defaults to matching platform conventions.
final ScrollPhysics? physics;
/// Creates the tab bar's [InkWell] splash factory, which defines
/// the appearance of "ink" splashes that occur in response to taps.
///
/// Use [NoSplash.splashFactory] to defeat ink splash rendering. For example
/// to defeat both the splash and the hover/pressed overlay, but not the
/// keyboard focused overlay:
/// ```dart
/// TabBar(
/// splashFactory: NoSplash.splashFactory,
/// overlayColor: MaterialStateProperty.resolveWith<Color?>(
/// (Set<MaterialState> states) {
/// return states.contains(MaterialState.focused) ? null : Colors.transparent;
/// },
/// ),
/// ...
/// )
/// ```
final InteractiveInkFeatureFactory? splashFactory;
/// A size whose height depends on if the tabs have both icons and text.
///
/// [AppBar] uses this size to compute its own preferred size.
......@@ -1187,7 +1204,8 @@ class _TabBarState extends State<TabBar> {
mouseCursor: widget.mouseCursor ?? SystemMouseCursors.click,
onTap: () { _handleTap(index); },
enableFeedback: widget.enableFeedback ?? true,
overlayColor: widget.overlayColor,
overlayColor: widget.overlayColor ?? tabBarTheme.overlayColor,
splashFactory: widget.splashFactory ?? tabBarTheme.splashFactory,
child: Padding(
padding: EdgeInsets.only(bottom: widget.indicatorWeight),
child: Stack(
......
......@@ -54,6 +54,21 @@ RenderParagraph _iconRenderObject(WidgetTester tester, IconData icon) {
}
void main() {
test('TabBarTheme copyWith, ==, hashCode, defaults', () {
expect(const TabBarTheme(), const TabBarTheme().copyWith());
expect(const TabBarTheme().hashCode, const TabBarTheme().copyWith().hashCode);
expect(const TabBarTheme().indicator, null);
expect(const TabBarTheme().indicatorSize, null);
expect(const TabBarTheme().labelColor, null);
expect(const TabBarTheme().labelPadding, null);
expect(const TabBarTheme().labelStyle, null);
expect(const TabBarTheme().unselectedLabelColor, null);
expect(const TabBarTheme().unselectedLabelStyle, null);
expect(const TabBarTheme().overlayColor, null);
expect(const TabBarTheme().splashFactory, null);
});
testWidgets('Tab bar defaults - label style and selected/unselected label colors', (WidgetTester tester) async {
// tests for the default label color and label styles when tabBarTheme and tabBar do not provide any
await tester.pumpWidget(_withTheme(null));
......
......@@ -4322,6 +4322,62 @@ void main() {
expect(controller3.index, 2);
expect(pageController.page, 2);
});
testWidgets('TabBar InkWell splashFactory and overlayColor', (WidgetTester tester) async {
const InteractiveInkFeatureFactory splashFactory = NoSplash.splashFactory;
final MaterialStateProperty<Color?> overlayColor = MaterialStateProperty.resolveWith<Color?>(
(Set<MaterialState> states) => Colors.transparent,
);
// TabBarTheme splashFactory and overlayColor
await tester.pumpWidget(
MaterialApp(
theme: ThemeData.light().copyWith(
tabBarTheme: TabBarTheme(
splashFactory: splashFactory,
overlayColor: overlayColor,
)),
home: DefaultTabController(
length: 1,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
tabs: <Widget>[
Container(width: 100, height: 100, color: Colors.green),
],
),
),
),
),
),
);
expect(tester.widget<InkWell>(find.byType(InkWell)).splashFactory, splashFactory);
expect(tester.widget<InkWell>(find.byType(InkWell)).overlayColor, overlayColor);
// TabBar splashFactory and overlayColor
await tester.pumpWidget(
MaterialApp(
home: DefaultTabController(
length: 1,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
splashFactory: splashFactory,
overlayColor: overlayColor,
tabs: <Widget>[
Container(width: 100, height: 100, color: Colors.green),
],
),
),
),
),
),
);
await tester.pumpAndSettle(); // theme animation
expect(tester.widget<InkWell>(find.byType(InkWell)).splashFactory, splashFactory);
expect(tester.widget<InkWell>(find.byType(InkWell)).overlayColor, overlayColor);
});
}
class KeepAliveInk extends StatefulWidget {
......
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