Jumat, 04 September 2020

Update map markers of Future Builder

Hello to all the Flutter community! I am about to finish an app, but I have this issue that I cannot solve, I looked online for correct implementation of what I'm trying to achieve without luck.

As you can see in the next image when the user opens this page see a map with the original red marker for the user location and then the markers of the shops.

In order to show this, I create a future builder who first checks the location of the user and then makes an API call who retrieves the shops surrounding the user.

Also, the user can select categories, but this is not important for the problem.

Screenshot_20200904-122130.png

All that I describe before works fine, but my client ask that if the user moves the map, the location of the user should update (considering the new user location as the center of the map) and make the API call again to update the shops surrounding.

I can get the new location of the user based on the map, so _onCameraIdle if the user location is different of the one before, a new API call is made and the markers list is updated, the problem is that the map is nos refreshing the markers, I can see the markers list on the console updating, so I try to put notifyListeners inside the Future where I assign the markers, but if I do this, the future builders enter in a loop.

Can anyone help me to solve this?

How can achieve this? Should I use something different than a Future Builder?


This is the complete code of the screen:

import 'package:app_pickolos/generated/l10n.dart';
import 'package:app_pickolos/src/providers/categories_list_provider.dart';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:geolocator/geolocator.dart';
import 'package:provider/provider.dart';

import '../styles.dart';
import 'widgets/background_gradient.dart';

class SearchMap extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var colorValue = Theme.of(context).primaryColorLight;
    Locale myLocale = Localizations.localeOf(context);

    CategoriesListProvider categoriesListProvider =
        Provider.of<CategoriesListProvider>(context);

    LatLng _locationSelected;
    LatLng _lastMapPosition;

    Future _getUserLocation(locationSelected) async {
      Position position = await Geolocator()
          .getCurrentPosition(desiredAccuracy: LocationAccuracy.high);

      if (locationSelected == null) {
        categoriesListProvider.userPositionLon = position.longitude;
        categoriesListProvider.userPositionLat = position.latitude;
        await categoriesListProvider.getMapMarkers(
          context: context,
          lat: position.latitude,
          lon: position.longitude,
        );
      } else {
        categoriesListProvider.userPositionLon = locationSelected.longitude;
        categoriesListProvider.userPositionLat = locationSelected.latitude;
        await categoriesListProvider.getMapMarkers(
          context: context,
          lat: locationSelected.latitude,
          lon: locationSelected.longitude,
        );
      }
    }

    void _onCameraMove(CameraPosition position) {
      _lastMapPosition = (position.target);
      categoriesListProvider.userPositionLon = position.target.longitude;
      categoriesListProvider.userPositionLat = position.target.latitude;
    }

    void _onCameraIdle() {
      if (_lastMapPosition != _locationSelected) {
        _getUserLocation(_locationSelected);
        _locationSelected = _lastMapPosition;
      }
    }

    return Scaffold(
      appBar: AppBar(
        title: Text(AppLocalizations.of(context).mapTitle),
      ),
      body: Container(
        decoration: buildBackgroundGradient(context),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          mainAxisSize: MainAxisSize.min,
          children: [
            DropDownSelect(
                categoriesListProvider: categoriesListProvider,
                myLocale: myLocale),
            SizedBox(
              height: 20,
            ),
            FutureBuilder(
              future: _getUserLocation(_locationSelected),
              builder: (
                context,
                snapshot,
              ) {
                switch (snapshot.connectionState) {
                  case ConnectionState.none:
                    return Text(AppLocalizations.of(context).errorNoConection);
                  case ConnectionState.waiting:
                    return Container(
                      height: 320,
                      child: Center(
                        child: CircularProgressIndicator(
                            valueColor:
                                AlwaysStoppedAnimation<Color>(colorValue)),
                      ),
                    );
                  case ConnectionState.active:
                    return Container(
                      height: 320,
                      child: Center(
                        child: CircularProgressIndicator(
                            valueColor:
                                AlwaysStoppedAnimation<Color>(colorValue)),
                      ),
                    );
                  case ConnectionState.done:
                    if (snapshot.hasError) {
                      return Text(
                        '${snapshot.error}',
                        style: TextStyle(color: Colors.red),
                      );
                    } else {
                      return Container(
                        width: MediaQuery.of(context).size.width * 0.8,
                        height: 320,
                        margin: EdgeInsets.symmetric(horizontal: 16.0),
                        child: ClipRRect(
                          borderRadius: borderRadiusPickolos(),
                          child: Stack(
                            children: [
                              GoogleMap(
                                onCameraMove: _onCameraMove,
                                onCameraIdle: _onCameraIdle,
                                mapType: MapType.normal,
                                initialCameraPosition: CameraPosition(
                                  target: LatLng(
                                      categoriesListProvider.userPositionLat,
                                      categoriesListProvider.userPositionLon),
                                  zoom: 14,
                                ),
                                markers: Set<Marker>.of(
                                    categoriesListProvider.markersList),
                              ),
                            ],
                          ),
                        ),
                      );
                    }
                }
                return Container(
                  height: 320,
                  child: Center(
                    child: CircularProgressIndicator(
                        valueColor: AlwaysStoppedAnimation<Color>(colorValue)),
                  ),
                );
              },
            ),
            Expanded(child: Container()),
            Container(
              width: 60,
              height: 60,
              decoration: BoxDecoration(
                shape: BoxShape.circle,
                color: Colors.white38,
              ),
              child: IconButton(
                icon: Icon(
                  Icons.close,
                  size: 40,
                ),
                onPressed: () {
                  Navigator.popAndPushNamed(context, 'home');
                },
              ),
            ),
            SizedBox(
              height: 40,
            ),
          ],
        ),
      ),
    );
  }
}

