How to pre-define propeties in classes Flutter - flutter

I have created a CardText as a stateless widget and I will use it whenever I would be needing it. But I have a problem. As y'all can see, there are properties that I haven't marked as #required. What I want is these properties have a pre-defined value. Like, suppose the color property, it should be 0xFFFFFFFF until and unless I want somewhere to be as 0xFF000000. But these are final properties that can't be assigned on the basis of ??= method. Yes, I know, marking these properties as #required will require me to define each and every property whenever I call it. But having a pre-defined value will help me a lot to save time and a few lines of code.
Well, any expert out there, I don't know how to express the problem, so feel free to change the title. Thank you.
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
class CardText extends StatelessWidget {
final String data;
final int color;
final int fontSize;
final FontWeight fontWeight;
const CardText(
this.data, {
this.color,
this.fontSize,
this.fontWeight,
});
#override
Widget build(BuildContext context) {
return Text(
data,
style: GoogleFonts.openSans(
textStyle: TextStyle(
fontSize: fontSize,
fontWeight: fontWeight,
color: Color(color),
),
),
);
}
}

If your arguments are optional then you can give default it right away, like following
const CardText({
this.data,
this.color = 0xFFFFFFFF,
this.fontSize = 14,
this.fontWeight,
})

You can use the : colon syntax:
const CardText(
this.data, {
this.color,
this.fontSize,
this.fontWeight,
}) : color = 0xFFFFFFFF, data = "data"
The code after the colon will be executed before the code inside the curly brackets. From the linked question
The part after : is called "initializer list. It is a ,-separated list
of expressions that can access constructor parameters and can assign
to instance fields, even final instance fields. This is handy to
initialize final fields with calculated values.

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),

Flutter: create const color from hex string

I am using Firebase remote config to store my color values. This gives me the flexibilty to update colors without the need to update my app. Now I have written myself a helper function which returns the color object.
In my Firebase remote config I have stored the hex color codes as strings. However, now I am facing the problem that my colors are no constants (const). This is a huge problem for me as I have set default color values in some constructors like here:
const CustomIcon(
{required this.iconType,
this.size,
this.color = Helper.getColor("black"),
Key? key})
: super(key: key);
Because my color is not a const value anymore I get the following error: https://dart.dev/tools/diagnostic-messages#non_constant_default_value
This is my helper function:
static Color getColor(colorName) {
final remoteConfig = FirebaseRemoteConfig.instance;
String colorString = remoteConfig.getString(colorName);
const color = Color(int.parse(colorString));
return color;
}
Do you have any idea on how I can solve this problem?
Kind regards
You sadly won't be able to const anything from the API. The const keyword implies that the Dart Analyzer knows what the value will be even before compiling. This isn't the case here, as the values come from the API.
However, you can still have a solution, by using a local Color default value, and checking for a null color.
class CustomIcon extends StatelessWidget {
final String iconType;
final int? size;
final Color? color;
late final Color defaultColor = Helper.getColor("black");
CustomIcon({required this.iconType, this.size, this.color, Key? key})
: super(key: key);
#override
Widget build(BuildContext context) {
final _color = color ?? defaultColor;
// Build your Widget
return Container(
color: _color,
height: 50,
width: 50,
);
}
}
Here is a simple DartPad showing it in action: https://dartpad.dev/?id=562c943972abaefd29b7b264e16ad5aa

Flutter manage all the extra arguments

In my flutter code, I have created a widget called BeautifulTextField. I use a similar design for all my text fields in my code, so I just copied it into one class. However, a text field can have many parameters, such as enableSuggestions, autocorrect, focusNode etc. Only 1 out of 10 text fields might require these parameters. How can I manage them? This is my current code.
String placeholder="";
IconData icon;
bool passField;
double fontSize;
EdgeInsets paddingText;
BeautifulTextField(this.placeholder,this.icon,[
this.passField=false,
this.fontSize = -1,
this.paddingText = const EdgeInsets.fromLTRB(10,10,20,10)
]);
To elaborate further, I achieved this in react like this:
const Inputs = (props) => {
return <input {...props} className="textfield"/>
}
Is there a similar feature in Flutter?
Why don‘t you inherit a base class to a detailed class
class BeautifulText {
base properties
}
class MostBeautifulText extends BeautifulText {
extra properties
}
You can use those fields as below when that fields are Optional,
String placeholder = "";
IconData icon;
bool passField;
double fontSize;
EdgeInsets paddingText;
bool enableSuggession;
bool autoCorrect;
FocusNode focusNode;
BeautifulTextField(this.placeholder, this.icon, this.passField, this.fontSize, this.paddingText,
{this.enableSuggession, this.autoCorrect, this.focusNode});

