How to get an access to a property of an inheriting class - flutter

I have one main class and three classes that inherits from it.
class Product {
const Product(this.price);
final int price;
}
class Book extends Product {
const Book(this.genre, super.price);
final String genre;
}
class CD extends Product {
const CD(this.genre, super.price);
final String genre;
}
class Sticker extends Product {
const Sticker(this.color, super.price);
final Color color;
}
And then I have widget that needs either Book or CD. Both have genre property. But I don't have access to it because the main class has only price property.
class BookOrCD extends StatelessWidget {
const BookOrCD(this.product,{Key? key}) : super(key: key);
final Product product;
#override
Widget build(BuildContext context) => Text(product.genre);
}
I can't add genre to Product class because Sticker doesn't need it. And I can't specify if Product is Book or CD because it can be either of them. I know there are lots of workarounds to that problem, but I'm looking for some clean solution. Maybe some generic function as helper for example.

You can check if the current instance is of a specific type like so:
if (product is Book) {
product.genre
}
If you want to include the logic inside your widgets you can do like this for example:
Text((product is Book) ? product.genre : '')

Related

Error: The argument type 'Component' can't be assigned to the parameter type 'Activity'

When i pass component to activity in ActivityWidget i will get this error.
Error: The argument type 'Component' can't be assigned to the parameter type 'Activity'.
this is my code.
// a simple model class
abstract class Component {}
// a simple model class
class Activity extends Component {}
// a simple model class
class Quest extends Component {}
// a simple model class
class PrIPC {
ComponentVertex? componentVertex;
PrIPC({this.componentVertex});
}
// a simple model class
class ComponentVertex {
Component? component;
ComponentVertex({this.component});
}
// a simple flutter widget
class ActivityWidget extends StatelessWidget {
const ActivityWidget({
Key? key,
required this.activity,
required this.onConfirmSelected,
required this.onCancelSelected,
}) : super(key: key);
final Activity activity;
final VoidCallback onConfirmSelected;
final VoidCallback onCancelSelected;
#override
Widget build(BuildContext context) {
return const Center(child: Text('Activity Widget'));
}
}
my Screen
class MyPageView extends StatefulWidget {
const MyPageView({Key? key}) : super(key: key);
#override
State<MyPageView> createState() => _MyPageViewState();
}
class _MyPageViewState extends State<MyPageView> {
PrIPC myPrIPC = PrIPC(
componentVertex: ComponentVertex(
component: Activity(),
),
);
#override
Widget build(BuildContext context) {
return ActivityWidget(
activity: myPrIPC.componentVertex!.component!, // <== **I get ERROR in this line.**
onConfirmSelected: () {},
onCancelSelected: () {},
);
}
}
when i want to pass Activity to ActivityWidget from PrPIC i get this error. how can pass component of PrPIC class to activity of ActivityWidget ?
Component :
What are the components in Flutter?
Visual, behavioral, and motion-rich widgets implementing the Material Design guidelines.
App structure and navigation.
Buttons.
Input and selections.
Dialogs, alerts, and panels.
Information displays.
Layout.
What is Flutter activity?
Activity which displays a fullscreen Flutter UI. FlutterActivity is the simplest and most direct way to integrate Flutter within an Android app. FlutterActivity responsibilities. FlutterActivity maintains the following responsibilities: Displays an Android launch screen.

Is it possible to have both a stateful widgets and a stateless widget as subtypes of another class?

I recently tried to create an abstract widget, that has then both a stateless and a stateful implementation, which both can be accessed via factory-methods.
Below I added a minimal example of the only real working solution I have figured out that works for my use case, but it leaves me with some things to be desired.
For example with this solution, I have to declare and override every variable in the sub-classes, while I would really like to rely on the fact that they are subtypes and implicitly have those variables.
Has anyone of you ever needed to do a similar thing? Have you worked out a different approach?
For those concerned about as to why I would need this: I wanted to make a singular Button-Class for my App, that then has different implementations for specific styles of buttons (regular button, a 'striped' button, a button that 'loads' as the user scrolls down a page and becomes active once the user reached the end of the page, etc.). That way I could then simply call 'Button.implementation' wherever i needed a specific button, and have all the button-related Code in the same place.
Cheers.
abstract class A {
final int intellect;
A(this.intellect);
factory A.giveMeB(int intellect) {
return _B(intellect);
}
factory A.giveMeC(int intellect) {
return _C(intellect);
}
}
class _B extends StatelessWidget implements A {
#override
final int intellect;
_B(this.intellect);
#override
Widget build(BuildContext context) {
return SizedBox.shrink();
}
}
class _C extends StatefulWidget implements A {
#override
final int intellect;
const _C(this.intellect, {Key key}) : super(key: key);
#override
_CState createState() => _CState();
}
class _CState extends State<_C> {
#override
Widget build(BuildContext context) {
return Container();
}
}

Is there any best practice of how to define the widget's properties visibility in Flutter?

