Flutter: how to pass arguments to a Widget using a variable?
Asked Answered
B

2

5

Here's some pseudo code showing what I'm trying to achieve:

Text txt(text, [subtitle = false]) {
  final params = subtitle
      ? {
          'textAlign': TextAlign.center,
          'style': TextStyle(color: Colors.purple)
        }
      : {
          'textAlign': TextAlign.left,
          'style': TextStyle(color: Colors.black54)
        };

  return Text(
    text,
    ...params,
  );
}

Is it possible to pass variable arguments to a Flutter widget? Please keep in mind that the Text widget is just an example and not the focus of my question, it could be any other Flutter widget, like Container, or SizedBox, for example.

Buttonhook answered 19/1, 2021 at 17:35 Comment(0)
M
2

How to pass arguments to a widget using a variable:

tldr; We have to turn our thinking on its head a bit. Data can be passed to the called widget when you navigate to it by using final arguments with default values in the destination widget. Using an optional function you can get data back from the 'child' (destination) widget.

In the destination stateful widget you create a final variable;

 final int boxIndex;

In the destination constructor give your final variable a constant default value

DestinationClassConstructor({Key? key, this.boxIndex = -1}): super(key: key);

You can add methods to the stateful widget class that use the value in some significant way:

e.g.

  bool isEditing() {
    return this.boxIndex != -1;
  }

In the source widget that calls the destination widget, you can pass in a value other than the default.

DestinationClassConstructor(boxIndex: 123),

In the destination widgets state content class you could use the value directly or call the method above:

e.g.

widget.isEditing()
widget.boxIndex,

The real power of this method happens when you decide that you can pass Functions as parameters:

e.g.

In your destination stateful widget create the nullable function call with its constructor argument:

final Function()? destinationWidgetTapped;

DestinationClassConstructor({Key? key, this.destinationWidgetTapped}): super(key: key);

Note: In this case the function variable is assigned a default value of null.

Somewhere in your destination content state widget call the function:

if (widget.destinationTapped != null) widget.destinationWidgetTapped!();

Then in your source widget make the call as follows:

DestinationClassConstructor(destinationWidgetTapped: () {
                        print('this code from the source widget executes after the child widget event is invoked');

                        Navigator.of(context).pop(); //pop the child widget
                      },

Which is fine and very useful when you consider that you can also pass back a value along with the function call.

final Function(String)? destinationWidgetTapped;

DestinationClassConstructor({Key? key, this.destinationWidgetTapped}): super(key: key);

Somewhere in your destination content state widget call the function:

if (widget.destinationTapped != null) widget.destinationWidgetTapped!('Hello from the Destination Content State Widget');

Then you can receive data like this:

DestinationClassConstructor(destinationWidgetTapped: (value) { 
    print('Data is passed from the destination widget with a string value of : $value');
    Navigator.of(context).pop();
},

Nota Bene:

Function(String) can also be written as ValueChanged<String>

We can further extrapolate that any object may be passed:

Function(Object?) written as ValueChanged<Object?>

And the argument might be better written as:

final ValueChanged<Object?>? onValueChanged;
DestinationClassConstructor({Key? key, this.onValueChanged}): super(key: key);

Which would allow one to send any data object, array, json, map, string, int, bool, etc. while maintaining access to a completion handler so that one could access the variable data in both directions.

Mcdonnell answered 2/9, 2021 at 2:53 Comment(0)
F
0

In one of my apps

      Text(listItem.name,
          style: TextStyle(
              decoration: listItem.checked
                  ? TextDecoration.lineThrough
                  : TextDecoration.none)),

works perfectly fine, listItem.checked is of boolean type.

This question has more examples: How to use conditional statement within child attribute of a Flutter Widget (Center Widget)

Flatways answered 19/1, 2021 at 17:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.