Ontap не работает на маркере Google Maps во флаттере - PullRequest
0 голосов
/ 08 апреля 2020

Я работаю над проектом, использую google_maps_flutter для отображения карт и маркеров на экране & search_map_place для поиска мест на карте, я предоставил исходный код ниже , есть ошибка в исходном коде, весь проект контролируется с помощью нижней навигации, когда при первом запуске приложения я перехожу на экран карты, он отображает маркеры из базы данных, и onTap также работает отлично, но когда я перехожу к любому на другом экране и снова вернитесь к экрану карты, onTap не работает с маркерами.

отображение маркеров на карте:

_onMapCreated() async {
    // print(customerInfo);
    for (var item in ud.customerInfo) {
      if (item['customer_latitude'] == "" && item['customer_longitude'] == "") {
        continue;
      } else {
        final MarkerId markerId = MarkerId((markers.length + 1).toString());
        LatLng markerPos = LatLng(double.parse(item['customer_latitude']),
            double.parse(item['customer_longitude']));
        final Marker marker = Marker(
            infoWindow: InfoWindow(
              title: item['customer_name'],
              snippet: item['customer_desc'],
            ),
            // onTap: () => _onMarkerTapped(markerId),
            icon: BitmapDescriptor.defaultMarkerWithHue(
                item['customer_status'] == 'red'
                    ? BitmapDescriptor.hueRed
                    : item['customer_status'] == 'yellow'
                        ? BitmapDescriptor.hueYellow
                        : BitmapDescriptor.hueGreen),
            markerId: markerId,
            consumeTapEvents: true,
            position: markerPos,
            onTap: () {
              Navigator.push(
                  context,
                  MaterialPageRoute<Null>(
                    builder: (BuildContext context) {
                      return CustomerDetail(
                          item['customer_id'],
                          item['customer_name'],
                          item['customer_email'],
                          item['customer_desc'],
                          item['customer_phone'],
                          item['customer_status']);
                    },
                    fullscreenDialog: true,
                  ));
            });
        _markers = null;
        markers[markerId] = marker;
      }
    }
    setState(() {});
  }

завершено код:

String _mapStyle;
GoogleMapController controller;
List<Map> customerInfo;

class MapS extends StatefulWidget {
  @override
  _MapSState createState() => _MapSState();
}

class _MapSState extends State<MapS> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Search Map Place Demo',
      home: MainScreen(),
    );
  }
}

MapType _mapType = MapType.normal;
Map<MarkerId, Marker> markers = <MarkerId, Marker>{};

class MapSample extends StatefulWidget {
  @override
  State<MapSample> createState() => MapSampleState();
}

class MapSampleState extends State<MapSample> {
  @override
  void initState() {
    super.initState();
    getCustomerInfo();
    rootBundle.loadString('assets/map_style.txt').then((string) {
      _mapStyle = string;
    });

    getCurrentLocation();
    setCustomMapPin();
    // _onMapCreated(controller);
    setState(() {
      _onMapCreated();
    });
  }

  Future getCustomerInfo() async {
    // getting customer info using saleManagerID
    var customerInfoUrl = "http://.../calender/getCustomerInfo.php";
    customerInfoResponse = await http.post(customerInfoUrl, body: {
      "sm_id": sm.sm_id,
    });
    if (jsonDecode(customerInfoResponse.body) == "No Customers") {
      String noCustomers = jsonDecode(customerInfoResponse.body);
      ud.customerInfo = [];
    } else {
      ud.customerInfo = jsonDecode(customerInfoResponse.body);
      print('user data got!');
    }
    // print(ud.customerInfo);
  }


  Widget _mapTypeSwitcher() => Align(
        alignment: const Alignment(0.95, -0.7),
        child: FloatingActionButton(
          mini: true,
          heroTag: null,
          tooltip: 'Map Type',
          child: const Icon(Icons.layers),
          onPressed: () {
            final MapType nextType =
                MapType.values[_mapType.index == 2 ? 1 : 2];
            setState(() {
              print(nextType.toString());
              _mapType = nextType;
            });
          },
        ),
      );

