Flutter: Change font family in ThemeData with .copyWith - flutter

I know that you can define a new ThemeData object with your own font like this:
ThemeData(fontFamily: 'Roboto')
However, I want to copy an existing ThemeData by using the copyWith method:
ThemeData.dark().copyWith(...)
Sadly, there is no argument fontFamiliy in copyWith. I only want to change the fontFamily and not define an entirely new TextTheme.
How do I copy an existing ThemeData and change its font familiy?

Try something like this:
ThemeData darkTheme = ThemeData.dark().copyWith(
textTheme: ThemeData.dark().textTheme.apply(
fontFamily: 'Roboto',
),
primaryTextTheme: ThemeData.dark().textTheme.apply(
fontFamily: 'Roboto',
),
);
If you look at the sources, it's the same thing:
This is about the same thing: https://github.com/flutter/flutter/issues/41276
I don't know why exactly you needed to copy font, but sometimes it makes sense to set fontFamily in theme MaterialApp. About this there is in: Changing the font family in Flutter when using ThemeData.dark() or ThemeData.light()

Related

Flutter app bar background color from seed not working

I am developing one app in Flutter. In this, I am trying to use useMaterial3 in ThemeData. So I used below code to set color in colorScheme.
static ThemeData lightThemeData = ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.red,
),
appBarTheme: AppBarTheme(
centerTitle: true,
elevation: 2,
titleTextStyle: textTheme.titleLarge,
),
);
I have assigned above lightThemeData in Main.dart to theme property. AppBar not showing proper color when I run the app. Please check below screenshot.
It is not showing proper Red Color. Anyone know, why this is happening?
Flutter version: 3.0.1
Note: It is working on Flutter v2.10.5 but not on 3.0.1
You can use something like this for the full red experience:
static ThemeData lightThemeData = ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.red,
primary: Colors.red,
secondary: Colors.red,
),
appBarTheme: AppBarTheme(
color: Colors.red,
//other options
),
);
Alternatively you can use fromSwatch like this:
static ThemeData lightThemeData = ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.red),
appBarTheme: AppBarTheme(
color: Colors.red,
//other options
),
);
But make sure to test every part of your app before using it because the documentation says:
For historical reasons, instead of using a [colorSchemeSeed] or [colorScheme], you can provide either a [primaryColor] or [primarySwatch] to construct the [colorScheme], but the results will not be as complete as when using generation from a seed color.
I think fromSwatch is designed for Material Design 2.
Following contains an external tool:
For the absolute control over the colors there is a nice tool at https://m3.material.io/theme-builder#/custom
From the left bar choose your colors, and export the result using the top right button(there is a Flutter option). Downloaded file contains the full schemes. You can override the colors you don't like and feed into the theme directly.
The seed color is used directly to create the tonal palette for primary tones. The ColorScheme.primary is then assigned tone 40 for light mode and tone 80 for dark mode, from the same tonal palette. Neither of these colors will be an exact match for the "primary" seed color you used, it will be a color from a tonal palette that matches the seed color, since it is the primary one.
Branding challange
If you for branding purposes require it to exactly match the provided seed color, you can always override ColorScheme.primary you got with copyWith using the original seed color. And then use that ColorScheme as input to your apps ThemeData. A bit of an extra step, but it will work and look OK too, because for primaries the other colors will still match and be in sync with this color.

Changing the font family in Flutter when using ThemeData.dark() or ThemeData.light()

