-
Notifications
You must be signed in to change notification settings - Fork 29.8k
Description
Steps to reproduce
When you theme or style a FilledButton.icon, ElevatedButton.icon, OutlinedButton.icon, TextButton.icon or a SegmentedButton with icons, and give them a foreground color, the text color and the used icon color both use the specified foreground color.
This was the case in all versions prior to Flutter 3.27.0.
In Flutter 3.27.0 and later, all the way to latest master version, this is no longer the case. The styling and theming is broken and the icon color keep default colors.
To get the correct and same color that you got in previous versions, you have to explicitly set the icon color in versions 3.27.0 and later. In versions before, if icon color was not specified and foreground was specified, the icon color used the same specified foreground color.
There is no mentioned of this radically breaking change in the Flutter 3.27.0 release notes, the new behavior is a bug. This bug caused icon color breaking changes in a production app with millions of users.
Expected results
When theming and styling FilledButton.icon, ElevatedButton.icon, OutlinedButton.icon, TextButton.icon or a SegmentedButton with icons and specifying only foreground color:
EXPECT the icon to use the same color.
The above CORRECT and EXPECTED result is obtained with Flutter 3.24.5 and earlier stable versions.
Actual results
When theming and styling FilledButton.icon, ElevatedButton.icon, OutlinedButton.icon, TextButton.icon or a SegmentedButton with icons and specifying only foreground color,
ACTUAL result is that the icon uses default colors.
The above INCORRECT and ACTUAL result is obtained with Flutter 3.27.x and later versions all the way up to latest master.
Code sample
Code sample
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
final ButtonStyle filledButtonStyle = FilledButton.styleFrom(
foregroundColor: Colors.red,
backgroundColor: Colors.grey,
);
final ButtonStyle elevatedButtonStyle = ElevatedButton.styleFrom(
foregroundColor: Colors.orange.shade600,
backgroundColor: Colors.blueGrey,
);
final ButtonStyle outlinedButtonStyle = OutlinedButton.styleFrom(
foregroundColor: Colors.lightBlue,
);
final ButtonStyle textButtonStyle = TextButton.styleFrom(
foregroundColor: Colors.green,
);
final ButtonStyle segmentedButtonStyle = SegmentedButton.styleFrom(
selectedForegroundColor: Colors.tealAccent.shade700,
);
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: const HomePage(),
theme: ThemeData(
filledButtonTheme: FilledButtonThemeData(
style: filledButtonStyle,
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: elevatedButtonStyle,
),
outlinedButtonTheme: OutlinedButtonThemeData(
style: outlinedButtonStyle,
),
textButtonTheme: TextButtonThemeData(
style: textButtonStyle,
),
segmentedButtonTheme: SegmentedButtonThemeData(
style: segmentedButtonStyle,
),
),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Button Icon Color Issue')),
body: Center(
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FilledButton.icon(
label: const Text('Filled Themed'),
icon: const Icon(Icons.add),
onPressed: () {},
),
const SizedBox(width: 8),
FilledButton.icon(
style: filledButtonStyle.copyWith(
foregroundColor: WidgetStateProperty.all(Colors.yellow),
),
label: const Text('Filled Styled'),
icon: const Icon(Icons.add),
onPressed: () {},
),
],
),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton.icon(
label: const Text('Elevated Themed'),
icon: const Icon(Icons.add),
onPressed: () {},
),
const SizedBox(width: 8),
ElevatedButton.icon(
style: elevatedButtonStyle.copyWith(
foregroundColor: WidgetStateProperty.all(Colors.lime),
),
label: const Text('Elevated Styled'),
icon: const Icon(Icons.add),
onPressed: () {},
),
],
),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
OutlinedButton.icon(
label: const Text('Outlined Themed'),
icon: const Icon(Icons.add),
onPressed: () {},
),
const SizedBox(width: 8),
OutlinedButton.icon(
style: outlinedButtonStyle.copyWith(
foregroundColor: WidgetStateProperty.all(Colors.deepOrange),
),
label: const Text('Outlined Styled'),
icon: const Icon(Icons.add),
onPressed: () {},
),
],
),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextButton.icon(
label: const Text('Text Themed'),
icon: const Icon(Icons.add),
onPressed: () {},
),
const SizedBox(width: 8),
TextButton.icon(
style: textButtonStyle.copyWith(
foregroundColor: WidgetStateProperty.all(Colors.pink),
),
label: const Text('Text Styled'),
icon: const Icon(Icons.add),
onPressed: () {},
),
],
),
const SizedBox(height: 8),
const SegmentedButtonShowcase(),
],
),
),
);
}
}
class SegmentedButtonShowcase extends StatefulWidget {
const SegmentedButtonShowcase({this.showOutlinedButton, super.key});
final bool? showOutlinedButton;
@override
State<SegmentedButtonShowcase> createState() =>
_SegmentedButtonShowcaseState();
}
enum Calendar { day, week, month, year }
class _SegmentedButtonShowcaseState extends State<SegmentedButtonShowcase> {
Calendar _selected = Calendar.day;
@override
Widget build(BuildContext context) {
return SegmentedButton<Calendar>(
segments: const <ButtonSegment<Calendar>>[
ButtonSegment<Calendar>(
value: Calendar.day,
label: Text('Day'),
icon: Icon(Icons.calendar_view_day),
),
ButtonSegment<Calendar>(
value: Calendar.week,
icon: Icon(Icons.calendar_view_week),
label: Text('Week'),
),
ButtonSegment<Calendar>(
value: Calendar.month,
icon: Icon(Icons.calendar_view_month),
label: Text('Mont'),
),
ButtonSegment<Calendar>(
value: Calendar.year,
icon: Icon(Icons.calendar_today),
label: Text('Year'),
),
],
selected: <Calendar>{_selected},
onSelectionChanged: (Set<Calendar> selected) {
setState(() {
_selected = selected.first;
});
},
);
}
}
Flutter Doctor output
Doctor output
flutter doctor -v
[✓] Flutter (Channel master, 3.29.0-1.0.pre.281, on macOS 15.3 24D60 darwin-arm64, locale en-US) [1,763ms]
• Flutter version 3.29.0-1.0.pre.281 on channel master at /Users/rydmike/fvm/versions/master
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 1b095a030d (2 hours ago), 2025-02-06 12:11:37 -0800
• Engine revision 1b095a030d
• Dart version 3.8.0 (build 3.8.0-70.0.dev)
• DevTools version 2.43.0
[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0) [1,720ms]
• Android SDK at /Users/rydmike/Library/Android/sdk
• Platform android-34, build-tools 34.0.0
• Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
This is the JDK bundled with the latest Android Studio installation on this machine.
To manually set the JDK path, use: `flutter config --jdk-dir="path/to/jdk"`.
• Java version OpenJDK Runtime Environment (build 17.0.9+0-17.0.9b1087.7-11185874)
• All Android licenses accepted.
[✓] Xcode - develop for iOS and macOS (Xcode 16.2) [951ms]
• Xcode at /Applications/Xcode.app/Contents/Developer
• Build 16C5032a
• CocoaPods version 1.16.2
[✓] Chrome - develop for the web [94ms]
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
[✓] Android Studio (version 2023.2) [93ms]
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 17.0.9+0-17.0.9b1087.7-11185874)
[✓] IntelliJ IDEA Community Edition (version 2024.3.1.1) [91ms]
• IntelliJ at /Applications/IntelliJ IDEA CE.app
• Flutter plugin version 83.0.4
• Dart plugin version 243.23177
[✓] VS Code (version 1.97.0) [11ms]
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 3.104.0
[✓] Connected device (3 available) [6.1s]
• MrPinkPro (wireless) (mobile) • 74120d6ef6769c3a2e53d61051da0147d0279996 • ios • iOS 17.7.2 21H221
• macOS (desktop) • macos • darwin-arm64 • macOS 15.3 24D60 darwin-arm64
• Chrome (web) • chrome • web-javascript • Google Chrome 132.0.6834.160
[✓] Network resources [691ms]
• All expected network resources are available.
• No issues found!Metadata
Metadata
Assignees
Labels
Type
Projects
Status

