Invalid constant value in const constructor of Flutter/Dart class - flutter

I want to create a bunch of const colored boxes. The following code works:
class MyBox extends SizedBox {
const MyBox(Color color, {Key? key}) // [*1] color parameter
: super(key: key,
width: 20,
height: 40,
child: const DecoratedBox(
decoration: BoxDecoration(
backgroundBlendMode: BlendMode.multiply,
borderRadius: BorderRadius.all(Radius.circular(10)),
color: Colors.green, // [*2] all boxes are green
// color: color, // [*3] this is what I want
),
),
);
}
[...]
static const mbRed = MyBox(Colors.red);
static const mbYellow = MyBox(Colors.yellow);
static const mbBlue = MyBox(Colors.blue);
But notice that the color parameter at line [*1] is not actually used. If I replace line [*2] with line [*3], I am told this is an Invalid constant value. (Note that the Color class are immutable 32-bit values.)
Somehow there must be a way to pass a color parameter to a const constructor. What am I doing wrong?
And if this is the wrong way to go about it, what is a succinct means of creating a bunch of boxes, identical except for color? Thanks!

You can't. When you declare MyBox's constructor as const, that means that the constructor can be used to create a compile-time constant, not that it must be. Meanwhile, when that constructor itself invokes const DecoratedBox, you're stating that DecoratedBox is guaranteed to be a compile-time constant, but you cannot guarantee that. For example, MyBox could have been constructed with a Color determined at runtime.
Unfortunately Dart has no way to recursively say "try to invoke this constructor as const if possible". You will have to declare the MyBox constructor as a non-const constructor.

Related

apply shade to flutter color variable

I have defined a variable that holds a color value and when I setstate the screen, I always change this color. I want to use this color both as normal and shade100 in my application. However, my code is giving an error below.
late Color objeColor;
objeColor = Colors.orange;
Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: objeColor, // there is no error *******
),),
Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: objeColor.shade100, // there is error *******
),),
error
The getter 'shade100' isn't defined for the type 'Color'.
Try importing the library that defines 'shade100', correcting the name to the name of an existing getter, or defining a getter or field named 'shade100'
shade100 is a getter for MaterialColor. You can do
late MaterialColor objeColor;
...
color: objeColor.shade100
You can't change the shade of the color again in the widget tree. Though you've got plenty of other methods to manipulate the color with. For example, objeColor.withAlpha(75) looks exactly like Colors.orange.shade100 so it would perfectly fit your needs. In other usecases you can try to experiment with other methods, like withOpacity().

Deciding which level(s) in object hierarchy to add const in Dart/Flutter

In a widget hierarchy, how should one go about deciding at which level const should be added? For example, is the following:
const Padding(
padding: EdgeInsets.symmetric(
horizontal: LayoutStyles.horizontalPagePadding
),
child: Icon(Icons.search, color: Colors.black),
)
better than, say:
Padding(
padding: const EdgeInsets.symmetric(
horizontal: LayoutStyles.horizontalPagePadding
),
child: const Icon(Icons.search, color: Colors.black),
)
If so, why? Does it depend on which element(s) is/are most likely to recur in the program, and hence be canonicalized?
Depends on that specific part of the Widget tree being constant throughout the Application life cycle. Like the entire Padding widget is not going to change overtime hence make it const. In cases where the child or the subtree is going to change the second approach suits
From the Docs - Performance considerations
If a subtree does not change, cache the widget that represents that
subtree and re-use it each time it can be used. It is massively more
efficient for a widget to be re-used than for a new (but
identically-configured) widget to be created. Factoring out the
stateful part into a widget that takes a child argument is a common
way of doing this.
Use const widgets where possible. (This is equivalent to caching a
widget and re-using it.)
An excerpt from medium article on Inherited Widgets
Use const to build your widgets
Without const, selective rebuilding of
the sub-tree does not happen. Flutter creates a new instance of each
widget in the sub-tree and calls build() wasting precious cycles
especially if your build methods are heavy.
If you can add const, add it because it will be compile-time constant and it will optimize the usage.
check this answer for details on const constructors:
How does the const constructor actually work?
here is an explanation of the keyword const and its use:
First, to be able to use this keyword the constructor of your widget must be const
for example (using flutter widgets ) :
you can add the keyword const before EdgeInsets.all but you cant do this with BorderRaduis.circular and the reason is that BorderRaduis.circular is not marked as const.
and the second condition if the constructor is marked as const is to pass a constant value as parametre.
Why we use const keyword ?
it's used mostely to increase the performance of your application (avoid instanciation for every call of the build method)
hope that my answer helped you.
From the Effective Dart: usage, you can see the following example:
Basically, any place where it would be an error to write new instead of const, Dart 2 allows you to omit the const.
Good:
const primaryColors = [
Color("red", [255, 0, 0]),
Color("green", [0, 255, 0]),
Color("blue", [0, 0, 255]),
];
Bad:
const primaryColors = const [
const Color("red", const [255, 0, 0]),
const Color("green", const [0, 255, 0]),
const Color("blue", const [0, 0, 255]),
];
Using your example, and reading the Edge Insets documentation you can see that the symmetric constructor is a const constructor:
const EdgeInsets.symmetric(
{double vertical: 0.0,
double horizontal: 0.0}
)
So the const in this case is optional and recommended to be ommited from the Dart Guidelines.
So, answering your question:
If so, why?
It isn't. It's optional and makes it redundant to read, so it's better to be ommited.
Does it depend on which element(s) is/are most likely to recur in the program, and hence be canonicalized?
You should use for things that are compile time constants, i.e you can figure it's whole value without having to run the program.
If you can assure that, you can add const to the constructor of a function you declared, or a value you created. In this way, the compiler can assign a "nickname" to that object and will not need to recreate it everytime it's needed.

