我正在做一个项目,我正在使用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,
),
);
}
}