Theme Switching with Bloc and RxDart In Flutter
Themes, are a topic people often talk about while making apps the most commonly used term regarding this topic would be ‘dark theme’, You can often see people asking how to manage a dark theme in your application or even going as far as asking how to manage different icons for different themes.
One such incident of managing themes happened to me when I was asked to manage 2 separate theme modes based on user preferences. So, I would like to share with everyone how I managed it at that time, hope everyone enjoys following along.
First things first let me brief you about this a little, In this, we will be managing 2 themes first one will be ‘red’ and the second one is called ‘blue’. On user selection the theme would completely change on every screen even icons and background images, So to further progress with this I suggest making 2 folders.
We are going to name the first folder as Red and the second one Blue respectively and put all our icons and background images inside of them.
Now we are done with the basic setup, it’s time to move on to the coding part of it. First of all, we will create an enum that will help us manage our themes
enum Mode { red, blue }
Alright, now we will work on our stream part for this. First of all, we will create a new file and call it theme_bloc_state.dart
part of 'theme_bloc_cubit.dart';
abstract class ThemeSwitchBloc {}
class ThemeInitial extends ThemeSwitchBloc {}
Secondly, we will create the theme_bloc_cubit.dart file
import 'dart:async';
import 'package:bloc/bloc.dart';
part 'theme_bloc_state.dart';
class ThemeBlocCubit extends Cubit<ThemeSwitchBloc> {
ThemeBlocCubit() : super(ThemeInitial());
final _themeController = BehaviorSubject<Mode>();
Stream<Mode> get themeStream => _themeController.stream;
dynamic switchTheme(Mode mode) async {
if (mode != Mode.red) {
_themeController.sink.add(mode);
return Mode.friendship;
} else {
_themeController.sink.add(mode);
return Mode.blue;
}
}
}
Note: You can learn more about behavior subjects over here
Moving onto, now we will be looking at switching the theme itself, but before that, we got to create a function that will return to us the current theme’s colors and the current theme’s icons path
So we will create 2 globally accessible functions inside our UiHelper class
Function 1 :
static Color getColor({
required Mode? themeMode,
}) {
var _color = Colors.red;
switch (themeMode) {
case Mode.blue:
_color = Colors.blue;
break;
case Mode.red:
_color = Colors.red;
break;
default:
break;
}
return _color;
}
This function will return to us the color for the theme, you can create even more functions that go into even more details as to what you may need
Function 2 :
static String getThemeIconPath({
required Mode? mode,
required String iconName,
}) {
var _iconPath = 'assets/red/';
if (mode != null) {
switch (mode) {
case Mode.blue:
_iconPath = 'assets/blue/';
break;
case Mode.red:
_iconPath = 'assets/red/';
break;
default:
break;
}
}
_iconPath = _iconPath + iconName;
return _iconPath;
}
The second function returns us the path for a particular icon. With this, we are now set to start with our changing of the theme. So, here is the shortcode for setting up a way to change the theme, I am using radio buttons for this :
var _radioSelected = Mode.red;StreamBuilder(
stream: _themeCubit?.themeStream,
builder: (context, snapshot) {
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Radio(
value: Mode.red,
groupValue: _radioSelected,
activeColor: Colors.blue,
onChanged: (dynamic value) async {
_changedOptions(value);
},
),
Text('Red'),
],
),
Row(
children: [
Radio(
value: Mode.blue,
groupValue: _radioSelected,
activeColor: Colors.blue,
onChanged: (dynamic value) async {
_changedOptions(value);
},
),
Text('Blue'),
],
),
Container(),
],
);
}),
The basic working is that when you click on the radio button, it will now update the value of our themeStream and similarly update the value of _radioSelected, which will allow new values to be returned in our getColor and getThemeIconPath functions.
The function to do so is:
void _changedOptions(value) async {
_radioSelected = _themeCubit?.switchTheme(value);
_radioSelected = value;
}
With this, we can finally change the theme whenever we want, now to look at the effect of theme changing we once again have to use a stream builder to read our from our stream :
StreamBuilder<Mode>(
stream: _themeCubit?.themeStream,
builder: (context, snapshot) {
return Container(
width: double.maxFinite,
padding: EdgeInsets.symmetric(horizontal: 20),
color: UIHelper.getColor(themeMode: snapshot.data),
child: Center(
child: Image.asset(UIHelper.getThemeIconPath(
mode: snapshot.data,
iconName: IconConstants.alarm),),
),
);
})
With this we can see the color changing, as every time we will switch the theme, it will return the new icon path and the new color, the default values are taken in the UiHelper function to make sure a value is always returned and we never encounter a null value.
This was but a simple example of how switching themes with rxDart and Bloc Cubit works if your objective was to change even the icons on the flip of a switch this method certainly works.
If you are facing any problems in the future implementing this, feel free to reach out to me, I would be happy to help.
I know this tutorial was a short one but it felt refreshing to come up with a way when someone asked me how do I change all the icons in an app with the flip of a button, I enjoyed implementing and writing about it, I hope everyone reading this also enjoys implementing it, If there are some better ways to achieve the same available please do let me know of those as well, I would love to look into them.
❤ ❤ Thanks for reading this article ❤❤
If I got something wrong? Let me know in the comments. I would love to improve.
Clap 👏 If this article helps you.
Feel free to connect with us:
And read more articles from FlutterDevs.com.
FlutterDevs team of Flutter developers to build high-quality and functionally-rich apps. Hire a flutter developer for your cross-platform Flutter mobile app project on an hourly or full-time basis as per your requirement! You can connect with us on Facebook, GitHub, Twitter, and LinkedIn for any flutter-related queries.
We welcome feedback and hope that you share what you’re working on using #FlutterDevs. We truly enjoy seeing how you use Flutter to build beautiful, interactive web experiences.