Code:
class MyColor {
final Color one;
final Color two;
MyColor({
this.one = Colors.black,
this.two = one.withOpacity(0.5), // error
});
}
Is there any way to assign the value of one to two in the constructor itself, I want all fields to be final.
class MyColor {
final Color one;
final Color two;
MyColor({
this.one = Colors.black,
Color? two,
}) : two = two ?? one.withOpacity(0.5);
}
Related
I'm still new to DART but I thought this would be easy to accomplish.
I want to check if a List from a future contains an integer. My return type is list dynamic but when I do the check it's telling me it's a Future.
The function that returns a List dynamic
I want to change the color of an icon
Icon(
Icons.favorite,
color: checkIfLiked(), // Change color here using a future.
size: buttonSize,
);
Future<List> userLikes() async {
GetUserLikes userLikesClicks = GetUserLikes();
Future<List> userLikes = userLikesClicks.getLikes();
List userList = await userLikes;
return userList; // returns List<dynamic>
}
I want to check of the Array contains an integer and if it does to return a color.
Future<Color> checkIfLiked() async{
Color color;
List resultUsersLikes = await userLikes();
if (resultUsersLikes.contains(widget.id)) {
color = Colors.blue;
} else {
color = Colors.grey;
}
return color;
}
I have to return a Color, and I am already using a FutureBuilder on the widget.
I need the color to change the color of an icon.
This is the icon
Icon(
Icons.favorite,
color: checkIfLiked(),
size: buttonSize,
);
How can I add an async here to await the future?
as I see the userLikes() is a Future method, which means when you do this:
if (userLikes().contains(widget.id)) {
// ....
you're trying to call contains() which belongs to the List type on a Future which didn't resolve yet to return the userList from it.
what you need to do is to wait until it gets it and resolves, then use its result ( which will be a List ), like this:
Future<Color> checkIfLiked() async { // add async
List resultUsersLikes = await userLikes(); // then await for this
Color color;
if (resultUsersLikes.contains(widget.id)) { // then use it here
color = Colors.blue;
} else {
color = Colors.grey;
}
return color;
}
Now when you call checkIfLiked(), first it will get the response from the userLikes() then store it in resultUsersLikes, then use it in the rest of your code :
and when you wanna use checkIfLiked() in your other codes as the onPressed of some button, you will need to await for it to get its final response, like this:
onPressed: () async {
Color colorResult = await checkIfLiked();
}
You can set that color to the Icon, by calling this method on initState, then once it completes, update the state with the Color, first declare a Color variable in your State class:
Color? resultColor;
then set it to your Icon:
Icon(
Icons.favorite,
color: resultColor,
size: buttonSize,
);
then in your initState:
#override
void initState() {
checkIfLiked().then((colorResponse) {
setState(() {
resultColor = colorResponse
});
});
}
now once the widget will be set inside the widget tree, the checkIfLiked() will get called, when it finishes, the then will be executed, which updates the state of resultColor with the color got from the method.
Like your error message states, The method 'contains' isn't defined for the type 'Future'. You should first await the future to resolve, and then you can use the List it returns. First of all, your checkIfLiked() function must return Future and inside it you should await userLikes() function.
Future<Color> checkIfLiked() async {
Color color;
if ((await userLikes()).contains(widget.id)) {
color = Colors.blue;
} else {
color = Colors.grey;
}
return color;
}
Since you don't want checkIfLiked() to return a Future<Color>, you can try this
First declare a variable color and give it a default value.
Color color = Colors.grey;
Then call the below method checkIfLiked() when you need to.
It will fetch the list of likes and finds the required color based on your logic.
Then it uses setState to change the variable color's value from default value grey to required value.
Color change will happen automatically in all your widgets, where color is referenced.
Future<void> checkIfLiked() async {
List userLikesList = await userLikes();
setState(() {
if (userLikesList.contains(widget.id)) {
color = Colors.blue;
} else {
color = Colors.grey;
}
});
}
How do you apply a method to a static variable from a class. There are certain built in classes in flutter that appear to do something like this.
class UITextStyle {
static const TextStyle body = TextStyle(fontSize: 17);
addColor(Color color) {
TextStyle style = this as TextStyle;
style.merge(TextStyle(color: color));
}
}
Which can then be called like this:
UITextStyle.body.addColor(Color.fromRGBA(0,0,0,1));
However I cannot call that method like that as firstly it is not static, and secondly if it were I would not be able to call it after declaring .body first and would only be able to call it at UITextStyle.addColor(...).
How is this achieved?
you can try this solution , the point is that addColor function is not defined to the TextStyle Type , so to achieve that you need to add this function to the TextStyle class by this extension :
extension TextStyleEx on TextStyle{
TextStyle addColor(Color color) {
return merge(TextStyle(color: color,fontWeight: FontWeight.w600));
}
}
and make this method return TextStyle so you can get instance from the merged ones , cause your static object is final so you can not receive new value on it.
and leave your class like this
class UITextStyle {
static const TextStyle body = TextStyle(fontSize: 17);
}
use this class and the saved static object to get new TextStyle with the old and the new TextStyles.
for test run this in main , will clear the previous example :
TextStyle mergedStyles = UITextStyl.body.addColor(Colors.black);
print(mergedStyles);
Thanks to the comments from #pskink I was eventually able to get this functioning.
class UITextStyle {
const UITextStyle(this.style);
final TextStyle style;
static const body = UITextStyle(TextStyle(fontSize: 17));
addColor(Color color) {
TextStyle textStyle = style;
return textStyle.merge(TextStyle(color: color));
}
}
In Dart extensions can have static members.
extension UITextStyle on TextStyle {
static const body = TextStyle(fontSize: 17);
TextStyle addColor(Color color) {
return this.merge(TextStyle(color: color));
}
}
UITextStyle.body.addColor(Color.fromRGBO(0, 0, 0, 1));
I need to create a class called GeneralAppAndDeviceDetails which has the following fields:
import 'package:flutter/material.dart';
class GeneralAppAndDeviceDetails {
final bool isDarkModeEnabled;
final double deviceWidth;
final double deviceHeight;
final Color primaryColor;
final Color secondaryColor;
}
It basically stores general device and app information at the start of the program so that I don't need to create a new instance of Theme or MediaQuery class whenever I want to access these details.
The problem I'm facing is that how can I write this class so that after the fields' values are assigned, They will be unmodifiable? (so that nothing can change the field values)
(I tried to create a singleton class but I need to pass the values to the constructor and by using factory and private constructor, A user can create new classes with different parameters passed to the factory.)
The thing I need is to have static fields that can receive a value once and become unmodifiable after that. How can I achieve something similar?
Thank you
Update:
I wrote the class as below:
import 'package:flutter/material.dart';
class GeneralAppAndDeviceDetails {
final bool isDarkModeEnabled;
final double deviceWidth;
final double deviceHeight;
final Color primaryColor;
final Color secondaryColor;
static bool _isAlreadyCreated = false;
static GeneralAppAndDeviceDetails _instance;
factory GeneralAppAndDeviceDetails(bool isDarkModeEnabled, double deviceWidth,
double deviceHeight, Color primaryColor, Color secondaryColor) {
if (_isAlreadyCreated == false) {
_isAlreadyCreated = true;
_instance = GeneralAppAndDeviceDetails._(isDarkModeEnabled, deviceWidth,
deviceHeight, primaryColor, secondaryColor);
}
return _instance;
}
const GeneralAppAndDeviceDetails._(this.isDarkModeEnabled, this.deviceWidth,
this.deviceHeight, this.primaryColor, this.secondaryColor);
}
I use a flag to check if an instance was created before or not in here and with this code, a similar instance will be returned every time but is it the best way to achieve this?
This is your singleton class
class Test{
final String str;
static Test _singleton;
Test._internal({this.str});
factory Test(String str) {
return _singleton ??= Test._internal(
str: str
);
}
}
example code for you to try and test
void main() {
Test obj = Test('ABC');
print(obj.str);
Test obj1 = Test('XYZ');
print(obj1.str);
}
class Test{
final String str;
static Test _singleton;
Test._internal({this.str});
factory Test(String str) {
return _singleton ??= Test._internal(
str: str
);
}
}
try running this in dartpad for better understanding
you can make the class as singleton and then make these fields as private, accessible only through getters and setters, inside the setter you can check and discard the new value if there is already some value assigned to the field.
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
This does not work because
"a value of type color can not be assigned to a variable of type colors"
import 'package:flutter/material.dart';
final Colors HOMEPAGE_BUTTON_COLOR = Colors.blue.withOpacity(0.5),
If I want to assign a color to a final var, how should this be done?
Use Color instead of Colors.
final Color HOMEPAGE_BUTTON_COLOR = Colors.blue.withOpacity(0.5),
//Declare color variable in your page like this
Color SuperColor = Colors.red;
//initialise the color in intState();
if(globals.userRole=="Super Admin") {
SuperColor = Colors.blue.withOpacity(0.5);
} else{
SuperColor = Colors.red.withOpacity(0.5); }
//and call them whenever you required
Blockquote
color: this.SuperColor,