Theme.of(context) as const - flutter

I have several places with repetitive codes, for BoxDecoration
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
borderRadius: BorderRadius.circular(5),
boxShadow: [
BoxShadow(
color: Theme.of(context).hintColor.withOpacity(0.15),
offset: Offset(0, 3),
blurRadius: 10)
],
),
So I'd like to extract the BoxDecoration into separated dart file and reuse it.
Something like
static const boxDecoration = BoxDecoration(...);
then use it
final container = Container(
decoration: boxDecoration
)
But I get stuck on few things:
1. If I put it on file that only contains constants, I still need to access context, e.g. in Theme.of(context).primaryColor, which can only retrieved from build(Context) method
2. Then, I create a new stateless widget
import 'package:flutter/material.dart';
class FlutterTemplateStyle extends StatelessWidget {
static var boxDecoration;
#override
Widget build(BuildContext context) {
boxDecoration = BoxDecoration(
color: Theme.of(context).primaryColor,
borderRadius: BorderRadius.circular(5),
boxShadow: [
BoxShadow(
color: Theme.of(context).hintColor.withOpacity(0.15),
offset: Offset(0, 3),
blurRadius: 10)
],
);
return Container();
}
}
And try to access decoration: FlutterTemplateStyle.boxDecoration, which doesn't work. I suppose this is because build is never called.
How can I achieve this constant styling?
Thanks

You cannot use const with any method call because methods cannot be evaluated at compile time - which is the requirement for a const value.
If you know that your primaryColor is constant, will never change, and that you will never want to dynamically change the color of your decoration, you can specify the color without the theme: color: const Color(0xfef1d2e1).
Otherwise, you do not want to use const. You might want to use final if you never reassign your variable, however, that will not work if you need to access your context.
Having said that, you will probably just want to create a function that returns your decoration, so you can use it in multiple places:
BoxDecoration myAwesomeBoxDecoration(BuildContext context) => BoxDecoration(
color: Theme.of(context).primaryColor,
borderRadius: BorderRadius.circular(5),
boxShadow: [
BoxShadow(
color: Theme.of(context).hintColor.withOpacity(0.15),
offset: const Offset(0, 3),
blurRadius: 10,
),
],
);
Let me explain why I believe that the thought of making your BoxDecoration a constant is counterintuitive:
The color of your decoration depends on the theme of your app, which is something that is created entirely at runtime. This means that in order for your BoxDecoration to adapt to the Theme, it cannot be constant because it is adaptive.

Related

Where are the elevation colors in Flutter material you?

