Dark Mode
Setting Up Light/Dark Mode and Fonts in a Flutter App
Setting Up Light/Dark Mode
The theme mode will be divided into three options:
Light Mode
Dark Mode
System Mode (which follows the system settings)
However, the actual UI will only display two primary modes: Light and Dark.
extension MyThemeModeContext on BuildContext {
bool get isDarkMode => switch (myThemeMode) {
ThemeMode.system => MediaQuery.of(this).platformBrightness == Brightness.dark,
ThemeMode.light => false,
ThemeMode.dark => true,
};
}
Creating a Global Variable to Manage Themes
We will define a global variable to manage the application's theme:
ThemeMode myThemeMode = ThemeMode.system;
Handling Theme Persistence
A common issue with this approach is that the theme setting will not persist after the app is completely closed. There are several solutions to this problem:
Using
shared_preferences
– A package that allows saving and retrieving values when initializing the app. Learn more here.Storing the Theme in a BLoC State – This ensures that the theme is managed within the state management logic.
Example of storing the theme in a Bloc
:
myThemeMode = context.select((SettingBloc bloc) => bloc.state.settingWeb.theme);
For more details on how to persist values using BLoC, check out my article on the topic here.
BlocApplying Light and Dark Themes in the UI
Defining Theme-Specific Colors
Each theme (light and dark) has its own set of colors. We can determine which color to use based on the theme mode.
extension WebColorContext on BuildContext {
Color get white => isDarkMode ? WebColor.blackForDark : WebColor.white;
}
How to Use
context.white
Handling context
Accessibility
One potential issue with this approach is that context
is required to access theme-specific colors, which may not always be convenient.
I have a simple way to access context
from anywhere in the project. Check out my article for more details:
Switching Between Light and Dark Themes
To change the theme mode, use the following code:
myThemeMode = ThemeMode.light;
await WidgetsFlutterBinding.ensureInitialized().performReassemble();
The second line forces the entire application to redraw the screen, ensuring the theme change is applied immediately.
Light and Dark Themes with Custom Fonts
Fonts play a crucial role in UI design. Currently, I use two methods to add custom fonts to my Flutter applications.
Method 1: Adding Fonts from Asset Files
Define a TextStyle
using a custom font stored in the assets
folder:
static const _neoTextStyle = TextStyle(
fontFamily: WebFontFamily.nanumSquareNeo,
fontFamilyFallback: [
WebFontFamily.pretendard,
],
package: 'dsg_ui_core', // Loading the font from a package
height: 1.5,
leadingDistribution: TextLeadingDistribution.even,
);
You can include fonts in your pubspec.yaml
and reference them in the TextStyle
. If using fonts from a package, ensure you specify the package
argument correctly.
Method 2: Using Google Fonts
If your desired font is available on Google Fonts, you can use it directly with the google_fonts
package:
static final _webTextStyle = GoogleFonts.inter().copyWith(
fontWeight: FontWeight.w600,
height: 1.5,
leadingDistribution: TextLeadingDistribution.even,
);
Handling Font Scaling for Different Screen Sizes
When the screen size changes, fonts should scale proportionally to maintain design consistency. One way to achieve this is by defining a ratio based on the screen width:
double get webRatio {
final width = MediaQuery.of(this).size.width;
final ratio = width / 1440;
return ratio < 1 ? (ratio < 0.75 ? 0.75 : ratio) : 1;
}
Applying Scaled Font Styles from Figma Design
Once we have the ratio, we can create text styles dynamically:
TextStyle get h46B => _webTextStyle.copyWith(
fontSize: 46 * webRatio,
fontWeight: FontWeight.w700,
color: neutral80,
);
This approach ensures your fonts scale properly across different devices, keeping your UI responsive and visually consistent.
Method 2: Using the google_fonts
Library
google_fonts
LibraryYou can use the google_fonts
package if your desired font is available on Google Fonts.
static final _webTextStyle = GoogleFonts.inter().copyWith(
fontWeight: FontWeight.w600,
height: 1.5,
leadingDistribution: TextLeadingDistribution.even,
);
Handling Font Scaling for Different Screen Sizes
A common issue when changing screen sizes is that fonts need to scale proportionally to maintain a harmonious design.
In this case, I use a ratio based on the screen width. This is calculated by taking the current screen width and dividing it by the original design width (e.g., 1440px in Figma).
double get webRatio {
final width = MediaQuery.of(this).size.width;
final ratio = width / 1440;
return ratio < 1 ? (ratio < 0.75 ? 0.75 : ratio) : 1;
}
Applying Scaled Font Styles from Figma Design
Once we have the scaling ratio, we can create text styles dynamically based on the design specifications:
TextStyle get h46B => _webTextStyle.copyWith(
fontSize: 46 * webRatio,
fontWeight: FontWeight.w700,
color: neutral80,
);
Full Code Overview
extension WebTextStyle on BuildContext{
/*static const _neoTextStyle = TextStyle(
fontFamily: WebFontFamily.nanumSquareNeo,
fontFamilyFallback: [
WebFontFamily.pretendard,
],
package: 'dsg_ui_core', // Thêm thư viện front chữ từ package: https://api.flutter.dev/flutter/painting/TextStyle-class.html#:~:text=To%20use%20a%20font%20family%20defined%20in%20a%20package%2C%20the%20package%20argument%20must%20be%20provided.%20For%20instance%2C%20suppose%20the%20font%20declaration%20above%20is%20in%20the%20pubspec.yaml%20of%20a%20package%20named%20my_package%20which%20the%20app%20depends%20on.%20Then%20creating%20the%20TextStyle%20is%20done%20as%20follows%3A
height: 1.5,
leadingDistribution: TextLeadingDistribution.even,
); */
static final _webTextStyle = GoogleFonts.inter().copyWith(
fontWeight: FontWeight.w600,
height: 1.5,
leadingDistribution: TextLeadingDistribution.even,
);
/// Edit ratio of fontSize for responsive screen
double get webRatio {
final width = MediaQuery.of(this).size.width;
final ratio = width / 1440;
return ratio < 1 ? ratio < 0.75 ? 0.75 : ratio : 1;
}
/// Heading
TextStyle get h46B =>
_webTextStyle.copyWith(
fontSize: 46 * webRatio,
fontWeight: FontWeight.w700,
color: white,
);
}
Usage Example
You can apply the text styles as follows:
Text("Hello", style: context.h46B)
Customizing Styles with Colors
You can fully customize styles according to your design system. Here’s an example of modifying the text color dynamically:
Text("Hello", style: context.b10B.copyWith(
color: context.white,
))
With this setup, when the light/dark mode changes, the text color will automatically adapt based on the selected theme.
This concludes my guide on setting up light/dark mode in Flutter. You can explore more about creating a UI package at
Core UILast updated