I'm trying to set the font of my MaterialApp. Since I'm using the dark theme, I'd like to just use copyWith and then change the fontFamily. However, copyWith doesn't have an option to change the fontFamily.
MaterialApp(
theme: ThemeData.dark().copyWith(
fontFamily: 'MyFontFamily',
),
The named parameter 'fontFamily' isn't defined.
How do I keep the dark theme but also change the font family? (Same problem with ThemeData.light().)
I found a solution and am posting below.
If you look at the source code for ThemeData.light() and ThemeData.dark(), you can see that all it does is set the brightness value:
/// A default light blue theme.
///
/// This theme does not contain text geometry. Instead, it is expected that
/// this theme is localized using text geometry using [ThemeData.localize].
factory ThemeData.light() => ThemeData(brightness: Brightness.light);
/// A default dark theme with a teal secondary [ColorScheme] color.
///
/// This theme does not contain text geometry. Instead, it is expected that
/// this theme is localized using text geometry using [ThemeData.localize].
factory ThemeData.dark() => ThemeData(brightness: Brightness.dark);
That means to solve your problem you don't need to bother with ThemeData.light() or ThemeData.dark(). Just create a new ThemeData and set the brightness yourself in addition to the fontFamily:
MaterialApp(
theme: ThemeData(
brightness: Brightness.dark,
fontFamily: 'MyFontFamily',
),
Since, all you're doing is setting the brightness, I think the easier way would be to just use DefaultTextStyle.
DefaultTextStyle(
style: TextStyle(
fontFamily: 'YourFontFamily',
),
child: YourWidget(),
)

Change text-color of validation messages in Flutter

I want to change the color of the text which is returned when validating a TextFormField. In the following example both the error text and the border of the FormField are red.
I want blue for both of them. I tried to override this in ThemeData with something like
class MyThemes {
static final darkTheme = ThemeData(
errorColor: Color(0xFFFE7C7C),
With this the color of the border of the TextFormField changes, but not the color of the validation text ("Please enter name of book") still is the default red:
So the errorColor property does not do what I want.
Unfortunately I cannot access e.g. the errorStyle property from ThemeData.
Perhaps the most easy thing would be to change the default color of the error messages. But I don't know where this is defined.
Also any other approach is appreciated - thanks in advance!
if you want to theme formfield do it this way
ThemeData(
inputDecorationTheme: const InputDecorationTheme(
errorStyle: TextStyle(color: Colors.blue),
),
);

Does Flutter support cascading styles?

I want to be able to set a default text style which I can use across my app and then overwrite part of that style in specific circumstances. React Native supports this, does Flutter support it too please? Or if not, how can I achieve something like this?
Example of how I'd hope this would work:
style.dart:
ThemeData appTheme() {
return ThemeData(
...
textTheme: TextTheme(
headline1: TextStyle(fontSize: 26.0, fontWeight: FontWeight.bold),
...
)
)
}
body.dart:
Text('My text here', style: [TextStyle(color: myColorVariable), themeData.textTheme.headline1])
Many thanks!
You can use
Theme.of(context).textTheme.copyWith()
or even
Theme.of(context).textTheme.subtitle1.copyWith()
to change the default for a specific text widget.

Add custom property to ThemeData in Flutter

I need to change color of a widget based on theme. I have separate ThemeData for light and dark theme. Now is it possible to add a custom property to ThemeData so that I can change the color of the widget based on theme and using that custom property?
Sadly, it appears that you simply can't - and the Flutter team doesn't seem to be interested in adding this, given their suggestion.
I think this is a major flaw, because we can't benefit from Theme.of(context) to automatically update all of our Widget that consume this ThemeData.
While some may say that you can use extensions to add new properties, you effectively won't know how to differ between multiple ThemeData (unless you can use some properties like Brightness, but I think this is just too hacky and not reliable to do so).
The alternative is to create another InheritedWidget (just like they said in the issue mentioned above) to handle your custom theme properties.
Edit: It seems that a new PR has introduced the possibility to extend the ThemeData, but it hasn't landed in main or even stable yet.
Flutter has recenty introduced ThemeExtensions (thanks #guilherme-matuella for the PR link!)
You can get a pretty good idea on how to use the functionality by following examples from the main Flutter repo:
return MaterialApp(
title: MyApp._title,
theme: ThemeData.light().copyWith(
extensions: <ThemeExtension<dynamic>>[
const MyColors(
brandColor: Color(0xFF1E88E5),
danger: Color(0xFFE53935),
),
],
),
darkTheme: ThemeData.dark().copyWith(
extensions: <ThemeExtension<dynamic>>[
const MyColors(
brandColor: Color(0xFF90CAF9),
danger: Color(0xFFEF9A9A),
),
],
),
themeMode: isLightTheme ? ThemeMode.light : ThemeMode.dark,
home: Home(
isLightTheme: isLightTheme,
toggleTheme: toggleTheme,
),
);
Which you can later retrieve in your widget like so:
final MyColors myColors = Theme.of(context).extension<MyColors>();
Instead of adding custom property, we can extend ThemeData by extension function. For example, if we need a custom property for color, we can add extension function on ColorScheme. Color dependencies are now moved to Themedata.
// checking brightness to support dynamic themeing
extension CustomColorSchemeX on ColorScheme {
Color get smallBoxColor1 =>
brightness == Brightness.light ? Colors.blue : Colors.grey[400];
}
And then access that property through Theme.of(context)...
Container(
decoration: BoxDecoration(
border: Border.all(
color: Theme.of(context)
.colorScheme
.smallBoxColor1),
),