I've been developing in Flutter for a few months and I'm not yet very experienced. These days I'm working on an app that I didn't create from the beginning and I'm having a strange problem, unfortunately I can't paste too much pieces of code but I try to explain the wrong behavior.
The state of the app is contained in an InheritedWidget that is called before all the others. For example, in this InheritedWidget there is a value that must always be visible at the top of the app (in the AppBar). The problem is that if at runtime this value is changed in the InheritedWidget, the view shows the previous value (as if it wasn't updated), but if I do Navigator.push() to a new page, the AppBar shows the correct value (i.e. the updated one). If I pop to the previous page, the old value reappears in the AppBar. If I put the app in the background and bring it back to the foreground, the correct value finally appears.
It seems that the view does not update even if the value changes in the InheritedWidget. I specify that before being displayed, this value is extracted directly from the InheritedWidget using context.dependOnInheritedWidgetOfExactType<InheritedWidgetName>(). I also specify that "updateShouldNotify" is set this way:
#override
bool updateShouldNotify(Session oldWidget) {
return true;
}
I wanted to ask if anyone knows what might be causing this problem.
Thanks in advance.
Related
I am employing Riverpod for state management via StateNotifierProvider. My switch button just won't enable upon clicking and thus no state changes to effect theme mode switching. I have spent a ton of hours researching similar issues but none like mine as I am not using setState(). I expect the state of the button to change on clicking on dragging but the thumb of the switch just returns to its initial off position. Please help me with what I am doing wrong. Here are snapshots of my main.dart, home_screen.dart, and the theme controller notifier as I am unable to copy and paste my code correctly as advised with 4 spaces.
You need to update the state (not the _isDarkvariable) this way:
toggleTheme(bool value) {
state = value;
_safePrefs;
}
The image is not complete, so I can't see the use of _isDark variable (Probably nothing). But You shoul be fine now, at least updating the state.
I'm a new Flutter developer and I have a problem, which I haven't been able to solve yet, even if I tried a lot.
I'm developing an App, where at some point a Dialog is opened(with showDialog()). In this Dialog there are 2 AutoCompleteTextField:
In the first one, the data will always be the same. So there is a list and the user needs to choose one of the choices. First AutoCompleteTextField code
In the second one, the data to be shown depends on the previous choice. In other words,
whenever an item from the previous list is chosen, the subdata of the item will be requested. Second AutoCompleteTextField code
The required data is fetched properly, however the dialog is not refreshing state so the suggestions of the second AutoCompleteTextField appears empty. When I close and enter again the suggestions of the second appears as they should.
To get notified when the data changes I use ChangeNotifier and Provider, but doesn´t refresh the Dialog (ChangeNotifier class). I also use StatefulBuilder to be able to use setState, but again, doesn´t refresh (Dialog code).
I would like to know if there is any other way to refresh the Dialog. Thank you!
PD: This is my first question in StackOverflow. I tried my best.
I think you need to use Provider.of(context) to be able to listen to the updates and refresh or add/update the data.
Provider.of(context)
I would create a widget class instead of the _widgetTask function and then use Provider.of(context) inside the widget build function like following (I think you can also try to add it inside the _widgetTask function but I dont know if this would work).
class WidgetTask extends StatelessWidget {
//WidgetTask contructor here..
#override
Widget build(BuildContext context) {
final odooData = Provider.of<OdooData>(context);
And then use the odooData to access the data/functions you need to update/listen to from the provider.
Also you can wrap the widget with GestureDetector so that you can update the widget upon tapping using the OnTap property.
flutterdartdialogrefreshproviderconsumer
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.
I have two app 'screens', A and B. Both set the SystemChrome.setEnabledSystemUIOverlays in the build methods.
A sets as per
Widget build(BuildContext context) {
SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values);
return WillPopScope(
....
whilst B sets as per
Widget build(BuildContext context) {
if (MediaQuery.of(context).orientation == Orientation.landscape) {
SystemChrome.setEnabledSystemUIOverlays([]);
}
else {
SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values);
}
return WillPopScope(
.....
Navigating from A to B in portrait works fine. If however I enter landscape in B flutter removes the overlays and then re-implements them immediately, ie I see the overlay disappear and reappear quickly. If I remove the overlay line completely from A, B works fine. Its like B is rebuilt followed by A but in the background. Is that a thing?
I'm navigating like so
Navigator.push(context, MaterialPageRoute(builder: (mContext) => DataForm(file: _file)))
I've been tying to track this bug for three days. For reference overlays are set here an only here in all my code. The issue only occurs on Android.
I appreciate the first response will be 'its in your code we need to see it to solve it'. I tried reproducing the issue in 'minimal code' to post an example but I cannot get the error to reoccur and my code is so extensive I am not sure how to show it all.
As per the title I am instead asking what scenarios might cause screen A overlay setting to influence screen B at each build.
Thanks in advance!
Answering my own question after 5 days of tracking down my bug in the hope it might help some else if future. I suspect those with experience will be thinking 'yes of course and' so this is probably more for someone new like myself.
SystemUIOverlay is like a global variable that persists in the app and is implemented across screens automatically. A new screen/code can change this overlay setting at any time and know if will be applied globally and retrospectively to all screens. In my case SystemUIOverlay is set in build so any action in Screen A that forces a rebuild will therefore enforce the update and apply the global overlay value to B.
Even though Screen A is not showing it can continue to rebuild in the background if triggered, even when Screen B is opened. Therefore anything triggering a rebuild of A whilst B is open means B will adopt A's overlay setting globally. This was the result I was seeing.
A couple of examples:
As referenced here, MediaQuery.of will cause your widget to rebuild automatically whenever the MediaQueryData changes (e.g., if the user rotates their device). So for instance if you include 'MediaQuery.of' anywhere in you build of Screen A, a build can occur even when not in focus. This rebuild of A then enforces it's overlay value globally which is picked up by B whilst it is open.
In my case rebuilding B set the overlay to [] and affected the insets. MediaQuery in A picked up on this, rebuilt and reset the overlay to .values and forced these onto B. And round she goes.
A periodic timer calling setState in A will do the same thing. I am sure there are many more examples.
So look out for and avoid any rebuild potential in A when it has lost focus.
Here is my problem: I have an app that has 2 list view.builders. You can imagine the scenario.
within the Stateful widget, we have:
Widget build(ct)
{
and this returns a column widget that has TWO list views.
The problem I have is that one list view changes (or should change) the items in another list view.
So what are my options? To create two Widget build(ct1) and Widget build(ct2)??
Do we do that? How can I communicate changes to ct1?
Oh my goodness, I've tried a lot, even setState etc... nothing works.. Perhaps could someone tell me how I can invoke the page to be refreshed?? That would work.
I keep on finding the answers myself - but for anyone who has this issue, Flutter apparently has evolved... if you are using the latest version, I really believe that SetState() function should work for you.. you just need to use it in the right place.