Trying to make a generic route "base class", where an abstract class defines a getter that returns the route name. Something like this:
abstract class ScreenAbstract extends StatefulWidget {
static String name;
static String get routeName => '/$name';
ScreenAbstract({Key key}) : super(key: key);
}
Then, any "screen" widget can extend this class:
class SomeScreen extends ScreenAbstract {
static final name = 'someScreen';
SomeScreen({Key key}) : super(key: key);
#override
_SomeScreenState createState() => _SomeScreenState();
}
Which should then be accessible like this:
Navigator.of(context).pushNamed(SomeScreen.routeName);
Hoever, when trying that, the linter throws an error:
The getter 'routeName' isn't defined for the type 'SomeScreen'.
What am I doing wrong?
In dart there's no inheritance of static members. See Language Specification here-
Inheritance of static methods has little utility in Dart. Static
methods cannot be overridden. Any required static function can be
obtained from its declaring library, and there is no need to bring it
into scope via inheritance. Experience shows that developers are
confused by the idea of inherited methods that are not instance
methods.
Of course, the entire notion of static methods is debatable, but it is
retained here because so many programmers are familiar with it. Dart
static methods may be seen as functions of the enclosing library.
To tackle this, you can update your solution like this -
Abstract Parent Class -
abstract class ScreenAbstract extends StatefulWidget {
final String _name;
String get routeName => '/$_name';
ScreenAbstract(this._name, {Key key}) : super(key: key);
}
The Screen Widget that extends the Parent class -
class SomeScreen extends ScreenAbstract {
static final String name = "url";
SomeScreen({Key key}) : super(name, key: key);
#override
_SomeScreenState createState() => _SomeScreenState();
}
Then you can access it like this -
Navigator.of(context).pushNamed(SomeScreen().routeName);
Related
I have been working on a flutter project and I have noticed Avoid using private types in public APIs.
Is there a way to fix this warning?
class SubCategoriesPage extends StatefulWidget {
final MainModel mainModel;
// final Ads ad;
const SubCategoriesPage(this.mainModel, {Key? key}) : super(key: key);
#override
_SubCategoriesPage createState() { // Avoid using private types in public APIs.
return _SubCategoriesPage();
}
}
Because createState method return State<Example> so it's preventing returning any private State.
You need to update your code like this.
class SubCategoriesPage extends StatefulWidget {
final MainModel mainModel;
// final Ads ad;
const SubCategoriesPage(this.mainModel, {Key? key}) : super(key: key);
#override
State<SubCategoriesPage> createState() { // Avoid using private types in public APIs.
return _SubCategoriesPage();
}
}
Since this is a StatefulWidget, I'm guessing the _SubCategoriesPage class inherits from State, since it's being returned by createState().
If so, the return type can be changed to State. Since State is public, it can safely be returned from the public createState() method.
Just change _SubCategoriesPage by State
For those using Riverpod, change _SubCategoriesPage by ConsumerState
I had the same issue using this code
class MyPage extends StatefulWidget {
const MyPage({super.key});
#override
_MyPageState createState() => _MyPageState();
}
I tried using this method - State createState() { // Avoid using private types in public APIs.
return _MyPageState();
but than I got this error message - The name MyPageState isn't a type so it can't be used a type argument.
Im trying to pass arguments from my widget's state into a super class, but i cannot access the "widget." from the initialization list.
if i do pass it from the variables and accept an additional parameter in the state's ctor, i get the lint error:
no_logic_in_create_state
Here's my code:
class TransferPage extends View {
final String screenId;
TransferPage(this.screenId, {Key? key}) : super(key: key);
#override
// ignore: no_logic_in_create_state
State<TransferPage> createState() => TransferPageState(screenId);
}
class TransferPageState extends ViewState<TransferPage, TransferController> {
final String screenId;
TransferPageState(this.screenId)
: super(TransferController(GetTransferDataUsecaseParams(screenId)));
I want to pass the id into the "super" ctor,
What's the best way to go about it?
I can think of these 3 ways to initialize a value using GetX
Initializing at the declaration:
class StatusPane extends StatelessWidget {
final HomeController homeController = Get.find();
StatusPane({Key? key}) : super(key: key);
in the initializer list:
class StatusPane extends StatelessWidget {
final HomeController homeController;
StatusPane({Key? key}) : homeController = Get.find(), super(key: key);
or in the constructor
class StatusPane extends StatelessWidget {
late final HomeController homeController;
StatusPane({Key? key}) : super(key: key) {
homeController = Get.find();
}
Is there any significant difference between the 3? Like, can one way lead to crashes or bugs? Or is one way better performance wise? Or are they actually identical? Would it be any different if GetX wasn't used, like final HomeController homeController = HomeController() for example? Or is it pretty much down to personal preference?
These 3 are identical but if you want a bit more performance you can get controller by a method or a getter like:
HomeController get controller => GetInstance().find<HomeController>()
this way, if you use Get.lazyPut instead of Get.put, HomeController and its lifecycle like onInit, onReady,etc gets called when neccessary. Otherwise it gets called immediately on constructor.
Also there is a built in GetView class which you can use instead of StatelessWidget. it has a getter for controller
I try to add multiple constructor in my code but it shows error. help me to solve this.
code :
class NoteModify {
const NoteModify({Key? key}) : super(key: key);
String NoteID;
NoteModify(String x) {
NoteID = x;
}
}
I need to use both constructor. Because I am working with 2 buttons and one button for navigate without sending data to another activity and one button for navigate with data to another activity.
As #Jigar Fumakiya said in his answer, dart doesn't support overloading.
You need to use differently named constructors to fix the error
NoteModify is already declared in this scoped
However, you have another issue, you declared a const constructor and String NoteID is not a final. To declare a const constructor, all the fields must be final.
That is why you get the error
Error: Constructor is marked as 'const' so all fields must be final
If you need the const constructor:
class NoteModify{
const NoteModify({Key? key}) : NoteID = null, super(key: key);
NoteModify.formId({this.NoteID});
final String? NoteID;
}
If you need NoteID to be a variable instead, you'll have to remove the const keyword:
class NoteModify{
NoteModify({Key? key}): super(key: key);
NoteModify.formId({this.NoteID});
String? NoteID;
}
Dart doesn't support methods/constructor overloading. But you can have multiple named constructor
Here
class NoteModify{
String NoteID;
NoteModify({Key key}) {
// main constructor
}
NoteModify.formId({this.NoteID}){
//Here is the named constructor
}
}
Given a stateful widget which takes arguments when it's called, there are two options (that I know of).
I can either use widget.arg to access the data in the state object, or I can create new variables and a new constructor in the state object.
Now I've mostly used the second one and there are some use cases in which the first one causes some problems. However, it looks more concise and readable (I guess).
My question is which one is a better practice?
Example code:
First option:
class Home extends StatefulWidget {
final String email;
const Home({Key key, this.email}) : super(key: key);
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
String example() {
return widget.email;
}
Second option:
class Home extends StatefulWidget {
final String email;
const Home({Key key, this.email}) : super(key: key);
#override
_HomeState createState() => _HomeState(email);
}
class _HomeState extends State<Home> {
final String email;
_HomeState(this.email);
String example() {
return email;
}
I use both approaches, however, i don't use a constructor for the second approach because idk i don't like it. I store a reference in initState. Something like email = widget.email;.
It really depends. It's mostly preference. But i use the widget. approach often, it avoids boilerplate code, and it's a way of identifying which arguments come from the widget vs whcih arguments come from the state.
The flutter team also uses this approach. A LOT. Check the Material AppBar source code. It would be a mess to declare the arguments twice and pass them to _AppBarState. It's cleaner and it works for them. And for me ;)
Don't use the second option, aka having a constructor on State. This is a bad practice.
Use the .widget.property syntax instead.
If you purposefully want to ignore the updates of a property, instead use initState:
class Example {
Example(this.initialText);
final String initialText;
#override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
String text;
#override
void initState() {
text = widget.initialText;
}
}