How to create two same instance widget in Flutter - flutter

everybody, I just test the "const" and "new" keyword in Dart, and I found that:
If I want to create the exactly same instance, I must:
add the "const" keyword before the constructor declaration.
add the "const" keyword before any place I want to use the object.
like this:
class A {
final int x;
const A(this.x);
}
// when use
var a = const A(0);
var b = const A(0);
identical(a,b); // this is true, they are same instance
--------------------------- OK, so far, this is ok, but !!!! ----------------------------
When I also want to create two same "widgets", I failed!!
like this:
class A extends StatelessWidget {
final int x;
const A(this.x,{Key? key })
: super(key: key);
#override
Widget build(BuildContext context) {
return Container();
}
}
// when use
var a = const A(0);
var b = const A(0);
identical(a,b); // this is false!!!!!! why?????????
So.... Someone can tell me how to create two same instance widgets?? Thanks. :)

Welcome to SOF.
It's because Dart first instantiates an A then makes it constant, please don't confuse constant with static.
The reason the first sample gives identical=true is because both objects have similar hashCode.
(https://api.dart.dev/stable/2.10.5/dart-core/Object/hashCode.html)
hashCode is used for object comparison operations like ==
You should write this way, which is actually useless!:
var z = const A(0);
var a = z;
var b = z
identical(a,b);
Or you should override == and hashCode

Related

Comparing stateless widgets for equality flutter

Im currently experimenting with flutter, and I wrote the following code.
Text t1 = const Text("Hi");
Text t2 = const Text("Hi");
print(t1 == t2);
The print statement prints false, but because i'm creating two constants, shouldn't this print true?
For example if I were to create a class with the following code...
class Class1 {
final int? var1;
final int? var2;
const Class1(this.var1, this.var2);
}
Class1 ob1 = const Class1(1, 10);
Class1 ob2 = const Class1(1, 10);
print(ob1 == ob2);
This prints true for the objects being equal, how are widgets different from other objects in this regard?

How to access bloc state properties that don't exist in the base state class?

Consider these states:
class ExerciseInitialState extends ExerciseState {}
class ExerciseLoadingState extends ExerciseState {}
class ExerciseLoadedState extends ExerciseState {
final List<Data> data;
const ExerciseLoadedState({required this.data});
#override
List<Object> get props => [data];
// total count
int get totalCount => data.length;
}
In the UI, I have to cast the state (ExerciseState) to ExerciseLoadedState to be able to access its property which doesn't exist in the ExerciseLoadingState and ExerciseInitialState:
final total = (context.read<ExerciseBloc>().state as ExerciseLoadedState).totalCount
It looks awkward to me to have to do this casting all the time. Is the only solution to add the same properties to the base class ExerciseState?
It should not feel wrong to you - if you want the property to be available in all the state classes, it should be defined in the base class. E.g. you cannot get the totalCount while the state is ExerciseLoadingState simply because this property is not defined here - you need to promote the type to a specific one.
There are two possible solutions to this problem:
Promote the type to ExerciseLoadedState to access the property:
return BlocBuilder<ExerciseBloc, ExerciseState>(
builder: (context, state) {
final totalCount = state is ExerciseLoadedState
? (state as ExerciseLoadedState).totalCount
: 0;
},
);
Create an extension method on ExerciseState:
extension ExerciseStateX on ExerciseState {
int get totalCount => this is ExerciseLoadedState
? (this as ExerciseLoadedState).totalCount
: 0;
}
With the extension, you won't need to do the type promotion in your UI layer.

What does this class-const-Syntax prefixed by Classname mean in Dart?

Although I thought being familiar with programming language Dart, i stumbled upon this syntax in an example for Bloc:
class AuthenticationState extends Equatable {
const AuthenticationState._({
this.status = AuthenticationStatus.unknown,
this.user = User.empty,
});
const AuthenticationState.unknown() : this._();
const AuthenticationState.authenticated(User user)
: this._(status: AuthenticationStatus.authenticated, user: user);
const AuthenticationState.unauthenticated()
: this._(status: AuthenticationStatus.unauthenticated);
final AuthenticationStatus status;
final User user;
#override
List<Object> get props => [status, user];
}
I know how to define a class constant and a const constructor.
However, why is the classname prefixed here everywhere?
const AuthenticationState._({
this.status = AuthenticationStatus.unknown,
this.user = User.empty,
});
That's a named constructor. In dart you can define constructors in two ways, either using ClassName or ClassName.someOtherName.
Eg: Consider you have a class called person with 2 variables, name and carNumber. Everyone has a name but carNumber is not necessary. In that situation, if you implement the default constructor, you have to initialise it like:
Person("Name", "");
So if you want to add some syntactic sugar, you can add a named constructor like below:
class Person {
String name;
String carNumber;
// Constructor creates a person with name & car number
Person(this.name, this.carNumber);
// Named constructor that only takes name and sets carNumber to ""
Person.withOutCar(String name): this(name, "");
// Named constructor with no arguments, just assigns "" to variables
Person.unknown(): this("", "");
}
And you can initialise the object like:
Person.withOutCar("Name");
In the above example the named constructors are being redirected to your actual constructor with pre-defined default values.
You can read more about named constructors here: Dart Language Tour
As the above answer was not really clear/complete to me, when I stumbled upon this, please me let me know, whether my understanding is correct:
const AuthenticationState._({
this.status = AuthenticationStatus.unknown,
this.user = User.empty,
});
The constructor using ._() is private to the library, I guess this is a security feature, so you can create an instance only from within the library.
const AuthenticationState.unknown() : this._();
If the object is created as .unknown, the default constructor from above is called (as private), such using the default values. In the other 2 cases, one or both default values are replaced.

what does the child class of Equatable pass to the super(Equatable class)?

hi I am new with bloc in flutter and I'm trying to understand block timer In the doc of flutter_bloc and I would know what's this constructor class mean
#immutable
abstract class TimerState extends Equatable {
final int duration;
//and this list props ??
TimerState(this.duration, [List props = const []])
: super([duration]..addAll(props));
}
Update: For the new version of Equitable package >= v 0.6.0 read my article on Medium, for older version or deep understanding read this answer.
When your father gives you and your brother 2 gifts, both gifts are laptops but they are not the same type of laptops; you want to know are both gifts equal or not! So you will compare all aspects that important to you RAM, SSD, CPU.
on a paper: myLaptop: 16G/256G/i5 | myBrotherLaptop: 8G/512G/i5
Assuming your brain is using Dart language, and you thought of each gift as an object of this class:
class LaptopGiftClass {
int ram;
int ssd;
String cpu;
// Default constructor
LaptopGiftClass(this.ram, this.ssd, this.cpu);
}
then to compare Equailty of both gifts that created using the class above, Dart and other Object oriented languages e.g Java, C# are expecting you to create(override) these functions, in order to make these languages understand the objects and able to compare any two objects of same class:
#override
bool operator ==(Object myBrotherLaptop) =>
identical(myLaptop, myBrotherLaptop) ||
myBrotherLaptop is LaptopGiftClass &&
runtimeType == myBrotherLaptop.runtimeType &&
name == myBrotherLaptop.name;
#override
int get hashCode => name.hashCode;
if these lines scares you off, no one blame you, that's why nice people have created equatable package for us!
Equatable package is telling you "leave this scary job for me" But how to delegate the scary code to equatable package??!
By doing two things:
Make your class extends equatable:
dart class LaptopGiftClass extends Equatable {...}
Pass all properties that you need to compare with inside an array to the Equatable(the super/parent class) from moment one, so inside the constructor:
LaptopGiftClass(this.ram, this.ssd, this.cpu) : super([ram, ssd, cpu]);
your final class is:
class LaptopGiftClass extends Equatable {
int ram;
int ssd;
String cpu;
// Default constructor
LaptopGiftClass(this.ram, this.ssd, this.cpu) : super([ram, ssd, cpu]);
}
AND YOU ARE DONE! you can now check equality of the two gifts, just create the objects then compare:
LaptopGiftClass myLaptop = LaptopGiftClass(16,256,'i5');
LaptopGiftClass myBrotherLaptop = LaptopGiftClass(8, 512,'i5');
AND JUST BEFORE START COMPARING, your brother saw you, and because he is a gamer, he wants you to add more properties in this equality check: GPU and Screen_Resolution! your mother heard that and asked you to add price too!
Now you have a list of new props to compare: [GPU, Screen_Resolution, Price].
So because you follow clean code principle, you expected that, and you made the constructor able to get more properties to compare with:
// This only mean combine both lists
[ram, ssd, cpu]..addAll(myBrotherAndMotherProps)
so your final class is:
class LaptopGiftClass extends Equatable {
int ram;
int ssd;
String cpu;
// Default constructor
LaptopGiftClass(
this.ram,
this.ssd,
this.cpu,
// List of list => because we think "clean code"
// and maybe in the future we will send other data; NOT
// only an array(list)..
// so we here sent the extra props we need to
// compare 'myBrotherAndMotherProps', and
// as sometime brother and mother will not ask you
// to add props to compare, you give it a default value
// as empty "const []", why const here??! just for better
// performance as we are so soooo Professional!!
[ List myBrotherAndMotherProps = const [] ],
) : super([ram, ssd, cpu]..addAll(myBrotherAndMotherProps));
// WHY TO PASS FROM INSIDE THE CONSTRUCTOR?
// because Equatable needs them (required)
// and not at anytime but immediately inside the
// constructor of itself, so we made this
// chaining(constructor pass to another constructor)..
}
So it's obvious that the essintial properties are [RAM, SSD, CPU], but anything extra will be take into consideration too as we made the implementation clean, flexible, and scalable.
before adding this flexible code List<Object> get props => [RAM, SSD, CPU]..addAll(myBrotherAndMotherProps); these used to be EQUAL!!:
// Note first 3 are equal [ram, ssd, cpu]:
LaptopGiftClass myLaptop = LaptopGiftClass(16,256,'i5', ['Nvidia', 1080, '1200$']);
LaptopGiftClass myBrotherLaptop = LaptopGiftClass(16, 256,'i5', ['Intel HD', 720, '900$']);
myLaptop == myBrotherLaptop; // True without ..addAll(myBrotherAndMotherProps);
myLaptop == myBrotherLaptop; // False with ..addAll(myBrotherAndMotherProps);
Same happening with TimerState:
#immutable
abstract class TimerState extends Equatable {
final int duration;
TimerState(this.duration, [List props = const []])
: super([duration]..addAll(props));
}
TimerState is implemented just like LaptopGiftClass above(last implementation).
you can send props to it using the constructor:
TimerState(this.duration, [List props = const []])
: super([duration]..addAll(props));
so TimerState will pass props's list to its parent(super/ the Equatable/ what extended..) in this line like this:
: super([duration]..addAll(props));
and in this timer example; duration is the basic prop, just like [RAM, SSD, CPU] to LaptopGiftClass.
and the hierarchy will be like this:
// Inside class Paused extends TimerState {...}
Paused(int duration) : super(duration); // super is TimerState
// then Inside abstract class TimerState extends Equatable {..}
TimerState(this.duration, [List props = const []])
: super([duration]..addAll(props)); // super is Equatable
// Then Equatable will get props and deal with it for you...
This tutorial use equatable: ^0.2.0, in this version when you want to override the hashcode and == operator you need to pass a List of the properties to the super constructor. Check out the docs.
Whit this in mind, he create a optional parameter called props, and pass to the super constructor a List that contains duration and all elements of the props parameter.
abstract class TimerState extends Equatable {
final int duration;
TimerState(this.duration, [List props = const []])
: super([duration]..addAll(props));
}
In this way the class that extends TimerState can use the props optional parameter to pass other properties, and this properties would be added to the List that is passed to the super constructor of TimerState for use Equatable correctly.
So if you need a state that have other properties you need to do this:
class OtherTimerState extends TimerState {
final int otherProperty1;
final int otherProperty2;
OtherTimerState(int duration, this.otherProperty1, this.otherProperty2)
: super(duration, [otherProperty1, otherProperty2]);
}

How to concatenate a class with a variable to get a static variable from this class?

I am making a pokemon app and I have a question that I already had in other projects and I would like to know if anyone can help me with a solution.
I receive a variable called pokemonName from other screen, I want to pass the variable and concatenate with the class "Strings", it will be like Strings.+pokemonName.toLowerCase(), converting to lowercase to get the map from the class Strings, but I don't know how to achieve this to remove the switch and don't need to use a lot of cases for each pokemon.
class PokemonDetailScreen extends StatelessWidget {
final String pokemonName;
final String image;
Map<String, dynamic> pokemonMap = {};
PokemonDetailScreen(this.pokemonName, this.image, this.index){
getPokemonMap();
}
#override
Widget build(BuildContext context) {
return Container();
}
void getPokemonMap(){
switch(pokemonName){
case "Bulbasaur":
pokemonMap = Strings.bulbasaur;
break;
case "Charmander":
pokemonMap = Strings.charmander;
break;
}
}
}
**Class in another dart file:**
class Strings {
static Map bulbasaur = {};
}
What I needed is something like this:
void getPokemonMap(){
pokemonMap = Strings.$pokemonMap.toLowerCase();
}
What you could do is have a static map indexed by the name of your Pokemons and whose values are maps.
class Strings {
static Map<String, dynamic> map = {
'Bulbasor': {},
'Charmander': {},
// ...
};
}
And you’ll use it like this: pokemonMap = Strings.map[pokemonName].
~You can use JSON file to do all this things instead use a class.~
I recommend not use a static class to do that thing, instead you can just make a normal class and instantiate on another file, so when the class that you call your another class will be dispose when the parent was.
class PokemonStrings {
Map bulbasaur = {your map here};
}
To call that in another file you need just do
PokemonString _pokemonString = PokemonString();
And call whatever you need in the class that you instantiate
var bulbasaurMap = _pokemonString.bulbasaur;
But even so you need walk with static class. Just call the name of class followed by dot to access all the static attributes
var bulbasaurMap = PokemonString.bulbasaur;