From 7d9eaab014b569dc28115429a3ddce721e5267df Mon Sep 17 00:00:00 2001 From: Eilidh Southren Date: Wed, 18 Jan 2023 23:00:09 +0000 Subject: [PATCH] Appbar iconTheme override fix (#118681) * theme override fix * add conditional centering --- .../flutter/lib/src/material/app_bar.dart | 54 +++++++-------- .../flutter/test/material/app_bar_test.dart | 67 +++++++++++++++++++ 2 files changed, 92 insertions(+), 29 deletions(-) diff --git a/packages/flutter/lib/src/material/app_bar.dart b/packages/flutter/lib/src/material/app_bar.dart index da6f10f64dbc..c290d70554bb 100644 --- a/packages/flutter/lib/src/material/app_bar.dart +++ b/packages/flutter/lib/src/material/app_bar.dart @@ -1023,39 +1023,35 @@ class _AppBarState extends State { } if (leading != null) { if (theme.useMaterial3) { - if (leading is IconButton) { - final IconButtonThemeData effectiveIconButtonTheme; - - // This comparison is to check if there is a custom [overallIconTheme]. If true, it means that no - // custom [overallIconTheme] is provided, so [iconButtonTheme] is applied. Otherwise, we generate - // a new [IconButtonThemeData] based on the values from [overallIconTheme]. If [iconButtonTheme] only - // has null values, the default [overallIconTheme] will be applied below by [IconTheme.merge] - if (overallIconTheme == defaults.iconTheme) { - effectiveIconButtonTheme = iconButtonTheme; - } else { - // The [IconButton.styleFrom] method is used to generate a correct [overlayColor] based on the [foregroundColor]. - final ButtonStyle leadingIconButtonStyle = IconButton.styleFrom( - foregroundColor: overallIconTheme.color, - iconSize: overallIconTheme.size, - ); - - effectiveIconButtonTheme = IconButtonThemeData( - style: iconButtonTheme.style?.copyWith( - foregroundColor: leadingIconButtonStyle.foregroundColor, - overlayColor: leadingIconButtonStyle.overlayColor, - iconSize: leadingIconButtonStyle.iconSize, - ) - ); - } - - leading = Center( - child: IconButtonTheme( - data: effectiveIconButtonTheme, - child: leading + final IconButtonThemeData effectiveIconButtonTheme; + + // This comparison is to check if there is a custom [overallIconTheme]. If true, it means that no + // custom [overallIconTheme] is provided, so [iconButtonTheme] is applied. Otherwise, we generate + // a new [IconButtonThemeData] based on the values from [overallIconTheme]. If [iconButtonTheme] only + // has null values, the default [overallIconTheme] will be applied below by [IconTheme.merge] + if (overallIconTheme == defaults.iconTheme) { + effectiveIconButtonTheme = iconButtonTheme; + } else { + // The [IconButton.styleFrom] method is used to generate a correct [overlayColor] based on the [foregroundColor]. + final ButtonStyle leadingIconButtonStyle = IconButton.styleFrom( + foregroundColor: overallIconTheme.color, + iconSize: overallIconTheme.size, + ); + + effectiveIconButtonTheme = IconButtonThemeData( + style: iconButtonTheme.style?.copyWith( + foregroundColor: leadingIconButtonStyle.foregroundColor, + overlayColor: leadingIconButtonStyle.overlayColor, + iconSize: leadingIconButtonStyle.iconSize, ) ); } + leading = IconButtonTheme( + data: effectiveIconButtonTheme, + child: leading is IconButton ? Center(child: leading) : leading, + ); + // Based on the Material Design 3 specs, the leading IconButton should have // a size of 48x48, and a highlight size of 40x40. Users can also put other // type of widgets on leading with the original config. diff --git a/packages/flutter/test/material/app_bar_test.dart b/packages/flutter/test/material/app_bar_test.dart index 73aa1d12f7b4..a48f06b84b30 100644 --- a/packages/flutter/test/material/app_bar_test.dart +++ b/packages/flutter/test/material/app_bar_test.dart @@ -3235,6 +3235,39 @@ void main() { expect(actionIconButtonSize(), 30.0); }); + testWidgets('AppBar.iconTheme should override any IconButtonTheme present in the theme for widgets containing an iconButton - M3', (WidgetTester tester) async { + final ThemeData themeData = ThemeData( + iconButtonTheme: IconButtonThemeData( + style: IconButton.styleFrom( + foregroundColor: Colors.red, + iconSize: 32.0, + ), + ), + useMaterial3: true, + ); + + const IconThemeData overallIconTheme = IconThemeData(color: Colors.yellow, size: 30.0); + await tester.pumpWidget( + MaterialApp( + theme: themeData, + home: Scaffold( + appBar: AppBar( + iconTheme: overallIconTheme, + leading: BackButton(onPressed: () {}), + title: const Text('title'), + ), + ), + ), + ); + + Color? leadingIconButtonColor() => iconStyle(tester, Icons.arrow_back)?.color; + double? leadingIconButtonSize() => iconStyle(tester, Icons.arrow_back)?.fontSize; + + expect(leadingIconButtonColor(), Colors.yellow); + expect(leadingIconButtonSize(), 30.0); + + }); + testWidgets('AppBar.actionsIconTheme should override any IconButtonTheme present in the theme - M3', (WidgetTester tester) async { final ThemeData themeData = ThemeData( iconButtonTheme: IconButtonThemeData( @@ -3275,6 +3308,40 @@ void main() { expect(actionIconButtonSize(), 30.0); }); + testWidgets('AppBar.actionsIconTheme should override any IconButtonTheme present in the theme for widgets containing an iconButton - M3', (WidgetTester tester) async { + final ThemeData themeData = ThemeData( + iconButtonTheme: IconButtonThemeData( + style: IconButton.styleFrom( + foregroundColor: Colors.red, + iconSize: 32.0, + ), + ), + useMaterial3: true, + ); + + const IconThemeData actionsIconTheme = IconThemeData(color: Colors.yellow, size: 30.0); + await tester.pumpWidget( + MaterialApp( + theme: themeData, + home: Scaffold( + appBar: AppBar( + actionsIconTheme: actionsIconTheme, + title: const Text('title'), + actions: [ + BackButton(onPressed: () {}), + ], + ), + ), + ), + ); + + Color? actionIconButtonColor() => iconStyle(tester, Icons.arrow_back)?.color; + double? actionIconButtonSize() => iconStyle(tester, Icons.arrow_back)?.fontSize; + + expect(actionIconButtonColor(), Colors.yellow); + expect(actionIconButtonSize(), 30.0); + }); + testWidgets('The foregroundColor property of the AppBar overrides any IconButtonTheme present in the theme - M3', (WidgetTester tester) async { final ThemeData themeData = ThemeData( iconButtonTheme: IconButtonThemeData(