functional_widget 0.10.2 copy "functional_widget: ^0.10.2" to clipboard
functional_widget: ^0.10.2 copied to clipboard

A code generator that generates widget classes from their implementation as a function.

Build pub package pub package

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:

... 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 as dependencies.
  • 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:

There are a few ways to do so:

  • With the shorthand @hwidget decorator:

    @hwidget // Creates a HookWidget
    Widget example(int foo, String bar) => Container();
    
    @hcwidget // Creates a HookConsumerWidget
    Widget example(WidgetRef ref, int foo, String bar) => Container();
    
    @cwidget // Creates a ConsumerWidget
    Widget example(WidgetRef ref, int foo, String bar) => Container();
    
  • 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();
    

In any cases, you will need to install the corresponding package separately, by adding either flutter_hooks/flutter_riverpod or hooks_riverpod to your 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);

Private vs public widgets #

In order to allow for private function definitions but exported widgets, all decorated widget functions with a single underscore will generate an exported widget.

@swidget
Widget _foo(BuildContext context, int value, { int value2 }) {
  return Text('$value $value2');
}

// USAGE

Foo(42, value2: 24);

In order to keep generated widget private, do use two underscores:

@swidget
Widget __foo(BuildContext context, int value, { int value2 }) {
  return Text('$value $value2');
}

// USAGE

_Foo(42, value2: 24);

Sponsors #

256
likes
140
points
5.26k
downloads

Publisher

verified publisherdash-overflow.net

Weekly Downloads

A code generator that generates widget classes from their implementation as a function.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

analyzer, build, build_config, code_builder, collection, functional_widget_annotation, meta, source_gen

More

Packages that depend on functional_widget