  _onMapCreated() async {
    // print(customerInfo);
    for (var item in ud.customerInfo) {
      if (item['customer_latitude'] == "" && item['customer_longitude'] == "") {
        continue;
      } else {
        final MarkerId markerId = MarkerId((markers.length + 1).toString());
        LatLng markerPos = LatLng(double.parse(item['customer_latitude']),
            double.parse(item['customer_longitude']));
        final Marker marker = Marker(
            infoWindow: InfoWindow(
              title: item['customer_name'],
              snippet: item['customer_desc'],
            ),
            // onTap: () => _onMarkerTapped(markerId),
            icon: BitmapDescriptor.defaultMarkerWithHue(
                item['customer_status'] == 'red'
                    ? BitmapDescriptor.hueRed
                    : item['customer_status'] == 'yellow'
                        ? BitmapDescriptor.hueYellow
                        : BitmapDescriptor.hueGreen),
            markerId: markerId,
            consumeTapEvents: true,
            position: markerPos,
            onTap: () {
              Navigator.push(
                  context,
                  MaterialPageRoute<Null>(
                    builder: (BuildContext context) {
                      return CustomerDetail(
                          item['customer_id'],
                          item['customer_name'],
                          item['customer_email'],
                          item['customer_desc'],
                          item['customer_phone'],
                          item['customer_status']);
                    },
                    fullscreenDialog: true,
                  ));
            });
        _markers = null;
        markers[markerId] = marker;
      }
    }
    setState(() {});
  }

  void getCurrentLocation() async {
    Position res = await Geolocator()
        .getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
    setState(() {
      position = res;
      // _child = mapWidget();
      print(res);
      mapToggle = true;
    });
  }

  Completer<GoogleMapController> mapController = Completer();
  Set<Marker> _markers = Set();
  // custom marker
  BitmapDescriptor pinLocationIcon;
  void setCustomMapPin() async {
    pinLocationIcon = await BitmapDescriptor.fromAssetImage(
        ImageConfiguration(devicePixelRatio: 4.5), 'assets/red_marker.png');
  }
  IconData fontAwesomeIconFromString(String name) {
    switch (name) {
      case 'website':
        return Icons.web;
      case 'phone_no':
        return Icons.phone_android;
      case 'desc':
        return Icons.lock_outline;
      case 'place':
        return Icons.place;
      case 'city':
        return Icons.location_city;
      case 'country':
        return Icons.my_location;
    }
  }

