wolfrevokcats
wolfrevokcats

Reputation: 75

Create a not final widget

I wonder is it possible to declare a widget then after that edit the properties in the widget. See example below:

InputDecoration temp = new InputDecoration(
  labelText: label,
  labelStyle: TextStyle(color: Colors.white),
  // ...
);

and then

temp.suffixIcon = IconButton(icon: Icons.sth);

I can't seems to get it working as it return suffixIcon is final. Any help much appreciated.

Upvotes: 0

Views: 49

Answers (2)

Marcel
Marcel

Reputation: 9569

What you're trying to do is imperative programming: You have a program state and whenever it changes, you update all the necessary UI elements manually.

Flutter is a reactive UI framework. Semi-mathematically speaking, that means there is some state s and a build method f and when the state changes, the framework builds the new widget subtree by calling your function f(s).

More specifically, you don't want to change the concrete attributes of your child widgets—you don't even want to be able to do that because that goes against the reactive paradigm. Rather change the state of the program and tell the framework that the state changed. It will then re-render all the child widgets with the new attributes. Don't worry about performance too much, Flutter is heavily optimized in that regard.

Widgets with changing state are StatefulWidgets in Flutter. Every StatefulWidget has a corresponding State, which can also contain mutable (non-final) attributes like these:

bool _useFirstIcon = true;

When you change the state, use the setState function in the State like this to notify the framework about the change:

void _changeTheState() {
  setState(() => _useFirstIcon = false);
}

That tells the framework to re-render that subtree. Basically, it means your build method will be called when the next frame is drawn. There, you should return different widget trees depending on the state (your _useFirstIcon attribute).

return SomeWidget(
  decoration: new InputDecoration(
    suffixIcon: IconButton(
      icon: _useFirstIcon ? Icons.someIcon : Icons.someOtherIcon,
      onPressed: _changeTheState,
    ),
  ),
);

Note that sometimes, you do want to access the state of a widget from the parent widget. That is—arguably somewhat inelegantly—achieved by providing some sort of controller to the child widget and the child widget modifies the state of the controller to make parts of its own state accessible to the parent. This architecture is for example used in the TextField using the TextController.

Upvotes: 0

Rémi Rousselet
Rémi Rousselet

Reputation: 276951

No. That is not possible (or should be avoided as much as possible).

The reason for this is, the same widget can be inserted in multiple locations of the widget tree.

For example, it's totally reasonable to do:

Widget foo = Something();

return Row(
  children: [
    foo,
    foo,
  ]
);

Upvotes: 1

Related Questions