How to set default value of function in a constructor (Flutter) - flutter

I want to set default function in my child Widget in a constructor.
Basically, I have two widgets
Login (Parent Widget)
AppButton (Child Widget)
Here is my AppButton.dart
And I am calling this child widget in Login.dart (Parent) like this:
AppButton(title: "Login")
Please give me a way that to set default function without making "onPress" required for it's Parent (Login.dart)
TIA

Only static value can be set as default value in constructor, so you need define you function as static like this:
class AppButton extends StatefulWidget {
final Function onPress;
const AppButton({Key? key, this.onPress = _onPress}) : super(key: key);
static void _onPress(){}
#override
State<AppButton> createState() => _AppButtonState();
}

just make it nullable:
class MyButton extends StatefulWidget {
final void Function()? onPress;
final String title;
const MyButton({Key? key, this.onPress, required this.title}) : super(key: key);
#override
State<MyButton> createState() => _MyButtonState();
}
class _MyButtonState extends State<MyButton> {
void Function() defaultOnPress = (){
// your default function here
};
#override
Widget build(BuildContext context) {
return ElevatedButton(onPressed: widget.onPress ?? defaultOnPress, child: const Text("my button"));
}
}
still you can get const constructor

you could put "static" before childOnPress()

Related

How to create custom types of widgets in Flutter?

I am trying to create a couple of widgets A that all should belong to another type of widget B, so that in the end all of them could be passed to a constructor that accepts only widgets of type B, but not other custom widgets like Container, Text, etc.
I tried something like this:
Parent class:
class ProDynamicWidget {
const ProDynamicWidget({
required this.height
});
final double height;
}
Child classes:
class ProDynamicTitle extends ProDynamicWidget {
final String title;
ProDynamicTitle({
required this.title
}) : super(height: 50.0);
// Here should be a build method for the title
}
############################################################
class ProDynamicImage extends ProDynamicWidget {
final String imageUrl;
ProDynamicImage({
required this.imageUrl
}) : super(height: 70.0);
// Here should be a build method for the image
}
I then wanted to create a widget that only accept widgets of type ProDynamicWidget:
class TestOneWidget extends StatelessWidget {
const TestOneWidget({
Key? key,
required this.widget
}) : super(key: key);
final ProDynamicWidget widget;
#override
Widget build(BuildContext context) {
return Container();
}
}
I do not really get how can now end up with child widgets that have separate build methods and a way the constructur at the end only accepts these child widgets instead of every type of widget.
Make ProDynamicWidget abstract and let it extend StatelessWidget:
abstract class ProDynamicWidget extends StatelessWidget{
const ProDynamicWidget({
required this.height
});
final double height;
}
Next, ProDynamicTitle and ProDynamicImage simply extend ProDynamicWidget and will thus have to define the build method:
class ProDynamicTitle extends ProDynamicWidget {
final String title;
const ProDynamicTitle({
required this.title
}) : super(height: 50.0);
#override
Widget build(BuildContext context) {
return Text(title);
}
}
class ProDynamicImage extends ProDynamicWidget {
final String imageUrl;
const ProDynamicImage({
required this.imageUrl
}) : super(height: 70.0);
#override
Widget build(BuildContext context) {
return Image(image: NetworkImage(imageUrl));
}
}
You can keep TestOneWidget as is. It will only accept descendants of ProDynamicWidget.

Flutter State<WidgetName> createState() => WidgetNameState()

