22

I am using Google Maps for Flutter widget. In my app map is displayed via one of the tabs of BottomNavigationBar.

And I have the following problem:

  1. user is on Map's tab
  2. user changes tab (by tapping on another one)
  3. [PROBLEM] when user returns on Map's tab map redraws.

I would like to keep map as it is when user leaves Map's tab, so he can continue to work with it when he returns to it later on.

Tried to:

  • use PageStorage - without success.
  • make something like Singletone of Map's state - without success.
  • use AutomaticKeepAliveClientMixin (saw here), which looked promising, but still without success.

(I admit that I could have done something wrong)

Code of last attempt:

class MapScreen extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => MapScreenState();
}

class MapScreenState extends State<MapScreen> with AutomaticKeepAliveClientMixin {
  GoogleMapController mapController;

  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Scaffold(
        appBar: AppBar(
          title: const Text("Map"),
        ),
        body: GoogleMap(
          onMapCreated: _onMapCreated,
        )
    );
  }

  void _onMapCreated(GoogleMapController controller) {
      mapController = controller;
      updateKeepAlive();
  }
}

So, I just need a way to either keep MapScreen alive and unchanged, or to store its state somehow and restore it when user returns to MapScreen. Or something else which will solve the problem.

AQRC
  • 323
  • 3
  • 10
  • Couple of extra thoughts to Diegos answer. You could use an Offstage widget, and move the widget offscreen and back when navigating. I don't know google_maps plugin, but can you store the camera position separately and include that in the google_maps widget as an example workaround, if that is what is getting reset each time and causing the problem. – Ian Jan 14 '19 at 11:19
  • @Ian Tried Offstage widget, still same behavior. Problem is not only camera position, but also time which map takes to load. I'll probably store camera position (and other options if needed) for now, but if I find or come up with a solution I will post it here. – AQRC Jan 15 '19 at 21:02
  • 2
    Did you already find a solution? I'm facing this problem aswell. – Tim Hoeksema Jun 12 '19 at 19:14
  • 1
    Did you ever find a solution to this @AQRC – The Tokenizer Nov 30 '19 at 16:33
  • 1
    @TheTokenizer I quite stopped work on my flutter project, so the answer is no, unfortunately I didn't find solution – AQRC Dec 03 '19 at 00:45
  • Keep in mind that the Google Maps widget is in a developer preview state at version 0.2. Some behavior may change over time. Do not use this in production yet. – Randal Schwartz Jan 27 '19 at 16:51

4 Answers4

8

Use IndexedStack

For example:

Class _ExamplePageState extends State<ExamplePage> {
  int _bottomNavIndex = 0;

  final List<Widget> _children = [
    WidgetOne(),
    WidgetTwo(),
    GoogleMap(),
  ]

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: IndexedStack(
        index: _bottomNavIndex,
        children: _children,
      ),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _bottomNavIndex,
        onTap: (index) {
          if (_bottomNavIndex == index) return;
          setState(() {
            _bottomNavIndex = index;
          });
        }
        items: [ ... ]
      ),
    );
  }
}
AaronJ
  • 706
  • 7
  • 17
3

Widget always rebuild after you change from page to page, so, try this , use a variable for GoogleMap and reuse if it's different from null.

    GoogleMap _map;

     @override
    Widget build(BuildContext context) {
      if (_map == null){
        _map =  GoogleMap(
            onMapCreated: _onMapCreated,
          );
      }
      return Scaffold(
          appBar: AppBar(
            title: const Text("Map"),
          ),
          body:_map,
      );
    }
diegoveloper
  • 93,875
  • 20
  • 236
  • 194
  • Tried this, unfortunately widget not only "rebuilds", but does it by "recreating its state" by calling `createState()` when page is changed back and forth, so `_map` will always be `null` on `build` method call. Also tryed the same approach with `createState()` (create state if it is null, otherwise return state created earlier), but it causes assertion errors in the framework. – AQRC Jan 14 '19 at 07:33
  • are you using AutomaticKeepAliveClientMixin ? – diegoveloper Jan 14 '19 at 07:35
  • 2
    Yes, I am. Even made State to use it, but it doesn't help. For now I am going to store camera position and all other data, as Ian suggested. If I find or come up with a solution I will post it here though – AQRC Jan 15 '19 at 20:52
  • How did you fixed this? – lacas Jan 11 '20 at 10:01
  • 1
    AQRC, have you found a solution? – Leandro Luque Mar 05 '20 at 19:41
  • @AQRC Did you find a solution to this? – Abdullah Riaz Sep 12 '20 at 08:24
  • Same problem here - did you find a solution? – Jammo May 24 '22 at 14:35
2

I was just having this same problem and the mixin solved it. I think you've just missed enter the type of mixin at the end of its declaration.

class MapScreenState extends State<MapScreen> with AutomaticKeepAliveClientMixin<MapScreenState>

see this thread if anything.

Rinaldi Segecin
  • 449
  • 8
  • 23
  • 1
    This did not work for me, is there anything else you've needed to do? what's your setup? – Keff Aug 02 '21 at 09:15
0
AutomaticKeepAliveClientMixin

To

AutomaticKeepAliveClientMixin<MapScreenState>
Iyyappan
  • 28
  • 4