Flutter - How to use enum with const in a class - flutter

I am fairly new to Flutter and have made my first Reusable Widget. Below is a cleaner example on what I am trying to do.
My enum:
enum StreamBoxSize {
small(9),
medium(15),
large(18);
final double borderRadius;
const StreamBoxSize(this.borderRadius);
}
I am trying to give each enum value a default border radius value, so if I am choosing StreamBoxSize.small the border radius of my container is going to be 9.
My class looks like this:
class StreamBox extends StatelessWidget {
const StreamBox({
super.key,
this.size = StreamBoxSize.large,
});
final StreamBoxSize size;
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(**borderRadius**),
topRight: Radius.circular(**borderRadius**),
bottomLeft: Radius.circular(**borderRadius**),
bottomRight: Radius.circular(**borderRadius**),
),
...
I have marked in bold the value that of course doesnt work becaues my class dont know what borderRadius is. Any idea how to make it work? The value I want here is dynamic so everything will be 9 if I have choosen this:
StreamBox(size: StreamBoxSize.small),

Maybe you already tried and there's something I'm missing, but why setting
Radius.circular(size.borderRadius)
for each side won't work?
After all, StreamBoxSize.borderRadius is public and should be visible inside the build method...

Related

How to manage more than 1 type(accent) of button properly?

