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.
Related
I have a sample code which detects a hovering stylus over a widget.
The code is from this Stackoverflow Quesion.
In short. It binds using GestureBinding.instance?.pointerRouter.addGlobalRoute and checks in the handler if the event is of type stylus.
This gets triggered when the stylus is hovering over the screen (no contact).
It works great on Widgets like Text(), Container() etc.
Question:
I want to use this functionality on a different Widget, the Flutter InAppWebView but the event will not get triggered until the pen has contact with the surface. Even on the Container it does not work, if the child is the InAppWebView.
I think this problem will occur on other Widgets too.
I tried the Listener, AbsorbPointer and IgnorePointer.
Update 1:
I can see the following in the debug output when I start hovering the stylus over the screen.
I/ViewRootImpl(23491): updatePointerIcon pointerType = 20001, calling pid = 23491
D/InputManager(23491): setPointerIconType iconId = 20001, callingPid = 23491
Update 2:
The InAppWebView has an option useHybridComposition which is false by default. Setting it to true solves the issue. But the WebView is becoming very slow.
HERE is a repository that shows the problem.
Thanks!
EDIT
As desribed below, this question has two solutions.
Set useHybridComposition to true. For slowness, maybe raise an issue to that repo.
Hook at android/ios level instead of Flutter level, and forward events back to Flutter.
The debugging method maybe like this: Firstly, print out the pointer events in methods like your _handleEvent. Then you will know whether the pointer event just occur, or they even do not occur.
Secondly, try what widgets are OK and what are not. Text is OK, WebView is not. Then is Container OK? Is InkWell OK? Is IconButton OK? Is IconButton OK? etc. By doing this you gain insight of what is special about Text that makes it work.
Thirdly, as a hacky workaround, could you please try Text.rich(WidgetSpan(child: your_web_view))? Since you say Text is OK while other widgets are not OK.
Lastly, maybe need to dig into Text's source to see what magic happens - probably some special configuration? - to let it work.
I am using scopedModel approach in flutter, but the question still remains with other patterns like flutter.
-My UI calls authModel.login()
-authModel.login does async work and calls notifyListeners
-build is automatically triggered on my UI
-inside build method, UI checks the login state on authModel, then calls
addPostFrameCallback to change the screen from the build method.
Is this the best design? I feel like this is code smell, but I am not sure. Would it be better if the authModel was passed an onLoginCompleteCallback function from the UI that would change the screen, and then I would not need to call addPostFrameCallback in the build method?
The presentation on the screen is not dependant on the isLoggedIn bool at all. Its just observed to change the screen.
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.
Ok, I am working on a media player app using flutter. Now when I press the play button, it changes to pause button. (Only the icon on the button changes)
The onPressed function for the button changes a boolean value and calls the setState() method.
It goes something like this.
bool _playing = false;
void _onPlayButtonPressed() {
setState () {
if (_playing)
_playing = false;
else
_playing = true;
}
}
I also have a function that returns the icon based on the value of _playing.
Widget _playButtonIcon() {
//This function has no setState() call
if (_playing)
//return pause icon
else
//return play icon
}
Everything works fine. The icon changes everytime I press the button. However as mentioned in docs and also in Flutter Demo App, setState() method calls the build method. Which redraws the entire widget tree including child widgets that are completely unchanged.
Is this approach justified or is this an overkill?
Do I have to put the button on a different Stateful Widget Class and call its build method via setState() everytime I tap this playButton?
What if I have other widgets that also changes the state of UI. Possibly changing different widgets?
What is the proper way to do this without having a performance hit?
Creating a play button that is a widget of its own with a state that maintains whether it is playing or not definitely makes sense. Now when you call setState on the parent widget it does call the build method, but as far as I know it does not necessarily redraw everything from scratch. If no changes are found in some of the embedded widgets it does not redraw them since they are already in the widget tree. Finally, it is okay to call setstate, however if your app starts getting bigger and you find yourself calling set state in too many places, and want to use global keys, I would advise looking into the Provider package, and making use of the ChangeNotifier/Consumer pattern.
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.