class DropDownSelect extends StatelessWidget {
 ***Not important
}


And this is the API call


Future getMapMarkers({context, double lat, double lon}) async {
    final Map<String, String> headers = {
      'Api-Token': _apitoken,
      'Session-Token': _prefs.sessionId,
      'Content-Type': 'application/json'
    };

    var body = {
      "longitude": lon,
      "latitude": lat,
      "maxDistance": 10000,
    };

    final url =
        'XXXXXXXm/api/v1/businesses/by-location';

    var response = await http.post(
      url,
      body: json.encode(body),
      headers: headers,
    );

    final mapBusinessListModel = mapBusinessListFromJson(response.body);

    final bitmapIcon = await BitmapDescriptor.fromAssetImage(
        ImageConfiguration(size: Size(48, 48)), 'assets/map_icon.png');
        
    _markers = mapBusinessListModel
        .map(
          (mapBusinessListModel) => Marker(
            markerId: MarkerId(mapBusinessListModel.id),
            position: LatLng(
              mapBusinessListModel.location.latitude,
              mapBusinessListModel.location.longitude,
            ),
            icon: bitmapIcon,
            infoWindow: InfoWindow(
              snippet: AppLocalizations.of(context).tapToView,
              onTap: () {
                Provider.of<UserProvider>(context, listen: false)
                    .setBusinessDetailID = mapBusinessListModel.id;

                Navigator.pushNamed(context, 'businessPreview');
                print('tap sobre icono mapa');
              },
              title: mapBusinessListModel.name,
            ),
          ),
        )
        .toList();

    _markers.add(Marker(
      markerId: MarkerId('user'),
      position: LatLng(lat, lon),
    ));
    //notifyListeners();
    print('agrgegue a marker list ${_markers.toString()}');
  }

--
You received this message because you are subscribed to the Google Groups "Flutter Development (flutter-dev)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to flutter-dev+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/flutter-dev/0e5a4db4-2625-483d-8b13-cfa9ba62a2e0n%40googlegroups.com.

Update map markers of Future Builder Rating: 4.5 Diposkan Oleh: Kurikulum Berkarakter

0 komentar:

Posting Komentar