Skip to content

Commit

Permalink
Add support for ExpansionPanel custom splash color (#147126)
Browse files Browse the repository at this point in the history
Relates to flutter/flutter#147098 and flutter/flutter#147097

Aside from fixing the expland/collapse icon color in the other PR, I noticed the splash color on both the icon button and the full expansion panel (if ExpansionPanel.canTapOnHeader is set to true) is just `Theme.of(context).splashColor` on the `InkWell` and `Theme.of(context).highlightColor` on the `IconButton` which may not suit the color scheme of the `ExpansionPanel`, so I have added a custom field `splashColor`, which will effect both the `IconButton` and the full panel `Inkwell`.
  • Loading branch information
BenjiFarquhar authored May 31, 2024
1 parent cc783cf commit 5116886
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 0 deletions.
18 changes: 18 additions & 0 deletions packages/flutter/lib/src/material/expand_icon.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ class ExpandIcon extends StatefulWidget {
this.color,
this.disabledColor,
this.expandedColor,
this.splashColor,
this.highlightColor,
});

/// Whether the icon is in an expanded state.
Expand Down Expand Up @@ -94,6 +96,20 @@ class ExpandIcon extends StatefulWidget {
/// and for [dark theme](https://material.io/design/color/dark-theme.html#ui-application)
final Color? expandedColor;

/// Defines the splash color of the IconButton.
///
/// If [ThemeData.useMaterial3] is true, this field will be ignored,
/// as [IconButton.splashColor] will be ignored, and you should use
/// [highlightColor] instead.
///
/// Defaults to [ThemeData.splashColor].
final Color? splashColor;

/// Defines the highlight color of the IconButton.
///
/// Defaults to [ThemeData.highlightColor].
final Color? highlightColor;

@override
State<ExpandIcon> createState() => _ExpandIconState();
}
Expand Down Expand Up @@ -170,6 +186,8 @@ class _ExpandIconState extends State<ExpandIcon> with SingleTickerProviderStateM
child: IconButton(
padding: widget.padding,
iconSize: widget.size,
highlightColor: widget.highlightColor,
splashColor: widget.splashColor,
color: _iconColor,
disabledColor: widget.disabledColor,
onPressed: widget.onPressed == null ? null : _handlePressed,
Expand Down
31 changes: 31 additions & 0 deletions packages/flutter/lib/src/material/expansion_panel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:flutter/widgets.dart';

import 'constants.dart';
import 'expand_icon.dart';
import 'icon_button.dart';
import 'ink_well.dart';
import 'material_localizations.dart';
import 'mergeable_material.dart';
Expand Down Expand Up @@ -80,6 +81,8 @@ class ExpansionPanel {
this.isExpanded = false,
this.canTapOnHeader = false,
this.backgroundColor,
this.splashColor,
this.highlightColor,
});

/// The widget builder that builds the expansion panels' header.
Expand All @@ -95,6 +98,28 @@ class ExpansionPanel {
/// Defaults to false.
final bool isExpanded;

/// Defines the splash color of the panel if [canTapOnHeader] is true,
/// or the splash color of the expand/collapse IconButton if [canTapOnHeader]
/// is false.
///
/// If [canTapOnHeader] is false, and [ThemeData.useMaterial3] is
/// true, this field will be ignored, as [IconButton.splashColor]
/// will be ignored, and you should use [highlightColor] instead.
///
/// If this is null, then the icon button will use its default splash color
/// [ThemeData.splashColor], and the panel will use its default splash color
/// [ThemeData.splashColor] (if [canTapOnHeader] is true).
final Color? splashColor;

/// Defines the highlight color of the panel if [canTapOnHeader] is true, or
/// the highlight color of the expand/collapse IconButton if [canTapOnHeader]
/// is false.
///
/// If this is null, then the icon button will use its default highlight color
/// [ThemeData.highlightColor], and the panel will use its default highlight
/// color [ThemeData.highlightColor] (if [canTapOnHeader] is true).
final Color? highlightColor;

/// Whether tapping on the panel's header will expand/collapse it.
///
/// Defaults to false.
Expand Down Expand Up @@ -125,6 +150,8 @@ class ExpansionPanelRadio extends ExpansionPanel {
required super.body,
super.canTapOnHeader,
super.backgroundColor,
super.splashColor,
super.highlightColor,
});