In Flutter, when initializing a new stateful widget, it is being initialized like this by default:
class WidgetName extends StatefulWidget {
const WidgetName({ Key? key }) : super(key: key);
#override
WidgetNameState createState() => WidgetNameState();
}
I have seen another way of initializing the statefulwidget with #override being slightly different.
class WidgetName extends StatefulWidget {
const WidgetName({ Key? key }) : super(key: key);
#override
State<WidgetName> createState() => WidgetNameState();
}
Notice in the #override method, WidgetNameState became State<WidgetName>. There is an explanation in the Flutter repo that explains it: Link, but I couldn't comprehend what it is trying to say.
What does State<WidgetName> do exactly? Does it give any advantages?
I thought it wouldn't be necessary as WidgetNameState already extends from State<WidgetName> in its class construction.
class WidgetNameState extends State<WidgetName> {
#override
Widget build(BuildContext context) {
Using the generic really let's you define an abstract Widget interface that must be used without having to define any state along with that abstract widget interface.
Let's look at using the concrete class first (WidgetNameState). This is an abstract definition, we must define the state if we do this.
abstract class FooWidget extends StatefulWidget {
const FooWidget({Key? key}) : super(key: key);
#override
_FooWidgetState createState();
}
abstract class _FooWidgetState extends State<FooWidget> {
#override
Widget build(BuildContext context) {
return Container();
}
}
Now to be able to extend this you must extend both the widget and the state.
class ImplementedFooWidget extends FooWidget {
const ImplementedFooWidget({Key? key}) : super(key: key);
#override
_ImplementedFooWidgetState createState() => _ImplementedFooWidgetState();
}
class _ImplementedFooWidgetState extends _FooWidgetState {
#override
Widget build(BuildContext context) {
return Container();
}
}
Now let's look at using the generic (State<WidgetName>). If we use the generic, we can just define and extend the widget and have our own custom state.
abstract class BarWidget extends StatefulWidget {
const BarWidget({Key? key, required this.someRequiredString})
: super(key: key);
final String someRequiredString;
#override
State<BarWidget> createState();
}
class ImplementedBarWidget extends BarWidget {
const ImplementedBarWidget({Key? key, required String someRequiredString})
: super(
key: key,
someRequiredString: someRequiredString,
);
#override
_ImplementedBarWidgetState createState() => _ImplementedBarWidgetState();
}
class _ImplementedBarWidgetState extends State<ImplementedBarWidget> {
#override
Widget build(BuildContext context) {
return Container();
}
}
I hope that all makes sense.

Pass to Widget a Function that returns a future

I want to pass to my Widget a function that returns a future:
class CircularButtonWithIcon extends StatefulWidget {
CircularButtonWithIcon(
{Key key,
#required this.onPress,
this.activeStatus})
: super(key: key);
final Function activeStatus;
class _CircularButtonWithIconState extends State<CircularButtonWithIcon> {
bool active;
#override
void initState() {
super.initState();
widget.activeStatus.then(...);
}
However Dart's class Function has no way to specify that the function's return type.
Is it possible to do such thing?
You can add the return type front of the Function
i.e.
class CircularButtonWithIcon extends StatefulWidget {
Future<void> Function() activeStatus;
CircularButtonWithIcon({Key key, #required this.onPress, this.activeStatus,}) : super(key: key);
}

How to receive a parameter and use in initState within a stateful widget

I have a stateful widget that has one method called in initialisation. I wanna know how to be able to get a parameter from the previous screen and pass it in initState to my initialisation method
class LabDetalheWidget extends StatefulWidget {
final String path;
const LabDetalheWidget({
Key key,
this.path,
}) : super(key: key);
You can pass parameter like that
class MyWidget extends StatefulWidget {
final String param;
const MyWidget({
Key key,
this.param,
}) : super(key: key);
#override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
#override
void initState() {
print(widget.param);
super.initState();
}
#override
Widget build(BuildContext context) {
return Container(
);
}
}
Inside the state you can access the parameter like that
print(widget.param)
I believe you wanna pass data across routes.. If so then read this flutter cookbook's section you might get the idea
https://flutter.dev/docs/cookbook/navigation/passing-data

How does flutter VSCode snippets to extract widget work?

When I use VSCode snippet Extract Widget, I have the following :
class MyExtractedWidget extends StatelessWidget {
const MyExtractedWidget({
Key key,
#required T someVariable,
}) : _someVariable = someVariable,
super(key: key);
final T _someVariable;
#override
Widget build(BuildContext context){ return Container(); }
}
However, I am used to write constructors the following way :
class MyExtractedWidget extends StatelessWidget {
const MyExtractedWidget({
Key key,
#required this.someVariable, // Directly accessing variable using "this"
}) : super(key: key);
final T someVariable;
#override
Widget build(BuildContext context){ return Container(); }
}
Do you know why snippets' constructors use a temporary variable instead of directly writing in the variable?
Is it related to encapsulation? If yes, I cannot understand why, as an extracted Widget is written in the same file, and that "underscored" variables are accessible in whole file.
EDIT
I tried with another widget and I have a kind of mix :
class Test extends StatelessWidget {
const Test({
Key key,
#required List<SortedExpense> sortedExpenses,
#required this.expensesSink,
}) : _sortedExpenses = sortedExpenses, super(key: key);
final List<SortedExpense> _sortedExpenses;
final StreamSink<List<Expense>> expensesSink;
...
This is based on the privacy of the variables you're extracting.
For example, the following widget:
Text(_count.toString())
will generate:
class MyName extends StatelessWidget {
const MyName({
Key key,
#required int count,
}) : _count = count, super(key: key);
final int _count;
#override
Widget build(BuildContext context) {
return Text(_count.toString());
}
}
while this widget:
Text(count.toString())
will create:
class MyName extends StatelessWidget {
const MyName({
Key key,
#required this.count,
}) : super(key: key);
final int count;
#override
Widget build(BuildContext context) {
return Text(count.toString());
}
}