RaisedButton's background color does not change after setting ThemeData's primaryswatch property - flutter

Below is a clean Flutter example with a RaisedButton.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
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),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Text('test'),
onPressed: () {},
)
],
),
),
);
}
}
Snippet from theme_data.dart
// Used as the default color (fill color) for RaisedButtons. Computing the
// default for ButtonThemeData for the sake of backwards compatibility.
buttonColor ??= isDark ? primarySwatch[600] : Colors.grey[300];
Snippet from material_button.dart
/// The button's fill color, displayed by its [Material], while it
/// is in its default (unpressed, [enabled]) state.
///
/// The default fill color is the theme's button color, [ThemeData.buttonColor].
///
/// See also:
///
/// * [disabledColor] - the fill color of the button when the button is disabled.
final Color color;
Based on the above, I assume the RaisedButton will have a blueish background color since the buttonColor will be inferred from primarySwatch. Instead, the RaisedButton has a greyish background color.
I know I can set the buttonColor parameter directly via ThemeData but since the source code states that buttonColor will be inferred from primarySwatch, I'm just curious why it did not work. What did I miss?

Your answer is in the code you quoted:
buttonColor ??= isDark ? primarySwatch[600] : Colors.grey[300];
On that same file (theme_data.dart) you can see that isDark is defined as:
final bool isDark = brightness == Brightness.dark;
Since your theme isn't defined as Brightness.dark the button will default to Colors.grey[300].

Related

Fill Icons with color in Flutter

I'm currently working on a Flutter project. I have been given Icons by the designer.
One of the Icons looks like this
Now I'd like to fill the inside of the Icon with color so that it looks like this
How can I achieve this in flutter? I really tried a lot. Like using ClipRect and other Classes. But none gave the desired results.
Try this one.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
bool _isBluetoothOn = false;
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
IconButton(
onPressed: () async {
print(_isBluetoothOn);
setState(() {
_isBluetoothOn = !_isBluetoothOn;
});
print(_isBluetoothOn);
},
icon: Icon(
_isBluetoothOn ? Icons.favorite : Icons.favorite_border,
color: Colors.greenAccent,
size: 40,
),
),
],
),
),
);
}
}
You can simply ask designer for filled icons too and show them when they are clicked.
So it goes like this:
if button clicked:
show filledIcon
else:
show unfilledIcon
You can code that in Flutter like:
icon:clicked? Icon(filledIcon):Icon(unfilledIcon)
This is the easiest way to do this.

changing theme through button input in Flutter

I made a button, and when that button is pressed, I want to change the color of the theme.
I am trying to modify the color with the value received from the button, but it does not work.
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
String themeColors=context.watch<DisplayList>().themeColor;
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: Colors.${themeColors}, //How do I fix this part?
),
Or is there another way to change the color?
themeColors variable already contains a string of the color to be changed.
You can't actually have a syntax like this one on Flutter: Colors.${themeColors}
To handle multiples themes, you need to create multiples ThemeData and switch them with a ValueNotifier.
I suggest you to use an already made community package like theme_provider which will help you to switch between themes very easily.
You will have to convert your widget to Stateful and use the setState method
class XYZ extends StatefulWidget {
const XYZ({Key? key}) : super(key: key);
#override
_XYZState createState() => _XYZState();
}
class _XYZState extends State<XYZ> {
var myAppBarThemeColor = Colors.red;
#override
Widget build(BuildContext context) {
print(myAppBarThemeColor);
return MaterialApp(
theme: ThemeData(appBarTheme: AppBarTheme(backgroundColor: myAppBarThemeColor)),
home: Scaffold(
appBar: AppBar(
title: Text('Hello'),
),
body: Center(
child: TextButton(
onPressed: () => setState(() => myAppBarThemeColor = Colors.green),
child: Text('Change AppBar Color'),
),
),
),
);
}
}
You can use findAncestorStateOfType to manage the state of the root widget.
class App extends StatefulWidget {
const App({Key? key}) : super(key: key);
static _AppState? of(BuildContext context) => context.findAncestorStateOfType<_AppState>();
#override
_AppState createState() => _AppState();
}
class _AppState extends State<App> {
late bool isDarkMode;
late ThemeModeStorage storage;
void toggleDarkMode() {
setState(() {
isDarkMode = !isDarkMode;
});
storage.writeBool(value: isDarkMode);
}
...
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeConfig(isDarkMode).themeData,
home: HomeScreen(),
);
}
}
So you can call this everywhere in your app.
App.of(context)?.toggleDarkMode();

I don't understand the point of the Theme class in Flutter

So I was working with Flutter and I needed a custom Widget for a ListView where every widget has its own theme based on some data.
The proper way to do it seems to be something like this:
class CustomWidget extends StatefulWidget {
CustomWidget({Key key, this.data}) : super(key: key);
final Color data;
#override
_CustomWidgetState createState() => _CustomWidgetState();
}
class _CustomWidgetState extends State<CustomWidget> {
#override
Widget build(BuildContext context) {
return Theme(
data: ThemeData(primaryColor: widget.data),
child: Builder(builder: (context) {
return Container(
color: Theme.of(context).primaryColor,
);
}),
);
}
}
But if I do it like this, what exactly is the advantage of this?
Specifically applying the color in the container? Why can't I just do color: widget.data?
Wouldn't it make more sense if things like TextTheme automatically applied to every Text() decadence of Theme()?
The ThemeData is used to configure a Theme or MaterialApp widget:
https://api.flutter.dev/flutter/material/ThemeData-class.html
The primaryColor value does not affect the color of the Text widget, from the docs:
The background color for major parts of the app (toolbars, tab bars, etc)
If you want to change the color of the text then you can use the textTheme property:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
accentColor : Colors.black,
textTheme: TextTheme(bodyText2: TextStyle(color: Colors.purple)),
primaryColor : Colors.black
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
primaryColor: is used for the appbar
accentColor: is used to color the foreground
textTheme: will change the color of the text and style it
working example:
https://dartpad.dartlang.org/bba537def9dbfa771400309a4e6415ed

How to turn other screens to Dark Mode

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

How do I make Scaffold.bottomSheet partly transparent?

Is there a way to make Scaffold.bottomSheet partly transparent (like for a notch that shows the body content behind it)? I noticed that even adding just Text implicitly puts a white background (Material?) below it, and I think this is not configurable.
class MyHomePage extends StatefulWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Colors.blue,
child: // ...
),
bottomSheet: Text('This is a bottom sheet'),
);
}
}
FWIW, Scaffold.bottomNavigationBar supports being semi-transparent (e.g. you can have a notch around FAB).
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(title: 'Flutter Demo Home Page'),
theme: ThemeData(
bottomSheetTheme: BottomSheetThemeData(
backgroundColor: Colors.black.withOpacity(0.5)),
),
);
}
}
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(
backgroundColor: Colors.blue,
appBar: AppBar(
title: Text(widget.title),
),
body: Center(),
bottomSheet: Container(
height: 40,
width: MediaQuery.of(context).size.width,
child: Center(child: Text('semi transparent bottom sheet :)', style: TextStyle(color: Colors.white),))
),
);
}
}
this was previously posted