functional_widget 0.8.1 functional_widget: ^0.8.1 copied to clipboard
A code generator that generates widget classes from their implementation as a function.
Widgets are cool. But classes are quite verbose:
class Foo extends StatelessWidget {
final int value;
final int value2;
const Foo({Key key, this.value, this.value2}) : super(key: key);
@override
Widget build(BuildContext context) {
return Text('$value $value2');
}
}
So much code for something that could be done much better using a plain function:
Widget foo(BuildContext context, { int value, int value2 }) {
return Text('$value $value2');
}
The problem is, using functions instead of classes is not recommended:
- https://stackoverflow.com/questions/53234825/what-is-the-difference-between-functions-and-classes-to-create-widgets/53234826#53234826
- https://github.com/flutter/flutter/issues/19269
... Or is it?
functional_widgets, is an attempt to solve this issue, using a code generator.
Simply write your widget as a function, decorate it with a @swidget
, and then
this library will generate a class for you to use.
As the added benefit, you also get for free the ability to inspect the parameters passed to your widgets in the devtool
Example #
You write:
@swidget
Widget foo(BuildContext context, int value) {
return Text('$value');
}
It generates:
class Foo extends StatelessWidget {
const Foo(this.value, {Key key}) : super(key: key);
final int value;
@override
Widget build(BuildContext context) {
return foo(context, value);
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(IntProperty('value', value));
}
}
And then you use it:
runApp(
Foo(42)
);
How to use #
Install (builder) #
There are a few separate packages you need to install:
functional_widget_annotation
, a package containing decorators. You must install it asdependencies
.functional_widget
, a code-generator that uses the decorators from the previous packages to generate your widget.build_runner
, a dependency that all applications using code-generation should have
Your pubspec.yaml
should look like:
dependencies:
functional_widget_annotation: ^0.8.0
dev_dependencies:
functional_widget: ^0.8.0
build_runner: ^1.9.0
That's it!
You can then start the code-generator with:
flutter pub run build_runner watch
Customize the output #
It is possible to customize the output of the generator by using different decorators or configuring default values in build.yaml
file.
build.yaml
change the default behavior of a configuration.
# build.yaml
targets:
$default:
builders:
functional_widget:
options:
# Default values:
debugFillProperties: false
widgetType: stateless # or 'hook'
FunctionalWidget
decorator will override the default behavior for one specific widget.
@FunctionalWidget(
debugFillProperties: true,
widgetType: FunctionalWidgetType.hook,
)
Widget foo() => Container();
debugFillProperties override #
Widgets can be override debugFillProperties
to display custom fields on the widget inspector. functional_widget
offer to generate these bits for your, by enabling debugFillProperties
option.
For this to work, it is required to add the following import:
import 'package:flutter/foundation.dart';
Example:
(You write)
import 'package:flutter/foundation.dart';
@swidget
Widget example(int foo, String bar) => Container();
(It generates)
class Example extends StatelessWidget {
const Example(this.foo, this.bar, {Key key}) : super(key: key);
final int foo;
final String bar;
@override
Widget build(BuildContext _context) => example(foo, bar);
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(IntProperty('foo', foo));
properties.add(StringProperty('bar', bar));
}
}
Generate different type of widgets #
By default, the generated widget by @FunctionalWidget()
is a StatelessWidget
.
It is possible to generate a HookWidget
instead (from https://github.com/rrousselGit/flutter_hooks)
There are a few ways to do so:
-
Through
build.yaml
:# build.yaml targets: $default: builders: functional_widget: options: widgetType: hook
then used as:
@FunctionalWidget() Widget example(int foo, String bar) => Container();
-
With parameters on the
@FunctionalWidget
decorator:@FunctionalWidget(widgetType: FunctionalWidgetType.hook) Widget example(int foo, String bar) => Container();
-
With the shorthand
@hwidget
decorator:@hwidget Widget example(int foo, String bar) => Container();
In any cases, flutter_hooks
must be added as a separate dependency in the pubspec.yaml
dependencies:
flutter_hooks: # some version number
All the potential function prototypes #
functional_widget will inject widget specific parameters if you ask for them. You can potentially write any of the following:
Widget foo();
Widget foo(BuildContext context);
Widget foo(Key key);
Widget foo(BuildContext context, Key key);
Widget foo(Key key, BuildContext context);
You can then add however many arguments you like after the previously defined arguments. They will then be added to the class constructor and as a widget field:
- positional
@swidget
Widget foo(int value) => Text(value.toString());
// USAGE
Foo(42);
- named:
@swidget
Widget foo({int value}) => Text(value.toString());
// USAGE
Foo(value: 42);
- A bit of everything:
@swidget
Widget foo(BuildContext context, int value, { int value2 }) {
return Text('$value $value2');
}
// USAGE
Foo(42, value2: 24);