I am using the Selector widget as shown below
Nothing wrong with it's build method, only call it when the value changes.
But when I use Devtools or android studio to track widget rebuild it's showing that the Selector it self rebuild when I am scrolling whether in a list or any other widget that support scrolling.
Yes the Selector didn't call the build method until the value changes but is this normal ?
Using Devtools:
As you can see the others (2) Selectors doesn't have to be triggers but yet they are.
sorry for my bad English, I can explain in another way in the comment section if you didn't understand me and thanks in advance.
edit:
I guess I know why the selector is rebuilding it's self, because I am using the provider class as listener to scroll controller direction with changenotifier.
here the code
in provider class:
bool isHideHomeScreenTabBar = false;
void hideShowTabBar(ScrollDirection scrollDirection) {
isHideHomeScreenTabBar = scrollDirection == ScrollDirection.reverse;
notifyListeners();
}
in my Home screen:
_scrollController.addListener(() {
Provider.of<AppProvider>(context, listen: false).hideShowTabBar(
_scrollController.position.userScrollDirection);
});
So basically the provider trigger changenotifier with every scroll I do and the selector get notified and rebuild it's self but if the value didn't change the selector won't trigger the build method (so it works fine for the child and the widget in the build method of the selector).
But even so is this normal ? and why, The other selectors aren't even listening to the scroll direction.
Anyway I found an alternative way to do this (with an animation controller) but it would be nice if someone could explain what is happening here, it's important for me at least because I might use another state management.
I know what was happing.
I am using 1 class for the provider that contains all the values I need with many methods using notifyListeners, however I thought it's ok to use 1 provider class if I use Selector for every value I had so anything that need rebuild will only rebuild when it's need it.
The problem with this approach is that with every notifyListeners call every selector got notified and rebuild it self (in my case when any scrolling detected) but the selector doesn't call the builder if the value not changed.
The fix is to make some condition that check the old value and the new value before calling notifyListeners, that works prefect in my case, this decrease the rebuilding happing when I scroll to only 1 as it's intended to be, however the other selectors in the same class also rebuild (I guess because they are all in the same class so every notifyListeners call effect them).
At the end if you end up with similar issue it is better to use ProxyProvider or any way that let you use multiple providres, beside the benefit of a better project architecture and disposing it is way better to have more control over the state.
Thanks to RĂ©mi Rousselet Riverpod it's way better than ProxyProvider and I am using it and it's awesome so consider Riverpod if you want to use ProxyProvider.
Related
In Android, every Fragment can partecipate in populating the options menu (aka "appBar actions", in flutter terms) of the activity, using the Fragment.onCreateOptionsMenu callback.
I would like a similar mechanism also in flutter, i.e. that some widgets are able to add buttons ("actions") to the AppBar.
Threads had already been opened on this topic, but none reports a fully functional example and contains solutions to the precise technical problem I encountered.
To do this, I had thought of using the following 'typical' structure:
a StatefulWidget -to which I have given name ScaffoldHandler (ScaffoldHandlerWidget/ScaffoldHandlerState)- which wraps the entire Scaffold, and which uses InheritedWidget so that widgets further down the widgets tree can get a reference to it in an optimal way (using the classic of() method which executes dependOnInheritedWidgetOfExactType()).
ScaffoldHandlerState keeps in a field the actions set by the various children, and supplies them to the app-bar.
a widget that creates the AppBar. In the build() method it gets the actions to be displayed calling ScaffoldHandlerState.of().
mixin ScaffoldChild on State, which applied to a widget gives it the ability to add actions to ScaffoldHandlerState.
Internally, ScaffoldChild executes ScaffoldHandlerState.of() in didChangeDependencies() (to add actions) and in deactivate() (to remove them).
I originally used initState() and dispose() but this did not handle the case where a ScaffoldChild changes position while not being permanently removed from the widgets tree.
The problem I encountered is that ScaffoldAppBar.build is executed before ScaffoldChild.didChangeDependencies, so when the app-bar is created, ScaffoldChild still has to put its actions in ScaffoldHandlerState.
The curious thing is that this problem is due to the simple linear order in which ScaffoldAppBar and ScaffoldChild are inserted in the page: if instead of a top app-bar I want to create a bottom app-bar, the problem is not there because ScaffoldChild.didChangeDependencies would run before ScaffoldAppBar.build.
As a workaround to overcome the problem, I have inserted in ScaffoldChild.didChangeDependencies a call to scaffoldHandler.setState scheduled by WidgetsBinding.instance.addPostFrameCallback(): thus, after the actions have been inserted in ScaffoldHandler, the app-bar is updated with the new actions.
However, this solution seems like a hack to me.
In stackoverflow I see a lot of problems solved with addPostFrameCallback + setState, and sometimes that solution avoids really understanding where it goes wrong; I am interested in understanding if there are better solutions because my purpose, as well as practical, was to better understand the lifecycle of widgets.
Is there a better solution?
This is my code:
DartPad or Gist
(I tried to shorten it as much as possible, but sorry if it's not really short)
I am trying to understand the method didChangeDependencies and according to the definition
It is Called when a dependency of this State object changes.
what do they mean by this. My guess is when properties in the state you manage per screen change. Am I right. Please I would love to understand better.
Try to think of it the same as initState but just a little later.
initstate is called before the state loads its dependencies and for that reason no context is available and you get an error for that if u use context in initstate. However, didChangeDependencies is called just few moments after the state loads its dependencies and context is available at this moment so here you can use context.
In case BuildContext.dependOnInheritedWigetOfExactType called, or in case the widget is been moved inside of the element tree, didChangeDependencies will is always called.
What will happen if An event is added to the bloc being passed inside the BlocProvider.value?
Will the event gets added before or after i get to the page?
And Is Blocprovider.value an ideal way to avoid adding events to bloc in initState() method?
I'm trying to avoid initstate as I'm listening to Stream of data from firebase (this event need to be called only once).
I found a workaround for this,
Using the approach stated above will make the LoadProductFromStream event get called even before getting to /opening the StreamproductPage().
To avoid this a simple and efficient approach could be used instead
create a wrapper widget
create the body (the main widget to display results)
Below is an image attached to explain this
Wrapper widget is where the bloc will be created/initialized
and where LoadProductFromStream() event will be added to the bloc
In conclusion
This way we only add LoadFromStream() event to bloc when we get to StreamproductPage
Takeaway
BlocProvider(create:(context)=> xyzBloc()) // can automatically close bloc
while
BlocProvider.value() // doesn't close bloc automatically
(i stand to be corrected)
I have a method in my parent widget that runs and updates a boolean. Whenever the value is changed, a method needs to be run in a child widget, using the changed value. What is the best way to trigger that action from the parent?
Both widgets are stateful widgets.
You could either inject the parent's method as a callback to the child or dispatch a notification from the child and then listen for it in the parent.
The latter is a cleaner and more reusable way, since it'll improve your child reusability.
You can check here for a very good guide on how to do it!
The answer from magicleon94 was pretty good, and would have worked if I needed to update a widget with new information. I will probably reference that for some other issues I am working on. For this issue, I needed to run a method to return markers for a mapWidget, based on data from a parent, when that data changed. I found the best way to do that was using a streamController, as outlined by this StackOverflow post. Whenever I updated the value, I called add on the stream, and then received the update in my child class.
I understand the general approach to building UI layouts using Flutter. However, I'm still unclear which classes or UI widgets require a .build() method when I'm creating my own vs. using the defaults generated by the project.
I haven't found a clear explanation yet - even in the Flutter tutorials. They all seem to just gloss over how "the build method takes a BuildContext" and then go on to the next subject without explaining further.
Does anyone have a succinct explanation of the build method and when it is or isn't needed? And more specifically: what does it actually do?
build() method describes the part of the user interface represented by this widget.
The framework calls this method in a number of different situations:
After calling initState.
After calling didUpdateWidget.
After receiving a call to setState.
After a dependency of this State object changes (e.g., an InheritedWidget referenced by the previous build changes).
After calling deactivate and then reinserting the State object into the tree at another location.
You can find more Here
TLDR: The build methode is used to create a new widget tree by placing the Widget reurned in the page tree. This method is essentially called when you create or update the widget (by calling setState((){})