How do I add commands within a widget tree? - flutter

In flutter/dart, how do I add commands (for loops, if/then etc) within widget trees?
So let's say we have a tree
Scaffold(...)
How can I add command syntax in there. The only thing possible is ternary operators. (as far as I'm aware)

You can do that inside build() like:
Widget build(context) {
// use for loop or if else or anything you need
return Scaffold(...);
}
The better way to do is by creating a dedicated method like
void _doSomethingHere() {
// use for, if-else etc
}
And use this method in button pressed like:
RaisedButton(onPressed: _doSomething)
If you want to perform some action before build(), you can override initState() like:
void initState() {
super.initState();
// use for, if-else
}

You can do that inside initState() if you are using StatefulWidget. Else do that inside build() method.

The main reason why you can't use control structures(if-else) or loops(for,while,do-while) while creating your UI as a widget(-tree) is because of the way flutter tries to understand what UI are you trying to create.
The control structure if just accepts a block of code and executes it if the condition given to it satisfies.
if(condition)
{
//statment(s) to be executed
}
Whereas ternary operator simply replaces a particular line of code/value based on the condition given to it.
(condition)
?
value-or-code-to-replaced-if-the-condition-satifies
:
value-or-code-to-replaced-if-the-condition-does-not-satisfy;
Since we just return the UI, a widget tree to the build function using return keyword, adding control structures like if practically does not make any sense.

Related

Flutter - Reuse same custom widget class for instances appear not at same time

In shorter word, my question is how to call child's initState() again on parent's setState().
I need to reuse a widget class for multiple instances. I need the widgets to appear in turn like below where I can use setState() to switch between them.
bool showthefirstone = true;
#override
Widget build(BuildContext context) {
...
TheWidget it = showthefirstone ? TheWidget(...) : TheWidget(..);
...
}
The later one's initState() is not called. No problem showing them both together along at the same time. The issue only occurs upon setState().
For those who don't understand, this trigger the change
setState((){showthefirstone = !showthefirstone})
It's the same answer with different question. My question is more generic. At least works for my case.
https://stackoverflow.com/a/70789848/1297048

What's the correct way to use methods from a sibling widget?

I am trying to clean my code by putting different widgets in different files/classes so it's not all inside the same main widget.
So right now I have this:
MainWidget {
Scaffold {
body: MyWebView(),
bottomNavigationBar: MyNavBar(),
}
}
Both are stateful widgets.
So now I'm wondering: how can I use methods from MyWebView from inside MyNavBar?
I've tried MyWebView.of(context).method() and even do a middle method inside MainWidget to try and call the methods from the parent widget always, but it's always "null". I've seen people mentioning PrivateKeys but many say this is an old way of doing things and I shouldn't rely on that.
So how can I do this?
I would need more details to provide an exact solution but based on your question this is the answer:
You have two options to do what you need
Lift Up The state:
This means In some situations, there are some states that are needed and shared among two or more sibling widgets, what we can do about it is to move those states to the parent widget, and provide it to the children, either by passing the variables and functions or using inherited-widget-based methods like using provider framework. so in your case, you can keep the function and state in the main widget, and pass it to both children.
Use a Key to access the MyWebView widget's state: as you mentioned in the comments, this is exactly done as you said :
you'd have to do it on the MainWidget, pass it onto the MyWebView(key: key), and then pass it to MyNavBar(webviewKey: key) to use it there
if you want to pass variable instead use typedef,
first declare outside MyWebview class :
let me guess, you need some int value from webview to pass it into navbar class.
typedef OndataProcessed = void Function(int valueIneed);
class MyWebView {
--------
final OndataProcessed ondataprocess;
and in methods in my webview
int someMethod (){
int result = blabla;
ondataprocess(result);
}
and finally :
MainWidget {
int resultfromwebview;
Scaffold {
body: MyWebView(ondataprocess: (int result){
setstate((){resultfromwebview = result})
}),
bottomNavigationBar: MyNavBar(index: result),
}
}

How can I listen to a String variable change and perform an action when there is a change?

Is it possible to execute a function, lets call it myFunction() if a variable _myString is changed, but have this happen on the fly?
What I have is a textfield with a controller
var _myString;
const TextField(
controller:_controller
)
Now elsewhere in my widget tree, I have a button that can change the value of _myString, in this case I'm changing '_myString' to 'Testing'
GestureDetector(
onTap:(){ _myString = 'Testing'; }
child: Text('Testing')
)
Now what I'm hoping to achieve is that when the value of _myString changes in any way, I can perform some action of my choosing. In this case, I want to edit the TextField using the _controller, but I don't only want to do that, but a few other things, so I think its better to listen to changes in that variable and then execute a function
void myFunction(){
///Do some stuff
}
I'm using riverpod for state management in my app, and I was thinking I could try to use it, but have no idea how to use it to watch a single variable, I'm more familiar with using it for entire widgets. Alternatively using riverpod for something like this might be overkill.
I just don't know how to approach this problem, so any guidance would be really appreciated!
I believe you could use a ValueNotifier for this, a value notifier is a class that holds some value and "notifies" its listeners when this value changes. It is a simpler version of ChangeNotifier:
ValueNotifier<String> _myString = ValueNotifier<String>('');
With the above, whenever you want to read or write the value, use the value getter/setter:
print(_myString.value);
_myString.value = 'some value';
Now, to listen to changes you should use the addListener method:
#override
initState() {
// update _controller with value whenever _myString changes
_myString.addListener(() => _controller.text = _myString.value);
// print value on change
_myString.addListener(() => print(_myString.value));
// do stuff
_myString.addListener(myFunction)
}

In Flutter, is there a diference if I place my methods inside or outside a widget's build method?

I'm starting with Flutter and got some questions about where is the right place to put my methods, inside or outside the widget's build method?
Example:
I have my Widget and create a method showText. Is there a diference if I place this method inside the widget's build method or outside it(as a method of the class itself)?
It seems to work either way.
Thanks
If you have some reusable piece of code, consider outsourcing it into its own Widget.
If that's too much boilerplate, considering helper build-methods is a valid option.
To the Dart compiler, it doesn't really matter where you put these methods, but for less indention and better readability, I recommend putting them inside the class.
Also, consider naming the methods _build.... That makes it clear to readers that they are helper build methods. The underscore also ensures that the analyzer warns you if you change the original build method and the helper method becomes unused.
Here's an example:
class A extends StatelessWidget {
Widget build(BuildContext context) {
return Column(
children: [
_buildTitle(context),
_buildContent(context),
],
);
}
Widget _buildTitle(BuildContext context) { ... }
Widget _buildContent(BuildContext context) { ... }
}

How can you get setState.of(context) in Flutter?

I have an app with a ModalProgresHUD on most pages. Usually I can pass a fucntion to, for example, onTap, to any widget in this tree, to turn this spinner on/off.
But sometimes this seems difficult and I'd like to access the fields and/or setState on a State somewhere else, up the WidgetTree.
One option seems to be to move all the logic into the top Widget, and pass handlers down to access these methods, but that feels cludgy.
class StatefullPage ..... {
String _someImportantField;
set someImportantField(String newValue) {
_someImportantField = newValue;
if(mounted) setState((){});
}
...
}
class StateOfSomethingElse ... {
Future doSomeWorkThatAffectsTheParent() async {
await something.then((String newResult) {
State.of(context).someImportantField = newResult;// HOW TO DO THIS
}
...
}
What kind of state management do you use? It looks that you are simply using setState and there's no problem with that. But to do the sort of think you want i think it's better to use something like provider or redux to handle the state of your app.
Using Provider for example, you can provide a value on the top of your tree and can get this value anywhere on your widget tree to do your logic.