This might be not technical question,however, I read that whenever you want to change StatefullWidget state you need to call setState() function. i gave a test for EditText() widget and use the EditingTextController as widget controller, i called the controller.text = "some text"from user-defined function without calling setState() function and the value of the EditText() changed to be some text !
i would like to know how this done? i read the documentation and it says EditingTextController will change the value of the widget but we already know that in order to change
State Full Widget state you need to call setState()
Kind of this is true. But to change the state in Flutter you have other options, and setState(() {}); is only one of them. Another option is to create Notifier -> listener, then set the listener to listen for the Notifier, like this TextFormField(controller: _controller,...) so any update on the Notifier(controller), will notify the listener(TextFormField) to update itself.
e.g:
//...
final _controller = TextEditingController();
//...
child: TextFormField(
controller: _controller,
decoration: InputDecoration(border: OutlineInputBorder()),
),
in this example:
_controller: is a ChangeNotifier.
TextFormField: is a listener to this ChangeNotifier(_controller).
and once you call this _controller.text=.. the _controller (which is consider as ChangeNotifier see this.) "will notify all the listeners of this TextEditingController that they need to update", so it will give you same result as using setState(() {}); or Stream/StreamBuilder or Future/FutureBuilder...etc.
Related
I have created a function which return 4 textfields in column and I have called that function from 4 different containers, now how do I know from which container textfields are being changed because all the textfields are common to different containers. Thanks in advance.
in general you can handle the changes in Textfield in two way
1- Using onChanged() callback
TextField(
onChanged: (text) {
print('First text field: $text');
},
),
2- Using a TextEditingController
you create a controller
final myController = TextEditingController();
Connect the TextEditingController to a text field.
TextField(
controller: myController,
),
Create a function to print the latest value.
void _printLatestValue() {
print('Second text field: ${myController.text}');
}
Listen to the controller for changes.
#override
void initState() {
super.initState();
// Start listening to changes.
myController.addListener(_printLatestValue);
}
in your case you can pass controllers to your function and listen to it
What about using keys. You can choose unique keys for each of the different textfields(maybe you can generate keys when you programmatically generate the textfields). Alternatively, you can assign unique keys to the containers as well.
flutter textfield has onChanged property, you can do inside onChanged
As you know, it is a basic requirement that; after the user makes an entry in an Autocomplete field (either by entering a new value or selecting an existing value from the dropdown list) and then press a 'Submit' button or 'Delete' button (say, to update the database); the old entry in the TextFormField should be cleared automatically for the next entry.
How can this be programmatically done in a simple way (for example, like Autocomplete.TextFormField.clear ) in Flutter?
I have tried several ways, but am unable to access/ modify the TextEditingController from an outside function.
Thank you in advance for any advice, please!
I am posting this for the benefit of whoever who reads this post, having a similar requirement.
A solution lies with flutter_typeahead widget, found here:
https://pub.dev/packages/flutter_typeahead
It could be used instead of RawAutocomplete or Autocomplete widgets.
You can use a RawAutocomplete to access the text editing controller from outside the Autocomplete. The RawAutocomplete is similar to Autocomplete, but it also provides the textEditingController and focusNode properties.
Note that if you pass in a textEditingController, you must also provide a non-null focusNode and fieldViewBuilder.
An example of modifying the textEditingController from outside the Autocomplete can be seen below.
final _controller = TextEditingController();
final _focusNode = FocusNode();
Widget build(BuildContext context) {
return RawAutocomplete<String>(
textEditingController: _controller,
focusNode: _focusNode,
fieldViewBuilder: (context, textEditingController, focusNode, onFieldSubmitted) =>
TextFormField(controller: _controller),
...
)};
//Then in your outside function
setState(() {
_controller.clear();
};
My screen has an AnimatedBackground which is continuously keep looping like this
Stack(
children: [
AnimatedContainer(
duration: Duration(seconds: 2),
onEnd: () {
setState(() {
//doing some animation repeatedly
});
},
),
StreamBuilder(
//keeping rebuild because of the above setState
),
],
),
I am so stuck right now rebuild is so often, because of the setState() (the problem)
I want to use StreamBuilder inside this screen because the information is continuously changing
how not to loop StreamBuilder? how to achieve this?
Since setState({}) method updates the whole widget where you call it, you need in some way separate your widgets. The idea is that the widget where you call setState method should be lower in the widget's tree and the widget, which contains StreamBuilder is upper. As a result calling setState method won't trigger widget with StreamBuilder to rerun.
I am using the following to spread Map values inside a stack. All widgets are positioned.
...widgets.values,
This works fine, however when I used the Map.update function to update the position of the Widgets at a certain key, there is no change to the widgets position.
if (widgets.containsKey(uniqueValue)) {
setState(() {
widgets.update(
uniqueValue,
(value) => Box(
uuid: uniqueValue,
startPosLeft: newPos,
startPostop: newPos,
onMoved: (uniqueValue) => _boxMoved(uniqueValue),
),
);
});
I can see the widget is being updated if I print out the Map Widget position, but it wont move.
Any idea what might be going wrong here?
The problem here was the state not being updated inside the child widget.
My solution was to create a behavioral subject with RXDart and bind the stream listen function in the widgets initState function.
Bloc Class
final boxMovementController = BehaviorSubject<String>();
Function(List<String>) get inputMovingBoxId =>
boxMovementController.sink.add;
Child Widget
streamSubscription = bloc.boxMovementController.listen((value) {
setState(() {});
});
The widget would then call setState whenever it detected an addition to the behavioral Subject stream.
The parent would then sink.add to the stream whenever positioned changed therefore triggering a state update on the child.
Parent Widget
bloc.boxMovementController(value);
Hopefully this is useful to others facing a similar issue.
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.
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,
]
);
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.