I want my TextField widget to be elevated like Card or NavigationBar widgets. I'm using Material 3 (You).
I've tried using surface color from colors like:
Theme.of(context).colorScheme.surface
but it appears to be the same color as
Theme.of(context).colorScheme.background
You can wrap your text_form_field widget with Card widget and give it elevation as well as boxShadow. It will work for you.
Card(
child: //Your_text_form_field,
elevation: 10,
decoration: BoxDecoration(
boxShadow: [
new BoxShadow(
color: Colors.red,
blurRadius: 20.0,
),
],
),

Is it possible to change Icon according to lightTheme or darkTheme in ThemeData? in flutter

I want the icon to change and the boxshadow color to change when GestureDetecotr is pressed. hopefully it will be What should I do?
In the current emulator, press the middle button to change the appearance.
blackMode
lightMode
home.dart part
import 'package:flutter/material.dart';
import 'package:neumorphism/theme/theme_service.dart';
class Home extends StatelessWidget {
const Home({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
bool _tapped = false;
var _lightIcon = Icons.wb_sunny;
var _blackIcon = Icons.dark_mode;
return Scaffold(
appBar: AppBar(
title: Text('Neumorphism'),
),
body: Center(
child: GestureDetector(
onTap: () {
ThemeService().changeThemeMode();
},
child: Container(
width: 200,
height: 200,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.all(
Radius.circular(40),
),
boxShadow: [
BoxShadow(
color: Colors.grey.shade500,
offset: Offset(5.0, 5.0),
blurRadius: 15.0,
spreadRadius: 1.0),
BoxShadow(
color: Colors.white,
offset: Offset(-5.0, -5.0),
blurRadius: 15.0,
spreadRadius: 1.0),
]),
child: Center(child: Icon(_lightIcon)))),
),
);
}
}
themes.dart
import 'package:flutter/material.dart';
class Themes {
final lightTheme = ThemeData.light().copyWith(
primaryColor: Colors.grey[300],
appBarTheme: AppBarTheme(
brightness: Brightness.light,
),
iconTheme: IconThemeData(color: Colors.white, size: 80),
);
final darkTheme = ThemeData.dark().copyWith(
primaryColor: Colors.grey[800],
appBarTheme: AppBarTheme(
brightness: Brightness.dark,
),
iconTheme: IconThemeData(
color: Colors.black87,
size: 80,
),
);
}
theme_service.dart
theme_service.dart
Hello its easy to do this.
Your main problem is that you need to change the icons when the button is pressed. Right?
Then for this you have to use a Stateful Widget and then wrap the widget into a Value Listenable Builder. After that in onpressed you need to update the notifier.
Let's take a example....
Suppose you have to change the background color of the container when theme changed then do like this..
First create a Instance of value Notifier.
ValueNotifier<bool> _themeNotifier = ValueNotifier<bool>(false);
And then update the notifier in onpressed like this:-
onPressed:(){
_themeNotifier.value = false ; //update the value
}
Note that i have used bool as a datatype of value notifier but you can choose whatever suits your need.
Then Wrap your widget in a ValueListnablebuilder
ValueListenableBuilder(
valueListenable: _themeNotifier,
builder: (context, value, child){
return Container(
decoration:BoxDecoration(color:_themeNotifier.value ? Color.white : Color.black),
child: Container(),
)
},
),
Similar to this in you case you need to change the icon and boxshadow
according to the value of the notifier.
If you need any further explanation or help then you can comment.
and as always
Happy Coding...
you also need to change the brightness of context along with theme mode
Check your theme's brightness to change icon and shadows.
To change the icon, you can use this package. Install the package in your project, import it in your file and then simply replace the child of your container with the below code:
AdvancedIcon(
icon: Icons.wb_sunny,
secondaryIcon: Icons.dark_mode,
state: Theme.of(context).brightness==Brightness.dark ? AdvancedIconState.secondary : AdvancedIconState.primary,
)
Now to change shadow of the container, just replace the boxShadow of your container's decoration with below code:
// replace the shadow with your values.
Theme.of(context).brightness == Brightness.dark ? [BoxShadow(color: Colors.white)] : [BoxShadow(color: Colors.black)]

Not able to import variable from a different class in Flutter

I am going off of a login screen tempalte,a nd am trying to get a widget class for a button to just show the username input as an alert on the screen. The usernameinput widget is defined but when I import it, it does not work.
class _InputEmailState extends State<InputEmail> {
final myController = new TextEditingController();
This is the part where I define the input, and this is where I import the class in the button widget:
import 'package:login_minimalist/widget/inputEmail.dart';
When I try and reference the myController.text value, I get the error
The getter 'myController' isn't defined for the class '_ButtonLoginState'.
import 'package:flutter/material.dart';
import 'package:login_minimalist/widget/inputEmail.dart';
class ButtonLogin extends StatefulWidget {
#override
ButtonLoginState createState() => ButtonLoginState();
}
class ButtonLoginState extends State<ButtonLogin> {
#override
Here is the button widget code:
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(top: 40, right: 50, left: 200),
child: Container(
alignment: Alignment.bottomRight,
height: 50,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.blue[300],
blurRadius: 10.0, // has the effect of softening the shadow
spreadRadius: 1.0, // has the effect of extending the shadow
offset: Offset(
5.0, // horizontal, move right 10
5.0, // vertical, move down 10
),
),
],
color: Colors.white,
borderRadius: BorderRadius.circular(30),
),
child: FlatButton(
onPressed: () {
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
// Retrieve the text the user has entered by using the
// TextEditingController.
content: Text(InputEmailState.getUsername),
);
},
);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Sign in',
style: TextStyle(
color: Colors.lightBlueAccent,
fontSize: 14,
fontWeight: FontWeight.w700,
),
),
Icon(
Icons.arrow_forward,
color: Colors.lightBlueAccent,
),
],
),
),
),
);
And here is the Input code:
class InputEmailState extends State<InputEmail> {
final myController = new TextEditingController();
getUsername() {
return(myController.text);
}
#override
void dispose() {
// Clean up the controller when the widget is disposed.
myController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(top: 50, left: 50, right: 50),
child: Container(
height: 60,
width: MediaQuery.of(context).size.width,
child: TextField(
controller: myController,
style: TextStyle(
color: Colors.white,
),
decoration: InputDecoration(
border: InputBorder.none,
fillColor: Colors.lightBlueAccent,
labelText: 'Student ID',
labelStyle: TextStyle(
color: Colors.white70,
fontSize: 20,
),
),
),
),
);
}
If I understand your question correctly, you're trying to access _ButtonLoginState from another class/file. However, in Dart, classes, members, variables, etc. that begin with an underline ("_") are considered private. You can't access them from a different file (except in some special situations with libraries).
To solve this, you can change the name of the class to ButtonLoginState and it should work.
EDIT: In response to more info:
You don't seem to have fully understood the concepts of State in a StatefulWidget. I would strongly recommend taking a good look through the Flutter guide on the subject.
There are many different ways of managing state and what I am going to explain is almost definitely not the best option most of the time (this was the introductory approach some time ago, but I can't even find the example anymore), however, it does work. For a more general option, I recommend Provider.
In your case, the problem starts with this: Text(InputEmailState.getUsername). You're not calling InputEmailState.getUsername, you're simply passing a reference to it. You need to include parentheses to actually call it - InputEmailState.getUsername().
However, this isn't the whole issue. You're trying to access this function using the name of the class, which means you're trying to use it as a static method. However, its an instance method (ie: you need a specific instance of the class to access it. This is the state I was talking about.
To simply get access to the state object of a specific widget, you can use a Key (generally a GlobalKey). You can define this in a parent widget, for example, and pass it as the key parameter of your InputEmail widget and keep a reference in the parent class. Then, to get the username, you can call <key>.currentState.getUsername() which will return the instance value. The exact implementation varies, and I don't have your code to know how it should be implemented.
As I say, this isn't really the recommended approach anymore. I strongly recommend getting to grips with the state concept, then it should be obvious what the best approach is.

Flutter Transparent Container and BoxShadow

I am stuck on this. I am trying to learn Flutter. While I was doing my custom project I hit this wall. I know this can be solved with AppBar, maybe. I want to learn how to draw custom shadow or at least alter BoxShadow.
When I try to add a box shadow to my row which wrapped with container I get this result;
shadow
Code looks like this;
class HeaderContents extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
boxShadow: [BoxShadow(offset: Offset(0, 2), blurRadius: 5)]),
height: MediaQuery.of(context).size.height * 0.1,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
As you can guess I am just trying to get elevation result to the bottom. Thanks everyone.
Add the SpreaRadius and increase the OffsetY. Change all the value to get the desired need.
BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.blue.withOpacity(0.1),
spreadRadius: 5,
blurRadius: 20,
offset: Offset(
0, 10), // changes position of shadow
),
],
),
It seems it is just my retardness on assigning color. On main file I assigned both dark and bright colors for testing out dark/light mode functionality.
Changing this,
color: Theme.of(context).primaryColor
to this,
color: Theme.of(context).primaryColorDark
fixed the problem.

Flutter Container: cannot provide both a color and a decoration

I want to draw a border around my container and have the background be colored.
Widget bodyWidget() {
return Container(
color: Colors.yellow,
decoration: BoxDecoration(
border: Border.all(color: Colors.black),
),
child: Text("Flutter"),
);
}
But when I try this I get the error
Cannot provide both a color and a decoration
The color argument is just a shorthand for "decoration: new BoxDecoration(color:
color)".
How is this solved?
Remove the color parameter from the Container and add it to the BoxDecoration:
Widget bodyWidget() {
return Container(
decoration: BoxDecoration(
color: Colors.yellow,
border: Border.all(color: Colors.black),
),
child: Text("Flutter"),
);
}
If you check the Container source code you can see that the color parameter is just used to set the BoxDecoration color if the decoration is null.
decoration = decoration ?? (color != null ? BoxDecoration(color: color) : null),
The error you got is just a helpful reminder of that. Otherwise you would get a strange override (as was apparently the case in the past) or you might not even notice the bug.