Flutter: how to keep widget with Google Map unchanged?

Viewed 4233

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.

3 Answers

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: [ ... ]
      ),
    );
  }
}

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,
      );
    }

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.

Related