Hi, 我是鱼板伯爵今天要教如何利用Theme结合Bloc来切换主题配色,教学内容只会撷取片段程序码,建议大家搭配完整程序码来练习。
使用Theme可以定义整个应用的主题,也可以使用元件来定义应用程序特定部分的颜色和字体样式,例如 AppBars、按钮、设置背景颜色和字体样式等。
MaterialApp(
title: appName,
theme: ThemeData(
brightness: Brightness.dark,
primaryColor: Colors.amber,
accentColor: Colors.accents,
),
home: Home(),
);
bloc: ^7.1.0
flutter_bloc: ^7.1.0
equatable: ^2.0.3
在做主题切换前先来创建一个深色与浅色主题的颜色,利用上一篇day19的shared设定的颜色来做主题颜色。
import 'package:flutter/material.dart';
import 'package:stunning_tribble/shared/colors.dart';
class AppThemeData {
static ThemeData darkMode = ThemeData(
brightness: Brightness.dark,
backgroundColor: oil6Color,
primaryColorDark: oil2Color,
primaryColorLight: oil5Color,
textTheme: TextTheme(
bodyText1: TextStyle(
fontSize: 80.0,
color: oil2Color,
fontWeight: FontWeight.bold,
),
),
);
static ThemeData lightMode = ThemeData(
brightness: Brightness.light,
backgroundColor: oil2Color,
primaryColorDark: oil2Color,
primaryColorLight: oil5Color,
textTheme: TextTheme(
bodyText1: TextStyle(
fontSize: 80.0,
color: oil5Color,
fontWeight: FontWeight.bold,
),
),
);
}
完成主题配置後就可以来建造熟悉的Bloc,不熟的同学可以去看day13的教学。首先是事件,由於我会使用 switch 这个小部件切换深浅主题,这个部件会回传现在的状态是开还是关,所以下面我就把true和false直接传进去。
part of 'theme_bloc.dart';
abstract class ThemeEvent extends Equatable {
final bool isDark;
const ThemeEvent(this.isDark);
@override
List<Object> get props => [];
}
class ThemeChange extends ThemeEvent {
ThemeChange(bool isDark) : super(isDark);
}
传进去以後呢我希望他回传主题颜色和开关的状态,这样我们等等使用 BlocBuilder 的时候就可以改变UI和开关状态。
part of 'theme_bloc.dart';
class ThemeState extends Equatable {
final ThemeData themeData;
final bool isDark;
const ThemeState({
required this.isDark,
required this.themeData,
});
@override
List<Object> get props => [themeData, isDark];
}
在Bloc中就按照着切换主题流程把它写出来,当ThemeChange事件触发时,把目前开关状态传入,然後判断开关状态切换主题。
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:stunning_tribble/shared/theme.dart';
part 'theme_event.dart';
part 'theme_state.dart';
class ThemeBloc extends Bloc<ThemeEvent, ThemeState> {
ThemeBloc()
: super(ThemeState(themeData: AppThemeData.darkMode, isDark: true));
@override
Stream<ThemeState> mapEventToState(
ThemeEvent event,
) async* {
if (event is ThemeChange) {
yield* _mapThemeChangeToState(event.isDark);
}
}
Stream<ThemeState> _mapThemeChangeToState(bool _isDark) async* {
if (_isDark) {
yield ThemeState(themeData: AppThemeData.darkMode, isDark: true);
} else {
yield ThemeState(themeData: AppThemeData.lightMode, isDark: false);
}
}
}
首先创建刚刚写好的ThemeBloc。
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await ConfigReader.initializeApp(Environment.dev);
runApp(
MultiBlocProvider(
providers: [
BlocProvider(
create: (context) => ThemeBloc(),
),
],
child: MyApp(),
),
);
}
接着利用BlocBuilder来查看themeData的状态。
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocBuilder<ThemeBloc, ThemeState>(
builder: (context, state) {
return MaterialApp(
debugShowCheckedModeBanner: ConfigReader.config().DEBUG,
title: 'Flutter Demo',
theme: state.themeData,
darkTheme: ThemeData(),
home: HomeScreen(),
);
},
);
}
}
最後把我们的按钮加入事件,你就可以切换主题罗!
class SwtichModeButton extends StatelessWidget {
const SwtichModeButton({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocBuilder<ThemeBloc, ThemeState>(
builder: (context, state) {
return Switch(
inactiveThumbColor: Theme.of(context).primaryColorLight,
activeColor: Theme.of(context).primaryColorDark,
value: state.isDark,
onChanged: (isDark) {
BlocProvider.of<ThemeBloc>(context).add(ThemeChange(isDark));
},
);
},
);
}
}
本次的主题切换顺便帮大家复习一下Bloc的用法。
<<: 每个人都该学的30个Python技巧|技巧 20:Python容器—集合(set)(字幕、衬乐、练习)
学习动机与目标: 和身边对程序有兴趣的朋友聊一些程序相关问题时,其中最常遇到的就是Python,但是...
重复使用 TCP 连线 本篇章请搭配以下一起服用: HTTP - 复习传送门 TCP / UDP -...
google一下:ISO 27001 附录A 会找到蛮多行业的应用~一直换关键字~有助於理解不懂的地...
IMPORT csv LOAD DATA INFILE 'test.csv' INTO TABLE ...
前言 很快的时间来到了28天 首先先讲结论 很可惜的我们团队挑战失败了 虽然前几天依旧还是有写文章 ...