Flutter: add a simple wrapper to the Text widget

I came from a React world and trying to get my head around Flutter and Dart.
I'm using the Text widget with the same parameters a lot, so it seems reasonable to think of a way to reuse code. I created a wrapper that uses it:
import 'package:flutter/material.dart';
TextStyle getThemeProperty(type, TextTheme textTheme) {
switch (type) {
case 'headline1':
return textTheme.headline1;
case 'headline2':
return textTheme.headline2;
case 'headline3':
return textTheme.headline3;
default:
return textTheme.bodyText2;
}
}
class CustomText extends StatelessWidget {
const CustomText({Key key, this.type, this.text, this.color}) : super(key: key);
final type;
final text;
final color;
#override
Widget build(BuildContext context) {
var textTheme = Theme.of(context).textTheme;
var style = getThemeProperty(type, textTheme);
if (this.color != null) style.color = this.color;
return Text(
this.text,
style: style,
);
}
}
// Usage
CustomText(
text: 'Some Heading',
type: 'headline2',
color: Colors.black
)
The idea is to set the color if the color property is passed as a parameter, but Dart's compiler doesn't like it. It throws me the error: ''color' can't be used as a setter because it's final.
Try finding a different setter, or making 'color' non-final.'
I'm planning to do the same to fontWeight and textAlign properties as well. How am I able to make this work, I mean, to add new props to the style object on demand?
The reason why the dart compiler is unhappy is just because the color property of the TextStyle is declared as final. Therefore to use a new color, you have to create a new instance of the TextStyle.
Luckily, the TextStyle class comes with a copyWith method that returns an edited copy of your TextStyle
final type;
final text;
final color;
#override
Widget build(BuildContext context) {
var textTheme = Theme.of(context).textTheme;
var style = getThemeProperty(type, textTheme);
return Text(
this.text,
// Added this...
style: style.copyWith(color: color ?? style.color),
);
}
As a side note, when making reusable widgets, it's always a good idea to type your parameters. This is because any type of variable can be used. So instead of passing a String for text, you may pass an int
// DON'T DO THIS
final type;
final text;
final color;
// DO THIS
final String type;
final String text;
final Color color;
Also adding the this keyword to reference a variable in a class without variable shadowing is unnecessary.
// DON'T
this.text
// DO
text

What's a good way of defining theme objects in Flutter(Dart)?

I know about the theme object "ThemeData" and i'm making use of that as well, but alas the need for extending it has arisen.
What I'm trying to accomplish is defining style sets to reference throughout my app. For example i have this
child: Text(
advisoryServiceStatus[item.status - 1],
style: TextStyle(
color: Color.fromRGBO(0, 0, 0, 0.6),
fontSize: 12,
fontWeight: FontWeight.w500),
),
and i want to move the TextStyle in a file so i can do something like
child: Text(
advisoryServiceStatus[item.status - 1],
style: extendedThemeConfig.textStyles.mutedText,
but i have troubled properly defining my style object. Here's what i tried. Maybe i shouldn't be using classes, but i haven't managed to define them as objects. (my understanding of the concepts is a bit shabby)
This is how i tried to define my extendedThemeConfig
class TextStyles {
final TextStyle mutedText = TextStyle(
color: Color.fromRGBO(0, 0, 0, 0.6),
fontSize: 12,
fontWeight: FontWeight.w500);
}
class ExtendedThemeConfig {
TextStyles textStyles;
}
const extendedThemeConfig = ExtendedThemeConfig;
Why your approach doesn't work
It probably does work, but features like hot-reload aren't supported, because you introduce global state to your app, which is often not what you want.
So, how to do it better?
I already answered a similar question here more elaborately, but here's a version adapted to your problem:
Because Flutter is open source, we can just look at how the Theme is implemented and copy that code to create a custom widget that functions just like a Theme.
Here's a boiled-down version:
#immutable
class MyThemeData {
MyThemeData({
this.mutedText,
});
final TextStyle mutedText;
}
class MyTheme extends StatelessWidget {
MyTheme({
Key key,
#required this.data,
#required this.child,
}) : super(key: key);
final MyThemeData data;
final Widget child;
static MyThemeData of(BuildContext context) {
return (context.ancestorWidgetOfExactType(MyTheme) as MyTheme)?.data;
}
#override
Widget build(BuildContext context) => child;
}
Now, you can just wrap the MaterialApp in a MyTheme widget:
MyTheme(
data: MyThemeData(
mutedText: ...,
),
child: ... (here goes the MaterialApp)
)
Then anywhere in your app, you can write MyTheme.of(context).mutedText.
You can adapt the MyThemeData class to your needs, storing anything you want.