  String iconfromApi;
  //  textfield in bottomsheet
  Widget _entryField(String title, TextEditingController tcont, String ic) {
    iconfromApi = ic;
    return Container(
      margin: EdgeInsets.symmetric(vertical: 5),
      padding: new EdgeInsets.fromLTRB(2.0, 2.0, 2.0, 2.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          TextFormField(
            controller: tcont,
            // obscureText: isPassword,
            style: TextStyle(color: Colors.black, fontFamily: 'Montserrat'),
            decoration: InputDecoration(
                border: OutlineInputBorder(),
                labelText: title,
                prefixIcon: Icon(fontAwesomeIconFromString(iconfromApi)),
                labelStyle: TextStyle(fontSize: 15)),
          )
        ],
      ),
    );
  }

  Future addData(String phone, web) async {
    var url = "http://.../addData.php";
    var response = await http.post(url, body: {
      "name": userD.name,
      "desc": userD.desc,
      "status": userD.status,
      "latitude": userD.latitide,
      "longitude": userD.longitude,
      "phone": phone != null ? phone : "n/a",
      "web": web != null ? web : "n/a",
      "sm_id": sm.sm_id
    });
    // print('Response status: ${response.statusCode}');
    // print('Response body: ${response.body}');
    response.body == '1' ? confirmDialog(context) : errorDialog(context);
  }

  Future<void> confirmDialog(BuildContext context) {
    return showDialog<void>(
      context: context,
      barrierDismissible: false,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text('Response'),
          content: const Text('Record Added!'),
          actions: <Widget>[
            FlatButton(
              child: Text('Ok'),
              onPressed: () {
                Navigator.pushAndRemoveUntil(
                    context,
                    MaterialPageRoute(builder: (context) => MainScreen()),
                    (Route<dynamic> route) => false);
              },
            ),
          ],
        );
      },
    );
  }

  Future<void> errorDialog(BuildContext context) {
    return showDialog<void>(
      barrierDismissible: false,
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text('Response'),
          content: const Text('Record submission failed'),
          actions: <Widget>[
            FlatButton(
              child: Text('Ok'),
              onPressed: () {
                Navigator.pushAndRemoveUntil(
                    context,
                    MaterialPageRoute(builder: (context) => MainScreen()),
                    (Route<dynamic> route) => false);
              },
            ),
          ],
        );
      },
    );
  }

  Widget _submitButton() {
    return InkWell(
      onTap: () {
        print(ud.phone);
        print(ud.web);
        addData(ud.phone, ud.web);
      },
      child: Container(
        width: MediaQuery.of(context).size.width,
        padding: EdgeInsets.symmetric(vertical: 15),
        alignment: Alignment.center,
        decoration: BoxDecoration(
            borderRadius: BorderRadius.all(Radius.circular(5)),
            gradient: LinearGradient(
                begin: Alignment.centerLeft,
                end: Alignment.centerRight,
                colors: [Hexcolor("#2a7837"), Hexcolor("#2a7837")])),
        child: Text(
          'Save In Database',
          style: TextStyle(
              fontSize: 15,
              color: Colors.white,
              fontWeight: FontWeight.bold,
              fontFamily: 'Montserrat'),
        ),
      ),
    );
  }

  Widget addButon = Container();
  @override
  Widget build(BuildContext context) {
    final height = MediaQuery.of(context).size.height;
    return Stack(
      children: <Widget>[
        GoogleMap(
            myLocationEnabled: true,
            myLocationButtonEnabled: true,
            compassEnabled: false,
            tiltGesturesEnabled: false,
            mapType: _mapType,
            initialCameraPosition: CameraPosition(
                target: LatLng(position.latitude, position.longitude),
                zoom: 15),
            onMapCreated: (controller) {
              mapController.complete(controller);

              _onMapCreated();
              // add things here on map, markers, design etc
              controller.setMapStyle(_mapStyle);
            },
            markers:
                _markers == null ? Set<Marker>.of(markers.values) : _markers
            // markers: Set<Marker>.of(markers.values),
            ),
        _mapTypeSwitcher(),
        Positioned(
          top: 60,
          left: MediaQuery.of(context).size.width * 0.05,
          // width: MediaQuery.of(context).size.width * 0.9,
          child: SearchMapPlaceWidget(
            apiKey: apiKEY,
            location: CameraPosition(
                    target: LatLng(position.latitude, position.longitude),
                    zoom: 18)
                .target,
            radius: 30000,
            onSelected: (place) async {
              // declaring some variables
              final geolocation = await place.geolocation;
              // final js = geolocation.fullJSON;
              controller = await mapController.future;
              // get latLong in a
              var latLong = geolocation.coordinates;
              // to save latLong in array for db
              var latLongList = new List(2);
              // to save place, city & country in array for db
              var loctionList = new List();

              controller.animateCamera(
                  CameraUpdate.newLatLng(geolocation.coordinates));
              controller.animateCamera(
                  CameraUpdate.newLatLngBounds(geolocation.bounds, 0));
              print(place.fullJSON);
              // converting LatLong to string and then array
              latLong = latLong.toString().replaceAll(RegExp("[a-zA-Z]"), '');
              latLong =
                  latLong.toString().replaceAll(RegExp("[\\[\\](){}]"), '');

              ud.customerDetials = place.fullJSON['place_id'];

              latLongList = latLong.split(', ');
              print(latLongList[0]);
              print(latLongList[1]);
              // print(prettyJson(place.fullJSON, indent: 2));
              // print(a.runtimeType);
              // adding retrived values to object
              userD.name = place.fullJSON['structured_formatting']['main_text'];

              // place.fullJSON['structured_formatting']['secondary_text'] == null
              //     ? userD.desc = c_desc.text
              //     : userD.desc =
              //         place.fullJSON['structured_formatting']['secondary_text'];
              // c_phone_no.text = c_place.text =
              //     c_city.text = c_country.text = c_desc.text = '';
              // userD.place = c_place.text;
              // userD.city = c_city.text;
              // userD.country = c_country.text;
              userD.phone = ud.phone;
              userD.web = ud.web;
              userD.latitide = latLongList[0];
              userD.longitude = latLongList[1];
              userD.status = "red";
              setState(() {
                markers = <MarkerId, Marker>{};
                _markers = new Set();
                _markers.add(
                  Marker(
                      markerId: MarkerId(place.fullJSON['place_id']),
                      position: geolocation.coordinates,
                      icon: pinLocationIcon,
                      infoWindow: InfoWindow(
                          title: place.fullJSON['structured_formatting']
                              ['main_text'],
                          snippet: place.fullJSON['structured_formatting']
                              ['secondary_text'])),
                );
                // markers = null;
              });
              // print(js);
              // savejson(js);
              addButon = new RawMaterialButton(
                onPressed: () async {
                  var responseDetails =
                      await getLocationDetails(place.fullJSON['place_id']);
                  ud.phone =
                      responseDetails.data["result"]["formatted_phone_number"];
                  ud.web = responseDetails.data["result"]["website"];
                  showStopper(
                      context: context,
                      stops: [0.5 * height, height],
                      builder:
                          (context, scrollController, scrollPhysics, stop) {
                        return Padding(
                          padding: const EdgeInsets.all(18.0),
                          child: ListView(
                              controller: scrollController,
                              physics: scrollPhysics,
                              children: [
                                // show location name
                                Text(
                                  userD.name,
                                  style: TextStyle(
                                      color: Colors.black,
                                      fontSize: 30,
                                      fontWeight: FontWeight.bold,
                                      fontFamily: 'Montserrat'),
                                ),

                                SizedBox(
                                  height: 50,
                                ),
                                // location desc
                                Text(
                                  'Description:',
                                  style: TextStyle(
                                      color: Colors.black,
                                      fontSize: 20,
                                      fontWeight: FontWeight.bold,
                                      fontFamily: 'Montserrat'),
                                ),

                                SizedBox(
                                  height: 10,
                                ),
                                userD.desc == null
                                    ? _entryField("Description", c_desc, 'desc')
                                    : Text(
                                        userD.desc,
                                        style: TextStyle(
                                            color: Colors.black,
                                            fontSize: 15,
                                            fontFamily: 'Montserrat'),
                                      ),

                                SizedBox(
                                  height: 20,
                                ),
                                // add website, phone, place, city, country
                                Text(
                                    ud.phone != null ? ud.phone : "phone: n/a"),
                                Text(ud.web != null ? ud.web : "website: n/a"),
                                // _userInfoWidget(),
                                // _entryField("Website", c_websitee, 'website'),

                                SizedBox(
                                  height: 20,
                                ),
                                _submitButton()
                              ]),
                        );
                      });
                },
                child: new Icon(
                  Icons.add_location,
                  color: Hexcolor('#2a7837'),
                  size: 35.0,
                ),
                shape: new CircleBorder(),
                elevation: 2.0,
                fillColor: Colors.white,
                padding: const EdgeInsets.all(15.0),
              );
            },
          ),
        ),
        // 2 floating buttons
        Padding(
          padding: const EdgeInsets.all(8.0),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.end,
            children: <Widget>[
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: <Widget>[
                  addButon,

                  new RawMaterialButton(
                    onPressed: () {
                      // Navigator.push(
                      //     context,
                      //     MaterialPageRoute<Null>(
                      //       builder: (BuildContext context) {
                      //         return MyApp();
                      //       },
                      //       fullscreenDialog: true,
                      //     ));
                      _markers = null;
                      _onMapCreated();
                    },
                    child: new Icon(
                      Icons.person,
                      color: Hexcolor('#2a7837'),
                      size: 35.0,
                    ),
                    shape: new CircleBorder(),
                    elevation: 2.0,
                    fillColor: Colors.white,
                    padding: const EdgeInsets.all(15.0),
                  ),

                  // feedback button
                  new RawMaterialButton(
                    onPressed: () {
                      Navigator.push(
                          context,
                          MaterialPageRoute<Null>(
                            builder: (BuildContext context) {
                              return FeedBackModal();
                            },
                            fullscreenDialog: true,
                          ));
                    },
                    child: new Icon(
                      Icons.feedback,
                      color: Hexcolor('#2a7837'),
                      size: 35.0,
                    ),
                    shape: new CircleBorder(),
                    elevation: 2.0,
                    fillColor: Colors.white,
                    padding: const EdgeInsets.all(15.0),
                  ),
                ],
              )
            ],
          ),
        )
      ],
    );
  }

  Future getLocationDetails(placeId) async {
    try {
      String requestUrl =
          "https://maps.googleapis.com/maps/api/place/details/json?place_id=$placeId&fields=website,formatted_phone_number&key=$apiKEY";
      Response placeDetails = await Dio().get(requestUrl);
      return placeDetails;
    } catch (e) {
      print(e);
    }
    // ud.phone= placeDetails.data["result"]["formatted_phone_number"];
    // ud.web= placeDetails.data["result"]["web"];
  }
}

