1

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!

plam
  • 313
  • 1
  • 4
  • 17

1 Answers1

1

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.

plam
  • 313
  • 1
  • 4
  • 17