Skip to content

Commit fbba194

Browse files
authored
Migrate ListTile disabled icon color to Material 3 (#102078)
1 parent d8fdb83 commit fbba194

File tree

2 files changed

+77
-13
lines changed

2 files changed

+77
-13
lines changed

packages/flutter/lib/src/material/list_tile.dart

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,13 @@ class ListTile extends StatelessWidget {
593593
return selectedColor ?? tileTheme.selectedColor ?? theme.listTileTheme.selectedColor ?? theme.colorScheme.primary;
594594
}
595595

596-
final Color? color = iconColor ?? tileTheme.iconColor ?? theme.listTileTheme.iconColor;
596+
final Color? color = iconColor
597+
?? tileTheme.iconColor
598+
?? theme.listTileTheme.iconColor
599+
// If [ThemeData.useMaterial3] is set to true the disabled icon color
600+
// will be set to Theme.colorScheme.onSurface(0.38), if false, defaults to null,
601+
// as described in: https://m3.material.io/components/icon-buttons/specs.
602+
?? (theme.useMaterial3 ? theme.colorScheme.onSurface.withOpacity(0.38) : null);
597603
if (color != null) {
598604
return color;
599605
}

packages/flutter/test/material/list_tile_test.dart

Lines changed: 70 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2037,8 +2037,6 @@ void main() {
20372037
});
20382038