In Java, according to the recommendations of Effective Java (Item 15 ["Minimize Mutability"] in the Second Edition and Item 13 ["Favor Immutability"] in the First Edition):
Fields are final and private.
If a field does not intend to be used externally, it's likely to set it to private, e.g.,
class CustomAppBar extends View {
public CustomAppBar(Context context, String title, Boolean centerTitle) {
super(context);
this.title = title;
this.centerTitle = centerTitle;
}
private final String title;
private final Boolean centerTitle;
}
But in Flutter framework, almost all Flutter widgets use properties as public property, like what I see in AppBar:
class AppBar extends StatefulWidget implements PreferredSizeWidget {
AppBar({
this.title,
this.centerTitle,
...
}): ...
final Widget title;
final bool centerTitle;
...
}
But based on the experience I learned from Java, I should make it more reasonable to change the properties to private, such like:
class CustomAppBar extends StatefulWidget implements PreferredSizeWidget {
CustomAppBar({
Widget title,
bool centerTitle,
}): _title = title,
_centerTitle = centerTitle;
final Widget _title;
final bool _centerTitle;
...
}
So I am curious, is there any best practice(effective) guide of the visibility of the properties of Flutter widgets?
From Dart Documentation
Dart doesn’t have the keywords public, protected, and private. If an identifier starts with an underscore _, it’s private to its Class, so it is different than Java
So as per you code only:
// these are private entities inside your Class/Activity
final Widget _title;
final bool _centerTitle;

Flutter: Undefined name Try correcting the name to one that is defined, or defining the name

I am facing a few strange issues with Flutter. I do have very little knowledge about Flutter. I am learning it.
class ViewOtherProfile extends StatefulWidget {
final String userName;
final int points;
const ViewOtherProfile({
#required this.userName,
#required this.points,
});
You can see i am getting userName and Points data as argument.
I want to print this argument in the page. Like this
class _ViewOtherProfileState extends State<ViewOtherProfile> {
..........
void initState(){
print(points);
deviceInfo();
super.initState();
print(userName);
]);
}
............
Now problem is i am getting error.
Undefined name 'userName'.
Try correcting the name to one that is defined, or defining the name.
Any reason why i am getting this error and how i can resolve it.
Thanks to #jamesdlin
I tried to put it like this
print(ViewOtherProfile.userName);
but now i am getting another error.
Instance member 'userName' can't be accessed using static access.
There are two main types of widgets in Flutter. StatelessWidget and StatefullWidget. A StatelessWidget is built only one when the UI builds and is never rebuilt. Meanwhile, a StatefulWidget can be rebuilt every time if a call for setState is made.
Hence, for a StatefulWiget, there is a need to track the state of the class by extending the main class with a State class.
You have to note that the scope of variables in those two types of widgets can vary. For example...
class ExampleStateless extends StatelessWidget {
final String userName;
final int points;
const ExampleStateless({
#required this.userName,
#required this.points,
});
#override
Widget build(BuildContext context){
print(userName); print(points);
return Something();
}
}
Note that for the stateful widget, there are two classes and each class has its scope. The superclass ExampleStateful can share its scope to its subclass _ExampleStatefulState via the widget
class ExampleStateful extends StatefulWidget {
final String userName;
final int points;
Static final string id = "exampleState";
const ExampleStatefull({
#required this.userName,
#required this.points,
});
// scope 1
#override
_ExampleStatefulState createState() => _ExampleStatefulState();
}
class _ExampleStatefulState extends State<ExampleStateful>{
// scope 2
final String userName2 = null;
#override
void initState(){
super.initState();
print(widget.userName);
print(userName2);
print(ExampleStateful.id); // you can do this only if variable is static.
}
}
What is in scope 1 can be accessed in scope 2 via the widget properties. eg print(widget.userName); instead of print(userName);

Using a provider in a custom class flutter

I am creating a program that needs to use Provider to get values. I call my provider like below in a stateful widget
final user = Provider.of<Users>(context);
Now I would like to use the provider in a custom class
class UserInformation {
final user = Provider.of<Users>(context):
}
This won't work because context is not defined. kindly assist on how I can do this without using a BuildContext.
This is my class Users that I have on a separate dart file and use as a model for for my data streams.
class Users {
final String uid;
final String name;
final String department;
final String position;
Users({ this.uid, this.department, this.name, this.position });
}
This is the query I use to pull data from firestore
Stream<List<FormQuestions>> get userData{
return userCollection.where('name', isEqualTo: 'First Name').where('department', isEqualTo: 'department').snapshots()
.map(_userDataFromSnapshot);
}
I would like the name to be a variable that I get from say (user.name) from the model class. and the same for the department.
Thanks.
You can only access classes which are ChangeNotifiers in the descendant widgets in the tree below this provided ChangeNotifier because behind the scenes the Provider uses InheritedWidget (which uses context) to provide you with the ChangeNotifier you put up in the tree
So in your case there is no way to access the Users from UserInformation and you have to alter your code to make a workaround
Edit: this is a suggestion to achieve what you want if you are using this code inside a widget:
class UserInformation{
final User user;
UserInformation(this.user);
}
class SomeWidget extends StatefulWidget {
#override
_SomeWidgetState createState() => _SomeWidgetState();
}
class _SomeWidgetState extends State<SomeWidget> {
void someMethod(){
final User user = Provider.of<Users>(context);
UserInformation userInformation = UserInformation(user);
//do something
}
#override
Widget build(BuildContext context) {
return Container();
}
}
¡Hey! In the class you need to add "with ChangeNotifier":
class Users with ChangeNotifier {
final String uid;
final String name;
final String department;
final String position;
Users({ this.uid, this.department, this.name, this.position });
}
Hope help. Sorry for the english, yo hablo español. :D