I hope somebody can explain me some kind of solution:)
I've been working on app UI using Flutter and there are 2 types of a button in that app design on Figma, each has its accent (there're 3 for now), which just define the button's heigth.
Those 2 types of button and accents
So those buttons have different emphasis over the app and I need to somehow manage it following the best coding practices.
Well for now I simply created enum, which contains accent variation:
enum ButtonAccent {
primary,
secondary,
tertiary,
}
class FilledButton extends StatelessWidget {
final String text;
final IconData icon;
final Color backgroundColor;
final Color foregroundColor;
// defines a button height following Figma design. By default 'buttonAccent = ButtonAccent.tertiary', which sets 'heigth = 46'
final ButtonAccent buttonAccent;
final VoidCallback onPressed;
const FilledButton(
{super.key,
required this.text,
required this.icon,
this.backgroundColor = ColorConstants.kCallToAction,
this.foregroundColor = ColorConstants.kText,
this.buttonAccent = ButtonAccent.tertiary,
required this.onPressed});
// method that checks accent
double _buttonHeigthFromAccent() => buttonAccent == ButtonAccent.primary
? 72.0
: buttonAccent == ButtonAccent.secondary
? 60.0
: buttonAccent == ButtonAccent.tertiary
? 48.0
: throw Exception('Wrong ButtonAccent value');
#override
Widget build(BuildContext context) {
return ElevatedButton.icon(
onPressed: onPressed,
style: ElevatedButton.styleFrom(
minimumSize: Size(double.infinity, _buttonHeigthFromAccent()),
backgroundColor: backgroundColor,
foregroundColor: foregroundColor,
textStyle: const TextStyle(color: ColorConstants.kText),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0))),
icon: Icon(icon),
label: Text(text),
);
}
}
Then my FilledButton contains method that checks the accents passed via constuctor and returning the proper heigth.
But! There're plenty of cons in my opinion:
if we consider to change not just height of a button but style in general (color, shape etc), it will lead us to overwrite the whole button implementation and ButtonAccent enum;
not sure that all principles of SOLID are met;
I put _buttonHeigthFromAccent() in both CustomOutlinedButton and FilledButton (added the code of FilledButton only as it doesn't differ much) which is bad idea as well;
I think it would be better to create an abstract class (interface) so I could implement it for my needs.
However I am not sure about it, it can be just extra, pointless work
You can use enhanced enum, it is comes by default from v2.17.0
enum ButtonAccent {
primary(72.0),
secondary(60.0),
tertiary(48.0);
const ButtonAccent(this.size);
final double size;
}
And use the size like
minimumSize: Size(double.infinity, buttonAccent.size),

The parameter 'colour' can't have a value of 'null' because of its type, but the implicit default value is 'null'

enter image description here
code here
constructor's this.colour vairable does not work
class ReusableCard extends StatelessWidget {
Color colour= null;
ReusableCard({#required this.colour});
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(15),
decoration: BoxDecoration(
color: colour,
borderRadius: BorderRadius.circular(10.0),
),
);
}
}
The issue is showing warning message because of null-safety.
On class level Color is needed to be initialized before read time. In your case you are using named Constructor which is default to act as optional parameter. You can do make it required on constructor.
final Color colour;
const ReuseableCard({
Key? key,
required this.colour,
}) : super(key: key);
Or make it nullable, as #EnviroApps mentioned. But for this case I prefer like above as my answer.
TO learn more about null-safety
This code should solve your problem:
ReusableCard({this.colour});
Color? colour;
Because Color isnt assigned yet it can be null.
Dart has nullsafety so the question mark implies the value can be null.
See this link for more details: https://sanjibsinha.com/null-safety-in-flutter-dart/
Edit: you could also do it like this:
ReusableCard({this.colour});
late Color colour;
The late keyword to initialize a variable when it is first read, rather than when it's created

How can I make a button object that has a parameter which can change iconData dynamically in flutter?

I am practicing flutter and building a simple app with buttons, each buttons contains different values and those values are stored inside the object's parameter. Now, I want to create a button object where I can change its button icon dynamically.
I want it to look like this:
Expanded(child: NavButton(buttonIcon: home,callFunction: buttonClick,buttonName: 'Home'),) ,
I tried declaring a field name buttonIcon inside my object's class but it goes like this:
class NavButton extends StatelessWidget{
final IconData buttonIcon;
final String buttonName;
final Function callFunction;
const NavButton({
required this.buttonIcon,
required this.buttonName,
required this.callFunction
});
#override
Widget build(BuildContext context){
return Container(
margin: EdgeInsets.fromLTRB(0, 10, 0, 10),
padding: EdgeInsets.zero,
child: FlatButton(
//this will make an error stating that the getter for 'buttonIcon' isn't defined for the type 'Icons'
child:Icon(Icons.buttonIcon, size: 45,),
onPressed: (){
callFunction(buttonName);
}
),
);
}
}
What can I do to make it recognize my 'buttonIcon' field? and if there's an easy way for this? thanks in advance. :)
It's a syntax error. Try the following, simply passing your IconData as the posititional argument to your Icon:
child:Icon(buttonIcon, size: 45,),

What is the best way to reuse a widget in Flutter?

In my app, I need to reuse a same divider more than 20 times.
Which way should I follow for best memory performance?
Way 1:
class DividerX extends StatelessWidget {
const DividerX({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Divider(color: Colors.green, height: 22);
}
}
Way 2:
class DividerX {
const DividerX._();
static const Widget divider = Divider(color: Colors.green, height: 22);
}
The second one. From Dart's website:
Const means that the object's entire deep state can be determined entirely at compile time and that the object will be frozen and completely immutable. (...) [Const objects] are canonicalized. This is sort of like string interning: for any given const value, a single const object will be created and re-used no matter how many times the const expression(s) are evaluated.

How to create a final member variable in the constructor initialization list using named parameters in Dart?

I have this class that I want to initialize using named parameters, and using those parameters I create the final variable in the initialization list.
But whatever I try, it doesn't seem to work. I have it narrowed down to the following example:
class Test {
const Test({
Color color,
BoxBorder border,
}) : decoration = const BoxDecoration(color: const color, border: const border);
final BoxDecoration decoration;
}
But when creating the BoxDecoration I'm getting the following error:
The constructor returns type 'dynamic' that isn't of expected type 'Color'.
The same error exists also for the border.
When I remove the const however, I get this:
Invalid constant value.
What am I missing here?
I would have done it like below:
class Test {
const Test({
Color color,
BoxBorder border,
}): assert(color != null),
assert(border != null),
_color = color,
_border = border;
final Color _color;
final BoxBorder _border;
BoxDecoration get decoration => BoxDecoration(color : _color, border: _border);
}
and then you can utilize it like this:
Container(decoration: Test(color: yourColor, border: yourBorder).decoration)
Note that in your case _color and _border has been declered internally and are not accessible outside the Test class. The only accessible field is decoration.