20392039
testWidgets('selected, enabled ListTile default icon color, light and dark themes', (WidgetTester tester) async {
2040-
// Regression test for https://github.com/flutter/flutter/pull/77004
2041-
20422040
const ColorScheme lightColorScheme = ColorScheme.light();
20432041
const ColorScheme darkColorScheme = ColorScheme.dark();
20442042
final Key leadingKey = UniqueKey();
@@ -2048,8 +2046,8 @@ void main() {
20482046

20492047
Widget buildFrame({ required Brightness brightness, required bool selected }) {
20502048
final ThemeData theme = brightness == Brightness.light
2051-
? ThemeData.from(colorScheme: const ColorScheme.light())
2052-
: ThemeData.from(colorScheme: const ColorScheme.dark());
2049+
? ThemeData.from(colorScheme: const ColorScheme.light(), useMaterial3: true)
2050+
: ThemeData.from(colorScheme: const ColorScheme.dark(), useMaterial3: true);
20532051
return MaterialApp(
20542052
theme: theme,
20552053
home: Material(
@@ -2075,10 +2073,10 @@ void main() {
20752073
expect(iconColor(trailingKey), lightColorScheme.primary);
20762074

20772075
await tester.pumpWidget(buildFrame(brightness: Brightness.light, selected: false));
2078-
expect(iconColor(leadingKey), Colors.black45);
2079-
expect(iconColor(titleKey), Colors.black45);
2080-
expect(iconColor(subtitleKey), Colors.black45);
2081-
expect(iconColor(trailingKey), Colors.black45);
2076+
expect(iconColor(leadingKey), lightColorScheme.onSurface.withOpacity(0.38));
2077+
expect(iconColor(titleKey), lightColorScheme.onSurface.withOpacity(0.38));
2078+
expect(iconColor(subtitleKey), lightColorScheme.onSurface.withOpacity(0.38));
2079+
expect(iconColor(trailingKey), lightColorScheme.onSurface.withOpacity(0.38));
20822080

20832081
await tester.pumpWidget(buildFrame(brightness: Brightness.dark, selected: true));
20842082
await tester.pumpAndSettle(); // Animated theme change
@@ -2090,10 +2088,10 @@ void main() {
20902088
// For this configuration, ListTile defers to the default IconTheme.
20912089
// The default dark theme's IconTheme has color:white
20922090
await tester.pumpWidget(buildFrame(brightness: Brightness.dark, selected: false));
2093-
expect(iconColor(leadingKey), Colors.white);
2094-
expect(iconColor(titleKey), Colors.white);
2095-
expect(iconColor(subtitleKey), Colors.white);
2096-
expect(iconColor(trailingKey), Colors.white);
2091+
expect(iconColor(leadingKey), darkColorScheme.onSurface.withOpacity(0.38));
2092+
expect(iconColor(titleKey), darkColorScheme.onSurface.withOpacity(0.38));
2093+
expect(iconColor(subtitleKey), darkColorScheme.onSurface.withOpacity(0.38));
2094+
expect(iconColor(trailingKey), darkColorScheme.onSurface.withOpacity(0.38));
20972095
});
20982096

20992097
testWidgets('ListTile font size', (WidgetTester tester) async {
@@ -2442,6 +2440,66 @@ void main() {
24422440
trailing = _getTextRenderObject(tester, 'trailing');
24432441
expect(trailing.text.style!.color, theme.textTheme.bodyMedium!.color);
24442442
});
2443+
2444+
testWidgets('selected, enabled ListTile default icon color, light and dark themes', (WidgetTester tester) async {
2445+
// Regression test for https://github.com/flutter/flutter/pull/77004
2446+
2447+
const ColorScheme lightColorScheme = ColorScheme.light();
2448+
const ColorScheme darkColorScheme = ColorScheme.dark();
2449+
final Key leadingKey = UniqueKey();
2450+
final Key titleKey = UniqueKey();
2451+
final Key subtitleKey = UniqueKey();
2452+
final Key trailingKey = UniqueKey();
2453+
2454+
Widget buildFrame({ required Brightness brightness, required bool selected }) {
2455+
final ThemeData theme = brightness == Brightness.light
2456+
? ThemeData.from(colorScheme: const ColorScheme.light())
2457+
: ThemeData.from(colorScheme: const ColorScheme.dark());
2458+
return MaterialApp(
2459+
theme: theme,
2460+
home: Material(
2461+
child: Center(
2462+
child: ListTile(
2463+
selected: selected,
2464+
leading: TestIcon(key: leadingKey),
2465+
title: TestIcon(key: titleKey),
2466+
subtitle: TestIcon(key: subtitleKey),
2467+
trailing: TestIcon(key: trailingKey),
2468+
),
2469+
),
2470+
),
2471+
);
2472+
}
2473+
2474+
Color iconColor(Key key) => tester.state<TestIconState>(find.byKey(key)).iconTheme.color!;
2475+
2476+
await tester.pumpWidget(buildFrame(brightness: Brightness.light, selected: true));
2477+
expect(iconColor(leadingKey), lightColorScheme.primary);
2478+
expect(iconColor(titleKey), lightColorScheme.primary);
2479+
expect(iconColor(subtitleKey), lightColorScheme.primary);
2480+
expect(iconColor(trailingKey), lightColorScheme.primary);
2481+
2482+
await tester.pumpWidget(buildFrame(brightness: Brightness.light, selected: false));
2483+
expect(iconColor(leadingKey), Colors.black45);
2484+
expect(iconColor(titleKey), Colors.black45);
2485+
expect(iconColor(subtitleKey), Colors.black45);
2486+
expect(iconColor(trailingKey), Colors.black45);
2487+
2488+
await tester.pumpWidget(buildFrame(brightness: Brightness.dark, selected: true));
2489+
await tester.pumpAndSettle(); // Animated theme change
2490+
expect(iconColor(leadingKey), darkColorScheme.primary);
2491+
expect(iconColor(titleKey), darkColorScheme.primary);
2492+
expect(iconColor(subtitleKey), darkColorScheme.primary);
2493+
expect(iconColor(trailingKey), darkColorScheme.primary);
2494+
2495+
// For this configuration, ListTile defers to the default IconTheme.
2496+
// The default dark theme's IconTheme has color:white
2497+
await tester.pumpWidget(buildFrame(brightness: Brightness.dark, selected: false));
2498+
expect(iconColor(leadingKey), Colors.white);
2499+
expect(iconColor(titleKey), Colors.white);
2500+
expect(iconColor(subtitleKey), Colors.white);
2501+
expect(iconColor(trailingKey), Colors.white);
2502+
});
24452503
});
24462504
}
24472505

0 commit comments

Comments
 (0)