Color vs Colors in Flutter

I'm writing a function in flutter like this
Expanded playButton({Color colorName, int buttonNumber, int soundNumber}) {
return Expanded(
child: FlatButton(
color: colorName,
onPressed: () {
final player = AudioCache();
player.play('note$soundNumber.wav');
},
child: Text(
'> PLAY $buttonNumber',
style: TextStyle(
fontSize: 35.0,
color: Colors.white,
),
),
),
);
}
Why the argument should be Color colorName instead of Colors colorName.
As we use color: Colors.teal for defining color.
I think the class Colors is a programmer friendly wrapper of the Color class.
As you can see in the source code of the Colors class:
class Colors {
// This class is not meant to be instatiated or extended; this constructor
// prevents instantiation and extension.
// ignore: unused_element
Colors._();
/// Completely invisible.
static const Color transparent = Color(0x00000000);
...
}
Here the 'Colors' class defines a variable transparent which we could easily use like
...
Container(
color: Colors.transparent,
)
...
So you always use a Color instance for a 'color' and therefore you have to define the variable as a Color instance, even if you use the Colors class wrapper.
Colors are predefined instances of the class Color.
It's like this...
Colors is to Color as Mercedes is to Car. Not every Car is a Mercedes. And not every Color object is a Colors object.
Btw, you can use Color to get the exact color you want, like...
const color = const Color(0xffb74093);
So it's much more versatile than Colors

Flutter: Error in assigning value to const color

const color = Colors.red; // no error
const color100 = Colors.red[100]; // error
If Colors.red is a compile time constant, why Colors.red[100] isn't.
You can assign the value of Colors.red to a const variable because Colors.red is a static const instance of MaterialColor. MaterialColor extends ColorSwatch which in turn extends Color, which is why you can use a MaterialColor as a Color.
Colors.red[100] cannot be assigned to a const variable because its value is obtained by applying the [] operator defined within ColorSwatch:
Color operator [](T index) => _swatch[index];
Operators are similar to named functions - the main difference is they use a different syntax. Operators and functions cannot use the const keyword as of now even if they only return const values, and as such their return values cannot be assigned to const variables either.
Because you can only assign constant values to a const variable.
And the return type of an operator T1 operator [](T2 i) isn't/can't be declared as const
So you can't do const a = b[c];
Like the return type of a function T1 x(T2 y) isn't/can't be declared as const
So you can't do const z = x(y);
Because when you use an operator or a function, you are not creating the return value at the moment of the call, so you are not returning a constant value. That can only be achieved with a constructor.
So you can do const a = ClassA(); if the constructor of ClassA is declared const

How to reuse widget styles properly in flutter?

Coming from frontend webframeworks like angular, react and vue I am struggling to find the best way to write reusable widget styles. Let me demonstrate the problem with an example.
Lets say we have this Widget:
Container(
width: 25,
height: 10,
decoration: BoxDecoration(
color: const Color(0xff7c94b6),
border: Border.all(
color: Colors.black,
width: 8.0,
),
),
child: /* some custom widget */,
);
Now lets say I want to make the Container properties like width, height etc. changable by parameters. If a certain parameter for a property is not passed it should use its default value, like this:
class CustomWidget extends StatelessWidget {
final double width;
final double height;
final BoxDecoration decoration;
const CustomWidget ({
Key key,
this.width = 25,
this.height = 10,
this.decoration = /* default decoration */
/* possibly even more properties */
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
width: width,
height: height,
decoration: decoration,
child: /* some custom widget */
}
}
Obviously, there could be more properties which would lead to more and more boilerplate. Also what do you do, if the container does not have a decoration by default? Should you pass a custom Container always? Also consider that the Container could be nested further down the widget tree.
There must be a good solution, I just can't think of one, probably because my thoughts are biased because of my experience with frontend development. In web project you simply pass the component/widget custom css-classes to overwrite the styles (e.g. a parameter containerClasses). How do you do it properly in flutter?
EDIT: In essence my question is: Is there an equivalent to a css-class in flutter? Or: Whats the best way to make a custom widget's style totally customizable by parameters. I feel like i have to write every single property by hand.
In react you have an interface for all html elements (e.g. div, input etc.) and their props (e.g. for an input-element you have an interface with value, class, type etc.), which you can use to define what parameters one can pass to customize the component/widget.
Flutter style behaves similarly to Vue scoped styled / React "styled-component" or React native in general:
There's no "global style" in these scenarios. Instead, you use composition to obtain the desired result.
In a sense, you have one StatelessWidget for each "CSS class", instead of one big StatelessWidget with many parameters.
For example, say we want to split a "red background + border radius" into reusable styles, then we'd typically have two widgets:
RedBackground
MyBorder
where you would then be able to use them independently:
RedBackground(
child: Text('hello world'),
)
or together:
RedBackground(
child: MyBorder(
child: Text('hello world'),
),
)