主题适配最好在新建项目时就考虑到

主题适配涉及到动态切换,需要用到状态管理。本项目用的是Provider

flutter pub add provider

创建主题文件

首先,创建 lib/pages/theme 文件夹

定义白天主题样式,创建light_theme.dart

theme/light_theme.dart
import 'package:flutter/material.dart';

ThemeData lightMode = ThemeData(
useMaterial3: true,
appBarTheme: const AppBarTheme(
systemOverlayStyle: SystemUiOverlayStyle(
statusBarColor: Colors.transparent, // 去除状态栏遮罩
statusBarIconBrightness: Brightness.dark, // 状态栏图标字体颜色
systemNavigationBarColor: Colors.white, // 底部导航栏颜色
)
),
colorScheme: ColorScheme.light(
primary: Colors.lightBlue,
onPrimary: Colors.white,
secondary: Colors.grey.withOpacity(0.25),
tertiary: const Color(0xFFEE4667),
inversePrimary: Colors.grey.shade600,
inverseSurface: Colors.grey.shade200,
onInverseSurface: Colors.grey.shade100,
surfaceContainer: Colors.grey.shade300,
),
);

定义夜间主题样式,创建dark_theme.dart

theme/dark_theme.dart
import 'package:flutter/material.dart';

ThemeData darkMode = ThemeData(
useMaterial3: true,
appBarTheme: const AppBarTheme(
systemOverlayStyle: SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: Brightness.light,
systemNavigationBarColor: Color(0xff121212), // 和主背景surface保持一致
)
),
colorScheme: ColorScheme.dark(
primary: Colors.blueAccent,
onPrimary: Colors.white,
secondary: Colors.grey.withOpacity(0.25),
tertiary: const Color(0xFFEE4667),
inversePrimary: Colors.grey.shade600,
inverseSurface: Colors.black87,
onInverseSurface: Colors.black26,
surfaceContainer: Colors.grey.shade300,
),
);

状态管理

创建theme_provider.dart文件

theme/theme_provider.dart
import 'package:flutter/material.dart';
import 'package:e_book_demo/themes/dark_theme.dart';
import 'package:e_book_demo/themes/light_theme.dart';
import 'package:e_book_demo/utils/constants.dart';
import 'package:e_book_demo/utils/shared_prefs_utils.dart';

class ThemeProvider with ChangeNotifier {
ThemeMode _themeMode = ThemeMode.system;

ThemeData get darkTheme => darkMode;
ThemeData get lightTheme => lightMode;
ThemeMode get themeMode => _themeMode;

set themeMode(ThemeMode themeMode) {
_themeMode = themeMode;
notifyListeners();
}

init() async {
String tmpThemeMode =
await SharedPrefsUtils.getString(Constants.keyThemeMode, "system");
changeTheme(tmpThemeMode, notify: false);
}

void changeTheme(String themeName, {bool notify = true}) {
if (themeName == "dark") {
themeMode = ThemeMode.dark;
} else if (themeName == "system") {
themeMode = ThemeMode.system;
} else {
themeMode = ThemeMode.light;
}
if (notify) {
notifyListeners();
}
}
}

注册全局状态,修改main.dart

main.dart
import 'package:flutter/material.dart';
import 'package:e_book_demo/app.dart';
import 'package:e_book_demo/themes/theme_provider.dart';
import 'package:provider/provider.dart';

void main() {
WidgetsFlutterBinding.ensureInitialized();
ThemeProvider theme = ThemeProvider()..init();
runApp(
MultiProvider(
providers: [
// 主题
ChangeNotifierProvider<ThemeProvider>.value(value: theme)
],
child: const MyApp(),
),
);
}

注册主题,修改app.dart

注意,增加darkTheme后,主题会跟随系统,这时theme不再生效

app.dart
...
@override
Widget build(BuildContext context) {
return ScreenUtilInit(
designSize: designSize,
builder: (context, child) {
return MaterialApp(
title: 'Flutter Demo',
theme: Provider.of<ThemeProvider>(context).lightTheme,
darkTheme: Provider.of<ThemeProvider>(context).darkTheme,
themeMode: Provider.of<ThemeProvider>(context).themeMode,
debugShowCheckedModeBanner: false,
home: const RootScreen(),
);
},
);
}

使用颜色代码

主题配置好之后如何使用呢?

通过Theme.of(context).colorScheme.来指定颜色

import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';

class HomePage extends StatefulWidget {
const HomePage({super.key});

@override
State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0,
toolbarHeight: 0,
backgroundColor: Theme.of(context).colorScheme.surface,
surfaceTintColor: Theme.of(context).colorScheme.surface,
),
body: Center(
child: Text(
'Home',
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
fontSize: 18.r,
),
)),
);
}
}