I am trying to implement a showCupertinoModalBottomSheet for the theme selection of my app.
But while switching the theme, the overall app theme changes except for the current showCupertinoModalBottomSheet in which the themes are listed.
Is there a way to change it's colour dynamically?
Or is there any other Widget which can help me implement this?
text: 'Change theme',
onPressed: () => showCupertinoModalBottomSheet<Widget>(
context: context,
bounce: true,
expand: false,
backgroundColor: themeProvider.currentTheme == THEME_DARK
? Colors.grey[800]
: Colors.white,
builder: (BuildContext context) => _AppPersonalization()),
The showCupertinoModalBottomSheet widget was not found, but if you imported modal_bottom_sheet from pub.dev, the solution is ^^
backgroundColor: Theme.of(context).[primaryColor/accentColor...]
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
ValueNotifier<Brightness> brightness = new ValueNotifier(Brightness.light);
void main() {
runApp(ValueListenableBuilder(
valueListenable: brightness,
builder: (context, Brightness _brightness, _) {
return MaterialApp(
theme: _brightness == Brightness.dark ? ThemeData(
primaryColor: Colors.black,
brightness: Brightness.dark,
) : ThemeData(
primaryColor: Colors.white,
brightness: Brightness.light,
),
home: const HomePage()
);
}
)
);
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).primaryColor,
body: Center(
child: ElevatedButton(
child: Text('Change theme'),
onPressed: () {
brightness.value = brightness.value ==Brightness.light ? Brightness.dark : Brightness.light;
brightness.notifyListeners();
showMaterialModalBottomSheet<Widget>(
context: context,
builder: (_) => Container(height: 300,color: Theme.of(context).primaryColor),
).catchError((onError) => print("$onError"));
},
),
),
);
}
}
Related
I need to change background color of elevated button, on click to indicate it as selected. I have tried this.
class _MyState extends State<MyPage> {
bool _flag = true;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () => setState(() => _flag = !_flag),
child: Text(_flag ? 'Red' : 'Green'),
style: ElevatedButton.styleFrom(
backgroundColor: _flag ? Colors.red : Colors.teal,
),
),
),
);
}
}
Here on onPressed(): The color is not changing
On DartPad your code works Link to dartpad.
Be sure you implemented correctly the stateful widget:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({
Key? key,
}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool _flag = true;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () => setState(() => _flag = !_flag),
child: Text(_flag ? 'Red' : 'Green'),
style: ElevatedButton.styleFrom(
backgroundColor: _flag ? Colors.red : Colors.teal,
),
),
),
);
}
}
In my application, in the appBar, there is a button that should change the theme to dark. I need to create functionality Provider. How can this be implemented? I just need to change the Scaffold color to black and the text color to white.
My main.dart:
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
textTheme: const TextTheme(
headline1: TextStyle(fontSize: 50.0, fontWeight: FontWeight.bold),
headline5: TextStyle(fontSize: 36.0, fontStyle: FontStyle.italic),
subtitle2: TextStyle(fontSize: 10.0, color: Colors.black),
bodyText1: TextStyle(fontSize: 14.0, color: Colors.black),
),
),
home: const HomeScreen(),
);
}
My switch button:
appBar: AppBar(
title: const Text('Flutter theme config'),
centerTitle: true,
actions: [
IconButton(
onPressed: () {
},
icon: const Icon(Icons.dark_mode),
)
],
),
Theme provider:
class ThemeProvider extends ChangeNotifier {
}
You can try something like this :
First we provide our Provider globally for the whole application, and then in the attribute theme: we listen for the change.
** main **
void main() async {
runApp(
MultiProvider( // create the provider
providers: [
ChangeNotifierProvider(
create: (_) => ThemeProvider(),
)
],
child: const MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Material App',
initialRoute: HomeScreen.routerName,
routes: {
},
theme: Provider.of<ThemeProvider>(context).currentTheme, // listen to the current theme
);
}
}
In the provider we will only have two functions, one to switch to LightMode and the other to DarkMode, then we add it to the currentTheme variable which is the one that listens in the main
** ThemeProvider **
class ThemeProvider extends ChangeNotifier {
ThemeData? currentTheme;
setLightMode() {
currentTheme = ThemeData(
brightness: Brightness.light, // LightMode
scaffoldBackgroundColor: Colors.red,
[...] // more attributes
);
notifyListeners();
}
setDarkmode() {
currentTheme = ThemeData(
brightness: Brightness.dark, // DarkMode
scaffoldBackgroundColor: Colors.green,
[...] // more attributes
);
notifyListeners();
}
}
Finally we create a StatefulWidget to change the isDarkMode variable to call the provider
** Button Home **
class _HomeScreenState extends State<SettingsScreen> {
bool isDarkmode = false; // new variable
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Settings"),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: IconButton(
onPressed: () {
final themeProvider =
Provider.of<ThemeProvider>(context, listen: false); // get the provider, listen false is necessary cause is in a function
setState(() {
isDarkmode = !isDarkmode;
}); // change the variable
isDarkmode // call the functions
? themeProvider.setDarkmode()
: themeProvider.setLightMode();
},
icon: const Icon(Icons.dark_mode),
),
),
);
}
}
So I'm trying here to get the current theme, if it's light or dark.
So I can change widget color accordingly..
However, it doesn't work, I used if statment to know when it's dark mode..
but it's always False ..
This is the code.. btw it switch between dark & light theme..
but when i try to get current theme.. even if the theme changed to dark..
the if statments always show false...
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
bool darkModeOn = MediaQuery.of(context).platformBrightness == Brightness.dark;
Color containerColor;
if (darkModeOn == true) {
containerColor = Colors.blueGrey;
print("----------------");
print("dark mode ON");
print("----------------");
} else {
containerColor = Colors.deepPurple;
print("LIGHT mode ON");
}
return Scaffold(
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
//----switch theme---
currentTheme.switchTheme();
},
label: Text(
"Switch theme",
style: TextStyle(
),
),
icon: Icon(Icons.color_lens_outlined),
),
appBar: AppBar(
title: Text("DarkXLight"),
),
body: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(child: Container(
color: containerColor,
),
),
Expanded(child: Container(
color: Colors.amber,
),
),
],
),
),
);
}
}
You can't switch themes like that. You will need to handle the logic in the MaterialApp otherwise
MediaQuery.of(context).platformBrightness == Brightness.dark;
will always return true/false based on what was provided to the MaterialApp.themeMode.
Here's a sample code to get started. I used ValueListenableBuilder but you can also use provider.
Full code:
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
final ValueNotifier<ThemeMode> _notifier = ValueNotifier(ThemeMode.light);
#override
Widget build(BuildContext context) {
return ValueListenableBuilder<ThemeMode>(
valueListenable: _notifier,
builder: (_, mode, __) {
return MaterialApp(
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
themeMode: mode, // Decides which theme to show, light or dark.
home: Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () => _notifier.value = mode == ThemeMode.light ? ThemeMode.dark : ThemeMode.light,
child: Text('Toggle Theme'),
),
),
),
);
},
);
}
}
So, I was able to solve my problem..
I will put the code so if someone faced the same issue..
I simply, changed the way I used to switch themes. It was wrong..
However, here I'm posting the Correct way & this way solved the problem..
MAIN PAGE
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:practice_darkmode/theme_provider.dart';
import 'package:provider/provider.dart';
import 'MyHomePage.dart';
Future<void> main() async {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => ThemeProvider(),
builder: (context, _) {
final themeProvider = Provider.of<ThemeProvider>(context);
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: MyThemes.lightTheme,
darkTheme: MyThemes.darkTheme,
themeMode: themeProvider.themeMode,
home: MyHomePage(),
);
},
);
}
}
Theme Provider class
import 'package:flutter/material.dart';
//---This to switch theme from Switch button----
class ThemeProvider extends ChangeNotifier {
//-----Store the theme of our app--
ThemeMode themeMode = ThemeMode.dark;
//----If theme mode is equal to dark then we return True----
//-----isDarkMode--is the field we will use in our switch---
bool get isDarkMode => themeMode == ThemeMode.dark;
//---implement ToggleTheme function----
void toggleTheme(bool isOn) {
themeMode = isOn ? ThemeMode.dark : ThemeMode.light;
//---notify material app to update UI----
notifyListeners();
}
}
//---------------Themes settings here-----------
class MyThemes {
//-------------DARK THEME SETTINGS----
static final darkTheme = ThemeData(
scaffoldBackgroundColor: Colors.black45,
// colorScheme: ColorScheme.dark(),
);
//-------------light THEME SETTINGS----
static final lightTheme = ThemeData(
scaffoldBackgroundColor: Colors.white,
//colorScheme: ColorScheme.light(),
);
}
Change Theme button widget class ( this is to create a switch button)
import 'package:flutter/material.dart';
import 'package:practice_darkmode/theme_provider.dart';
import 'package:provider/provider.dart';
class ChangeThemeButtonWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
//----First we want to get the theme provider----
final themeProvider = Provider.of<ThemeProvider>(context);
return Switch.adaptive(
//---isDarkMode to return if its dark or not--true or false--
value: themeProvider.isDarkMode,
onChanged: (value) {
final provider = Provider.of<ThemeProvider>(context, listen: false);
provider.toggleTheme(value);
},
activeColor: themeProvider.isDarkMode ? Colors.purple : Colors.green,
);
}
}
Home Page
import 'package:flutter/material.dart';
import 'package:practice_darkmode/theme_provider.dart';
import 'package:provider/provider.dart';
import 'ChangeThemeButtonWidget.dart';
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
dynamic text;
dynamic textColor;
dynamic appBarColor;
dynamic btnColor;
dynamic appBarTextColor;
if (Provider.of<ThemeProvider>(context).themeMode == ThemeMode.dark) {
text = "IT'S DARK ";
textColor = Colors.cyanAccent;
appBarColor = Colors.black;
btnColor = Colors.deepPurple;
appBarTextColor = Colors.cyanAccent;
} else if (Provider.of<ThemeProvider>(context).themeMode == ThemeMode.light) {
text = "IT'S LIGHT ";
textColor = Colors.red;
appBarColor = Colors.red;
btnColor = Colors.red;
appBarTextColor = Colors.white;
}
return Scaffold(
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
},
label: Text(
"Switch theme",
style: TextStyle(
),
),
icon: Icon(Icons.color_lens_outlined),
backgroundColor: btnColor,
),
appBar: AppBar(
title: Text("DarkXLight", style: TextStyle(color: appBarTextColor),),
backgroundColor: appBarColor,
actions: [
ChangeThemeButtonWidget(),
],
),
body: Container(
child: Center(
child: Text(
"$text!",
style: (
TextStyle(
fontSize: 27,
color: textColor,
)
),
),
),
),
);
}
}
Below code will to change theme via Icon Button in appBar. Steps:
Create a stateful widget.
Add the following variables:
bool _iconBool = false;
IconData _iconLight = Icons.wb_sunny;
IconData _iconDark = Icons.nights_stay;
Create actions -> IconButton in the appBar as below:
appBar: AppBar(
title: Text("Simple Colregs"),
backgroundColor: Color(0xFF5B4B49).withOpacity(0.8),
actions: [
IconButton(icon: Icon(_iconBool ? _iconDark : _iconLight),
},)
],
), //AppBar
Add Below methods with Light and Dark themes and any custom preference is required:
// light Theme
ThemeData lightThemeData(BuildContext context) {
return ThemeData.light().copyWith(
primaryColor: Color(0xFF5B4B49),
colorScheme: ColorScheme.fromSwatch().copyWith(secondary: Color(0xFF24A751)));
}
// dark Theme
ThemeData darkThemeData(BuildContext context) {
return ThemeData.dark().copyWith(
primaryColor: Color(0xFFFF1D00),
colorScheme: ColorScheme.fromSwatch().copyWith(secondary: Color(0xFF24A751)));
}
Read more about ThemeData Class here.
Under IconButton, create a functionality for the button as below which will toggle the theme:
onPressed: () {
setState(() {
_iconBool = !_iconBool;
});
Finally add under Material App:
theme: _iconBool ? lightThemeData(context) : darkThemeData(context),
That's all, good to go. Hope it helps.
you can use it in initState
bool darkModeOn = brightness == Brightness.dark;
or
var brightness = MediaQuery.of(context).platformBrightness;
bool darkModeOn = brightness == Brightness.dark;
Good morning,
Here I have two buttons that change the theme of my application (light and dark). When I reload my app the theme is not the one I selected last. I would like the application to back up the last theme used locally. You may need to save just a number that indicates which theme used the last one. . . But I don’t know at all how to do this?
Here’s the code: main.dart
import 'package:flutter/material.dart';
import 'package:animated_splash_screen/animated_splash_screen.dart';
import 'package:watch/nav.dart';
import 'package:page_transition/page_transition.dart';
import 'package:watch/blocs/theme.dart';
import 'package:provider/provider.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<ThemeChanger>(
builder: (_) => ThemeChanger(ThemeData.dark()),
child: MaterialAppWithTheme(),
);
}
}
class MaterialAppWithTheme extends StatelessWidget {
#override
Widget build(BuildContext context) {
final theme = Provider.of<ThemeChanger>(context);
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: theme.getTheme(),
home: AnimatedSplashScreen(
duration: 3000,
splash: "",
splashTransition: SplashTransition.slideTransition,
pageTransitionType: PageTransitionType.downToUp,
nextScreen: Nav(),
),
);
}
}
settings.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:watch/blocs/theme.dart';
import 'package:watch/constants.dart';
class Parametres extends StatelessWidget {
#override
Widget build(BuildContext context) {
ThemeChanger _themeChanger = Provider.of<ThemeChanger>(context);
return Scaffold(
appBar: AppBar(
title: Text('Paramètres', style: kAppBarStyle,),
elevation: 0,
automaticallyImplyLeading: false,
leading: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Icon(
Icons.arrow_back,
),
),
),
body: Container(
child: Column(
children: <Widget>[
FlatButton(
onPressed: () => _themeChanger.setTheme(
ThemeData(
bottomNavigationBarTheme: bNavBar,
scaffoldBackgroundColor: kBlackMedium,
brightness: Brightness.dark,
iconTheme: bIcons,
)),
child: Text('Dark Theme')),
FlatButton(
onPressed: () => _themeChanger.setTheme(
ThemeData(
bottomNavigationBarTheme: lNavBar,
scaffoldBackgroundColor: Colors.white,
brightness: Brightness.light,
iconTheme: lIcons,
primaryColor: kWhite,
)),
child: Text('Light Theme')),
],
),
),
);
}
}
Thank you
Shared preference is best option for it. Since I don't know about your ThemeChanger class I add here my theme class first:
class MyThemeModel extends ChangeNotifier{
ThemeData _themedata;
MyThemeModel(bool isActive){
if(isActive == null){
getThemeData;
}
else{
if(isActive){
_themedata = sleepTheme;
}
else{
_themedata = morningTheme;
}
}
}
ThemeData get getThemeData => _themedata;
void setThemeData(ThemeData data){
_themedata = data;
notifyListeners();
}
}
In main.dart
void main() async{
var isSleepActive;
if(SharedPrefHelper.prefInstance.checkContains(SharedPrefKeys.ISMORNING)){
isSleepActive = SharedPrefHelper.prefInstance.getBool(SharedPrefKeys.ISMORNING);
}
else{
isSleepActive = false;
}
runApp(MultiProvider(
providers: [
ChangeNotifierProvider(
builder: (context) => MyThemeModel(isSleepActive),
)
],
child: MyApp(),
)
);
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: Provider.of<MyThemeModel>(context).getThemeData,
title: 'Theme App',
home: AnimatedSplashScreen(
duration: 3000,
splash: "",
splashTransition: SplashTransition.slideTransition,
pageTransitionType: PageTransitionType.downToUp,
nextScreen: Nav(),
),
debugShowCheckedModeBanner: false,
);
}
In order to change theme with flat button:
FlatButton(
onPressed: () => myThemeModel.setThemeData(
ThemeData(
bottomNavigationBarTheme: lNavBar,
scaffoldBackgroundColor: Colors.white,
brightness: Brightness.light,
iconTheme: lIcons,
primaryColor: kWhite,
)),
child: Text('Light Theme')),
Use the Shared Preference package and there you can store simple values as key pair values.Load that data in the init of the initial screen so that you can display the screen according to the theme
You should use local memory to save theme.
You can use shared preference or hive db or sqflite or other database system.
About changing theme you can use Cubit,Bloc,Provider or etc or even if ValueNotifier.
However you should wrap your MaterialApp or CupertinoApp with "your state management widget"
And add some Logic
OR you can use some library
Library to change theme
I have managed to implement a Darkmode into my app, however I don't know how to implement dark mode into other screens, so that when I press a button in settings the whole app goes into dark mode. I know it has something to do with notifying the listeners but I don't know where to begin.
Currently I am using shared preferences to store the dark mode and I have a separate file for the theme.
My Question is effectively how do I implement dark mode into other screens?
Here is my main controller code
import 'themes.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() => runApp(Darkmode());
class Darkmode extends StatelessWidget {
#override
Widget build(BuildContext context) {
/// Here we are asynchronously passing an instance of SharedPreferences
/// to our Settings ChangeNotifier class and that in turn helps us
/// determine the basic app settings to be applied whenever the app is
/// launched.
return FutureBuilder<SharedPreferences>(
future: SharedPreferences.getInstance(),
builder:
(BuildContext context, AsyncSnapshot<SharedPreferences> snapshot) {
return ChangeNotifierProvider<Settings>.value(
value: Settings(snapshot.data),
child: _Darkmode(),
);
},
);
}
}
class _Darkmode extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: Provider.of<Settings>(context).isDarkMode
? setDarkTheme
: setLightTheme,
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
widget.title,
style: TextStyle(color: Theme.of(context).accentColor),
),
actions: <Widget>[
IconButton(
icon: Icon(Provider.of<Settings>(context).isDarkMode
? Icons.brightness_high
: Icons.brightness_low),
onPressed: () {
changeTheme(
Provider.of<Settings>(context, listen: false).isDarkMode
? false
: true,
context);
},
),
],
),
body: Center(),
);
}
void changeTheme(bool set, BuildContext context) {
///Call setDarkMode method inside our Settings ChangeNotifier class to
///Notify all the listeners of the change.
Provider.of<Settings>(context, listen: false).setDarkMode(set);
}
}
Here is the Shared Preferences file:
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
/// Class that contains all your app settings
/// Consists only of Theme setting as of now
class Settings extends ChangeNotifier {
final SharedPreferences sharedPreferences;
Settings(this.sharedPreferences);
bool get isDarkMode => sharedPreferences?.getBool("isDarkMode") ?? false;
void setDarkMode(bool val) {
sharedPreferences?.setBool("isDarkMode", val);
notifyListeners();
}
}```
Use the ThemeData() to apply the theme to whole app!
bool isDarkMode = Provider.of<Settings>(context).isDarkMode
return MaterialApp(
theme: ThemeData(
primaryColor: isDarkMode ? Colors.blueGrey[900] : Colors.white,
accentColor: isDarkMode ? null : Colors.pink,
scaffoldBackgroundColor: isDarkMode ? Colors.blueGrey[900] : Colors.white,
brightness: isDarkMode ? Brightness.dark : Brightness.light,
backgroundColor: isDarkMode ? Colors.white : Colors.blueGrey[900],
dividerTheme: DividerThemeData(endIndent: 10, indent: 10),
iconTheme: IconThemeData(
color: isDarkMode ? Colors.white : Colors.grey[900]),
textTheme: Theme.of(context)
.textTheme
.apply(
displayColor: model.drakModeState
? Colors.white
: Colors.grey[900],
bodyColor: model.drakModeState
? Colors.white
: Colors.grey[900]),
),
);
This how you can ahieve this.
use Consumer. this widget will let you listen to changes in Settings
pass the new theme to your MaterialApp.
Then combine them.
class _Darkmode extends StatelessWidget {
#override
Widget build(BuildContext context) {
//settingProvider is the current instance of Settings (up to date)
return Consumer<Settings>(builder: (ctx, settingProvider, child)=> MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: settingProvider.isDarkMode
? setDarkTheme
: setLightTheme,
home: MyHomePage(title: 'Flutter Demo Home Page'),
));
}
}
This is some kind of realtime detection. Any time you'll change your theme, this code will update it for the whole app