class MainScreen extends StatefulWidget {
  @override
  _MainScreenState createState() => _MainScreenState();
}

class _MainScreenState extends State<MainScreen> {
  // bottom navigation variables
  int _selectedIndex = 0;
  static const TextStyle optionStyle =
      TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
  List<Widget> _widgetOptions = <Widget>[
    Kpi(),
    Customers(),
    MapSample(),
    AddMeeting(),
    Customers(),
  ];
  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
      fd.indexForFeedback = _selectedIndex;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: _widgetOptions.elementAt(fd.indexForFeedback),
      ),
      bottomNavigationBar: BottomNavigationBar(
        unselectedItemColor: Colors.white,
        type: BottomNavigationBarType.fixed,
        backgroundColor: Colors.black,
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.insert_chart),
            title: Text('KPI'),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.people),
            title: Text('Customers'),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.add_location),
            title: Text('Map'),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.calendar_today),
            title: Text('Calender'),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.group_add),
            title: Text('Quotes'),
          ),
        ],
        currentIndex: fd.indexForFeedback,
        selectedItemColor: Hexcolor('#2a7837'),
        onTap: _onItemTapped,
      ),
    );
  }
}

1 Ответ

0 голосов
/ 08 апреля 2020

Заменить

child: _widgetOptions.elementAt(fd.indexForFeedback),

на

child: IndexedStack(
      children: _widgetOptions,
      index: fd.indexForFeedback,
    ),

Предотвращает перерисовку карты при каждом переключении между вкладками и предотвращает утечки памяти.

См. Также: https://www.youtube.com/watch?v=_O0PPD1Xfbk

...