/// The value that uniquely identifies a radio panel so that the currently
Expand Down Expand Up @@ -366,6 +393,8 @@ class _ExpansionPanelListState extends State<ExpansionPanelList> {
disabledColor: child.canTapOnHeader ? widget.expandIconColor : null,
isExpanded: _isChildExpanded(index),
padding: _kExpandIconPadding,
splashColor: child.splashColor,
highlightColor: child.highlightColor,
onPressed: !child.canTapOnHeader
? (bool isExpanded) => _handlePressed(isExpanded, index)
: null,
Expand Down Expand Up @@ -399,6 +428,8 @@ class _ExpansionPanelListState extends State<ExpansionPanelList> {
if (child.canTapOnHeader) {
header = MergeSemantics(
child: InkWell(
splashColor: child.splashColor,
highlightColor: child.highlightColor,
onTap: () => _handlePressed(_isChildExpanded(index), index),
child: header,
),
Expand Down
68 changes: 68 additions & 0 deletions packages/flutter/test/material/expansion_panel_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1948,6 +1948,74 @@ void main() {
}
});

testWidgets('Ensure IconButton splashColor and highlightColor are correctly set when canTapOnHeader is false', (WidgetTester tester) async {
const Color expectedSplashColor = Colors.green;
const Color expectedHighlightColor = Colors.yellow;

await tester.pumpWidget(MaterialApp(
home: SingleChildScrollView(
child: ExpansionPanelList(
children: <ExpansionPanel>[
ExpansionPanel(
headerBuilder: (BuildContext context, bool isExpanded) {
return const ListTile(title: Text('Panel 1'));
},
body: const ListTile(title: Text('Content for Panel 1')),
splashColor: expectedSplashColor,
highlightColor: expectedHighlightColor,
),
],
),
),
));

await tester.tap(find.text('Panel 1'));
await tester.pumpAndSettle();

final IconButton iconButton = tester.widget(find.byType(IconButton).first);
expect(iconButton.splashColor, expectedSplashColor);
expect(iconButton.highlightColor, expectedHighlightColor);
});

testWidgets('Ensure InkWell splashColor and highlightColor are correctly set when canTapOnHeader is true', (WidgetTester tester) async {
const Color expectedSplashColor = Colors.green;
const Color expectedHighlightColor = Colors.yellow;

await tester.pumpWidget(MaterialApp(
home: SingleChildScrollView(
child: ExpansionPanelList(
children: <ExpansionPanel>[
ExpansionPanel(
canTapOnHeader: true,
headerBuilder: (BuildContext context, bool isExpanded) {
return Container(
padding: const EdgeInsets.all(16),
alignment: Alignment.centerLeft,
child: const Text('Panel 1'),
);
},
body: const ListTile(title: Text('Content for Panel 1')),
splashColor: expectedSplashColor,
highlightColor: expectedHighlightColor,
),
],
),
),
));

await tester.pumpAndSettle();

final Finder inkWellFinder = find.descendant(
of: find.byType(ExpansionPanelList),
matching: find.byWidgetPredicate((Widget widget) =>
widget is InkWell && widget.onTap != null)
);

final InkWell inkWell = tester.widget<InkWell>(inkWellFinder);
expect(inkWell.splashColor, expectedSplashColor);
expect(inkWell.highlightColor, expectedHighlightColor);
});

testWidgets('ExpandIcon.disabledColor uses expandIconColor color when canTapOnHeader is true', (WidgetTester tester) async {
const Color expandIconColor = Color(0xff0000ff);

Expand Down

0 comments on commit 5116886

Please sign in to comment.