there is a dark/light theme toggle function in this snap of code. There is no error when I compile, debuging this code. But It doesn't work.
For example, I never define scaffoldbackgroundColor(0xfffafafa) and What I define color in dark, light theme is Color(0xFFE7626C) and Color(0xFF232B55). But ios simulator only show me backgroundcolor(0xfffafafa).
When I click toggle button, the screen never changes. What's wrong with my code...
import 'package:flutter/material.dart';
import 'package:pomodoro_app/widget/sidebar_widget.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
#override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
static final ValueNotifier<ThemeMode> themeNotifier =
ValueNotifier(ThemeMode.dark);
#override
Widget build(BuildContext context) {
return ValueListenableBuilder<ThemeMode>(
valueListenable: themeNotifier,
builder: (_, ThemeMode currentMode, __) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
brightness: Brightness.light,
scaffoldBackgroundColor: const Color(0xFFE7626C),
textTheme: const TextTheme(
displayLarge: TextStyle(
color: Color(0xFF232B55),
),
displaySmall: TextStyle(
color: Color(0xFF232B55),
),
),
cardColor: const Color(0xFFF4EDDB),
),
darkTheme: ThemeData(
brightness: Brightness.dark,
scaffoldBackgroundColor: const Color(
0xFF232B55,
),
cardColor: const Color(0xFFF4EDDB),
textTheme: const TextTheme(
displayLarge: TextStyle(
color: Color(0xFFE7626C),
),
displaySmall: TextStyle(
color: Colors.white,
),
),
),
themeMode: currentMode,
home: Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
elevation: 0,
leading: Builder(
builder: (context) => IconButton(
onPressed: () => Scaffold.of(context).openDrawer(),
icon: const Icon(
Icons.menu_rounded,
color: Color(0xFFF4EDDB),
),
),
),
actions: [
IconButton(
icon: Icon(themeNotifier.value == ThemeMode.light
? Icons.dark_mode
: Icons.light_mode),
onPressed: () {
setState(
() {
themeNotifier.value =
themeNotifier.value == ThemeMode.light
? ThemeMode.dark
: ThemeMode.light;
},
);
},
),
],
),
drawer: const SideBar(),
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text(
"Hello",
)
],
),
),
);
},
);
}
}
That's because the context you are using with
Theme.of(context);
comes from the build method of _HomeScreenState.
So this context is above the MaterialApp which has the Theme.
You have to use a context that is bellow the MaterialApp.
One way to do it is to add a Builder in between your MaterialApp and Scaffold:
return MaterialApp(
title: 'Flutter Demo',
theme: // ...
darkTheme: // ...
themeMode: currentMode,
home: Builder( // <- Insert a builder here.
builder: (context) { // <- Now you'll be using this `context` which is below the `MaterialApp` (and your themes) in the widget tree, so you'll be able to use them.
return Scaffold(
// ...
);
},
);
Related
I like flutter hot reload. I use flutter bloc and auto route. but it doesn't work for me
main.dart file
void main() {
WidgetsFlutterBinding.ensureInitialized();
configureInjection(Environment.prod);
runApp(const AppWidget());
}
app_widget.dart
class AppWidget extends StatelessWidget {
const AppWidget({super.key});
#override
Widget build(BuildContext context) {
final _appRouter = AppRouter();
return MultiBlocProvider(
providers: [
BlocProvider(
create: (context) =>
getIt<AuthBloc>()..add(const AuthEvent.authCheckRequested()))
],
child: MaterialApp.router(
title: 'MyApp',
routerDelegate: _appRouter.delegate(),
routeInformationParser: _appRouter.defaultRouteParser(),
debugShowCheckedModeBanner: false,
theme: ThemeData.light().copyWith(
floatingActionButtonTheme: FloatingActionButtonThemeData(
backgroundColor: Colors.blue[900],
),
primaryColor: Colors.green[800],
colorScheme: ColorScheme.fromSwatch().copyWith(
secondary: Colors.blueAccent,
),
inputDecorationTheme: InputDecorationTheme(
hintStyle: const TextStyle(fontSize: 10),
contentPadding:
const EdgeInsets.symmetric(vertical: 10, horizontal: 10),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(40)),
),
),
),
);
}
}
I tried to convert AppWidget to statefull but doesn't work
Thanks for your valuable time
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),
),
),
);
}
}
I added the libraries to pubspec.yaml. In the current project I am not using hooks, but used the package because I want to use this to build a skeleton starter project.
pubspec.yaml:
flutter_hooks: ^0.18.2+1
hooks_riverpod: ^1.0.3
Then I modified the code to the latest RiverPod syntax. This involved changing things to Consumer widgets and using the ref parameter. The app now runs but just is not switching from dark mode to light mode and vice versa!
main.dart:
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
class AppThemeState extends StateNotifier<bool> {
AppThemeState(): super(false);
void setLightTheme() => state = false;
void setDarkTheme() => state = true;
}
// Theme
final appThemeStateNotifier = StateNotifierProvider((ref) => AppThemeState());
void main() {
runApp(ProviderScope(child: MyApp()));
}
class MyApp extends HookConsumerWidget {
#override
Widget build(BuildContext context, WidgetRef ref) {
final darkModeEnabled = ref.watch(appThemeStateNotifier);
return MaterialApp(
title: 'Flutter Demo',
theme: AppTheme.lightTheme,
darkTheme: AppTheme.darkTheme,
themeMode: darkModeEnabled != null ? ThemeMode.dark : ThemeMode.light,
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 2.0,
title: Text("Flutter Theme Riverpod Demo"),
),
body: Column(
children: [
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("Light Mode"),
DarkModeSwitch(),
Text("Dark Mode"),
],
),
),
],
),
);
}
}
class DarkModeSwitch extends ConsumerWidget {
#override
Widget build(BuildContext context, WidgetRef ref) {
final darkModeEnabled = ref.read(appThemeStateNotifier) == true;
return //Text('$darkModeEnabled');
Switch(
value: darkModeEnabled,
onChanged: (enabled) {
if (enabled) {
ref.read(appThemeStateNotifier.notifier).setDarkTheme();
} else {
ref.read(appThemeStateNotifier.notifier).setLightTheme();
}
},
);
}
}
class AppTheme {
// Private Constructor
AppTheme._();
static final lightTheme = ThemeData(
scaffoldBackgroundColor: Colors.white,
appBarTheme: AppBarTheme(
color: Colors.teal,
iconTheme: IconThemeData(
color: Colors.white,
),
),
textTheme: TextTheme(
bodyText2: TextStyle(
color: Colors.black,
),
),
);
static final darkTheme = ThemeData(
scaffoldBackgroundColor: Colors.black,
appBarTheme: AppBarTheme(
color: Colors.black,
iconTheme: IconThemeData(
color: Colors.white,
),
),
textTheme: TextTheme(
bodyText2: TextStyle(
color: Colors.white,
),
),
);
}
The problem is at this line:
themeMode: darkModeEnabled != null ? ThemeMode.dark : ThemeMode.light,
darkModeEnabled can't be null.
Use this instead:
themeMode: darkModeEnabled ? ThemeMode.dark : ThemeMode.light,
Today I have a button that calls the method _launchURL. But I'd like to call this method right after the app opens, without the need to press a button.
import 'package:flutter/material.dart';
import 'package:flutter_custom_tabs/flutter_custom_tabs.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Custom Tabs Example',
theme: ThemeData(
primarySwatch: Colors.blue,
brightness: Brightness.light,
),
darkTheme: ThemeData(
primarySwatch: Colors.blue,
brightness: Brightness.dark,
),
home: Builder(
builder: (_context) => Scaffold(
appBar: AppBar(
title: const Text('Flutter Custom Tabs Example'),
brightness: Brightness.dark,
),
body: Center(
child: TextButton(
onPressed: () => _launchURL(_context),
child: Text(
'Open Page',
style: TextStyle(fontSize: 17),
),
),
),
),
),
);
}
Future<void> _launchURL(BuildContext context) async {
final theme = Theme.of(context);
try {
await launch(
'https://www.google.com/',
customTabsOption: CustomTabsOption(
toolbarColor: theme.primaryColor,
enableDefaultShare: true,
enableUrlBarHiding: true,
showPageTitle: true,
animation: CustomTabsSystemAnimation.slideIn(),
extraCustomTabs: const <String>[
// ref. https://play.google.com/store/apps/details?id=org.mozilla.firefox
'org.mozilla.firefox',
// ref. https://play.google.com/store/apps/details?id=com.microsoft.emmx
'com.microsoft.emmx',
],
),
safariVCOption: SafariViewControllerOption(
preferredBarTintColor: theme.primaryColor,
preferredControlTintColor: Colors.white,
barCollapsingEnabled: true,
entersReaderIfAvailable: false,
dismissButtonStyle: SafariViewControllerDismissButtonStyle.close,
),
);
} catch (e) {
// An exception is thrown if browser app is not installed on Android device.
debugPrint(e.toString());
}
}
}
Widget build(BuildContext context) {
_launchURL(context); // <= here
return MaterialApp(
title: 'Flutter Custom Tabs Example',
theme: ThemeData(
primarySwatch: Colors.blue,
brightness: Brightness.light,
),
.
.
.
.
Or you can add it in initstate, but your method needs a BuildContext to work.
Flutter SearchDelegate: How to change the color of the blue bubbles in search delegate widget in flutter?
environment:
sdk: ">=2.12.0 <3.0.0"
In my Scaffold-Appbar i have an action with an IconButton and then i call DataSearch. Then i set the ThemeData appBarTheme in the DataSearch. Thats it.
appBar: AppBar(
title: Text(widget.title),
actions: [
IconButton(
icon: const Icon(Icons.search),
onPressed: () {
showSearch(context: context, delegate: DataSearch());
},
),
],
),
class DataSearch extends SearchDelegate<String> {
#override
ThemeData appBarTheme(BuildContext context) {
return ThemeData(
textSelectionTheme: TextSelectionThemeData(
//cursorColor: Colors.red,
selectionHandleColor: Colors.red,
//selectionColor: Colors.white,
), // cursor color
);
}
You can change the color within the textSelectionTheme by setting the selectionHandleColor.
textSelectionTheme: TextSelectionThemeData(
selectionHandleColor: Colors.red, // Change bubble to red
cursorColor: Colors.white,
),
EDIT: Full Example
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
textSelectionTheme: TextSelectionThemeData(
selectionHandleColor: Colors.red,
),
primaryColor: Colors.green,
),
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: TextField(),
),
body: Center(
child: Text('MyApp'),
),
),
);
}
}
Result: