I use the package google_maps_flutter to use Google maps in my app. My problem is how to set a listener, show when I press in the map to get the coordination of this place. I don't find anything in documentation.
The only thing which I find is with controllerMap, which I use to set marker listener, is that it has a method,
.addListener(listener)
Any idea?
I have solved the problem using the onMarkerTapped callback methods below:
Note: mapController below is an instance of the GoogleMap Controller
mapController.**onMarkerTapped**.add((marker){
String title= marker.options.infoWindowText.title;
String latitude= marker.options.position.latitude.toString();
String longitude= marker.options.position.longitude.toString();
});
google map plugin has a lot of errors:), I prefer using this plugin : flutter_map
full example :
import 'package:location/location.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong/latlong.dart';
class ContactPage extends StatefulWidget {
#override
ContactPageState createState() => new ContactPageState();
}
class ContactPageState extends State<ContactPage>
with TickerProviderStateMixin {
static LatLng myLocation = new LatLng(51.5, -0.09);
#override
void initState() {
super.initState();
setState(() {
new LatLng(51.5, -0.09);
});
}
#override
Widget build(BuildContext context) {
Size screenSize = MediaQuery.of(context).size;
double heigh = screenSize.height;
TextStyle whiteStyle = new TextStyle(fontSize: 20.0, color: Colors.white);
return new Directionality(
textDirection: TextDirection.rtl,
child: new Container(
padding: new EdgeInsets.only(bottom: 10.0, left: 1.0, right: 1.0),
color: Colors.white,
child: new FlutterMap(
options: new MapOptions(
center: myLocation,
zoom: 15.0,
maxZoom: 15.0,
minZoom: 3.0,
onTap: _handleTap),
layers: [
new TileLayerOptions(
urlTemplate:
"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
subdomains: ['a', 'b', 'c']),
new MarkerLayerOptions(markers: markers)
],
)
)),
);
}
_handleTap(LatLng point) {
setState(() {
myLocation = point;
});
}
}
This functionality is currently not available in version 2.0 of the google flutter plugin, however there are two pull requests that have added this functionality.
1121
941
Pull request 1121 has example code on how to use the tap functionality.
With the current documentation, I only made the following change to the example of #lionelsanou and #Pradeep given above:
String latitude= marker.values.first.position.toString();
String longitude= marker.values.last.position.toString();
and it worked for me.
Related
I have a GoogleMap in my Flutter app.
When the page loads it calls on API and gets a list of geolocations which I use to create a list of markers.
My GoogleMap uses this list of markers and they display nicely, however, I would like one of them to be active. I can't see anything in the API documentation that says this is possible. How can I achieve this?
Use GoogleMapController to set the marker active, allMarkers here is a list of markers which might be coming from the database and the first one (index 0) will be active after execution of:
_googleMapController.showMarkerInfoWindow(allMarkers[0].markerId);
Documentation
You can implement custom active state through onTap event handler.
In stateful widget create state to track selected marker and rebuild all markers comparing their IDs to the highlighted one:
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
class GoogleMapsLabPage extends StatefulWidget {
#override
State<GoogleMapsLabPage> createState() => GoogleMapsLabPageState();
}
class GoogleMapsLabPageState extends State<GoogleMapsLabPage> {
final preset = [
{"id": "mountain-view", "lat": 37.421512, "lng": -122.084101},
{"id": "san-bruno", "lat": 37.62816, "lng": -122.426491},
{"id": "san-francisco", "lat": 37.789972, "lng": -122.390013},
{"id": "sunnyvale", "lat": 37.403694, "lng": -122.031583}
];
String _selectedOffice = '';
List<Marker> _buildMarkers() {
return preset.map((office) {
return Marker(
markerId: MarkerId(office['id']),
position: LatLng(office['lat'], office['lng']),
icon: office['id'] == _selectedOffice
? BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueBlue)
: BitmapDescriptor.defaultMarker,
consumeTapEvents: true,
onTap: () {
setState(() {
_selectedOffice = office['id'];
});
});
});
}
#override
Widget build(BuildContext context) {
return new Scaffold(
body: GoogleMap(
initialCameraPosition: CameraPosition(target: LatLng(37.7, -122.2), zoom: 9.0),
markers: _buildMarkers().toSet(),
),
);
}
}
By setting consumeTapEvents parameter to true we can disable default tap handling by centering the map on the marker and displaying its info window.
There are ongoing issues in flutter related to the same thing here and here.
Currently, It is not possible to do this via official maps SDK.
However, thanks to the community there is another forked project which has an implementation which can help you achieve this. Checkout this.
mapController.addMarker(
MarkerOptions(
position: LatLng(your values here),
),
);
Hei there,
I have the Problem that my WebView doesn't load. It only shows me a loading Screen.
I am using the flutter_webview_plugin in Flutter for Web.
I have no idea why its always loading. It does this always, with whatever Website I tried.
import 'package:flutter/material.dart';
import 'package:website_aalen_by_night/widgets/info_card.dart';
import 'package:website_aalen_by_night/widgets/nav_bar.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'AAlen by Night',
theme: ThemeData.dark(),
home: WebsiteAalenByNight(),
debugShowCheckedModeBanner: false,
);
}
}
class WebsiteAalenByNight extends StatefulWidget {
#override
WebsiteState createState() => WebsiteState();
}
ScrollController controller = new ScrollController();
class WebsiteState extends State {
#override
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width;
double height = MediaQuery.of(context).size.height;
FlutterWebviewPlugin().onHttpError.listen((WebViewHttpError item) {
print(" WebView onHttpError.code: ${item.code}");
});
return Scaffold(
backgroundColor: Color.fromRGBO(79, 79, 79, 1),
body: Stack(
children: <Widget>[
Scrollbar(
child: ListView(
controller: controller,
children: <Widget>[
InfoCard(),
Image(
image: AssetImage("lib/images/map.png"),
//height: height,
width: width,
fit: BoxFit.cover,
),
InfoCard(),
LimitedBox(
maxWidth: width,
maxHeight: height,
child: WebviewScaffold(
url: "https://www.google.com",
withZoom: false,
withLocalStorage: false,
withJavascript: true,
withLocalUrl: true,
),
),
],
),
),
NavBar(),
],
),
);
}
}
The goal of this is to implement a Map with Markers on the Screen. So I believed I can try a WebView but with that I did come to a stop soon.
Maybe there is a better Way to implement a Map (tried a few other Things like using a map plugin instead but I didn't find any which works for Flutter for Web).
It is really important to get it working on Flutter for Web and NOT on
any other Platform!
Thanks for helping me....
Maybe in the Future I am able to answer such questions for others :D
I don't think that https://github.com/fluttercommunity/flutter_webview_plugin works in web since it uses native libraries.
HOWEVER, the great advantage of using a browser for your flutter app, is that you can use HTML and you don't need a webview there!
check this example of using a nested youtube player
void main() {
ui.platformViewRegistry.registerViewFactory(
'hello-world-html',
(int viewId) => IFrameElement()
..width = '640'
..height = '360'
..src = 'https://www.youtube.com/embed/IyFZznAk69U'
..style.border = 'none'
);
runApp(Directionality(
textDirection: TextDirection.ltr,
child: SizedBox(
width: 640,
height: 360,
child: HtmlElementView(viewType: 'hello-world-html'),
),
));
}
source
Of course the communication with the content it's another history, since it's an iframe and in web browsers CORS is enabled it means you can't access the iframe from flutter, in the case of Google maps, they have an URL api and pass your marker location there ;)
I'm trying to add marker to my map widget based on the string in a Json file. However i have no idea how the marker thingy works after the .addMarker no longer applied. Can anyone please explain on it?
The markers: attribute in the Flutter_Google_maps widget now takes a Set<Marker>().
to add markers, first you should create an empty Set of type Marker and assign it to the markers: attribute in the google maps widget. Consequently, you append the desired Marker() to the created set using the add() method. Finally, you use setState() to rebuild the widget and display the updated Markers set on the UI.
Example:
class MapsScreen extends StatefulWidget {
#override
_MapsScreenState createState() => _MapsScreenState();
}
class _MapsScreenState extends State<MapsScreen> {
Completer<GoogleMapController> _mapsController = Completer();
Set<Marker> _myMarkers = Set<Marker>();
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {
_myMakers.add(
markerId: MarkerId("current"),
position: LatLng(yourLatitude, yourLongitude),
);
setState((){});
)},
),
body: GoogleMap(
initialCameraPosition: _anyCameraPosition,
markers: _myMarkers,
onMapCreated: (GoogleMapController controller) {
_mapsController.complete(controller);
},
);
);
}
}
you have the option to use any state management pattern you prefer.
I've recently started getting into flutter, but just as I was about to write a few widget tests, I noticed that I wasn't terribly sure how to mock out the Google Maps Flutter package.
Many examples I've seen include using the library "mockito" to mock out classes, but this assumes that the Google Maps widget will be injected into the widget to be tested. Unfortunately, with their given documentation and startup guide, this doesn't seem to be very possible:
class MapsDemo extends StatefulWidget {
#override
State createState() => MapsDemoState();
}
class MapsDemoState extends State<MapsDemo> {
GoogleMapController mapController;
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(15.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Center(
child: SizedBox(
width: 300.0,
height: 200.0,
child: GoogleMap(
onMapCreated: _onMapCreated,
),
),
),
RaisedButton(
child: const Text('Go to London'),
onPressed: mapController == null ? null : () {
mapController.animateCamera(CameraUpdate.newCameraPosition(
const CameraPosition(
bearing: 270.0,
target: LatLng(51.5160895, -0.1294527),
tilt: 30.0,
zoom: 17.0,
),
));
},
),
],
),
);
}
void _onMapCreated(GoogleMapController controller) {
setState(() { mapController = controller; });
}
}
Note that the GoogleMaps widget cannot be passed in because onMapCreated is a required function, and that function relies private class method (give the parent widget access to GoogleMapsController). Many other examples of mockito mock functions that don't have this sort of callback function to set state.
There doesn't seem to be any other packages I've seen that can effectively mock out the GoogleMaps widget, so I don't really have any sort of example to follow. Ideally, what I was expecting was some sort of behavior like proxyquire or sinon in node.s (where you don't need to pass in the mocked libraries into function.constructors), but it looks like mockified classes need to be passed into the tested widgets.
Are there any other ideas on how to mock out this library for testing? Or should I just live with testing the actual functionality?
I managed to mock the GoogleMaps by mocking the channels it uses:
setUpAll(() async {
SystemChannels.platform_views.setMockMethodCallHandler((MethodCall call) {
switch (call.method) {
case 'create':
return Future<int>.sync(() => 1);
default:
return Future<void>.sync(() {});
}
});
MethodChannel('plugins.flutter.io/google_maps_0', StandardMethodCodec())
.setMockMethodCallHandler((MethodCall methodCall) async {
return null;
});
}
I got inspiration from this webview plugin test (which is a PlatformView like the GoogleMaps widget), as well as this GoogleMaps plugin test
Using Google Maps for Flutter I've placed some markers on different places on the map. I have a separate RaisedButton on my Flutter app which I need to only be visible when one or more of those markers are currently visible on the map.
How can this be achieved? I've found a somewhat similar solution for Google Maps API but I need this for google_maps_flutter on Flutter.
LatLngBounds has specific method known as contains() which works along with GoogleMapController's getVisibleRegion().
From the official docs:
contains(LatLng point) → bool
Returns whether this rectangle contains the given LatLng.
Usage:
Completer<GoogleMapController> _controller = Completer();
static final CameraPosition _positionCenter = CameraPosition(
target: LatLng(40.730610, -73.935242),
zoom: 3.5,
);
Future<LatLngBounds> _getVisibleRegion() async {
final GoogleMapController controller = await _controller.future;
final LatLngBounds bounds = await controller.getVisibleRegion();
return bounds;
}
#override
Widget build(BuildContext context) {
void checkMarkers() async {
LatLngBounds bounds = await _getVisibleRegion();
Set<Marker> markers = Set<Marker>.of(markers.values);
markers.forEach((marker) {
print('Position: ${ marker.position } - Contains: ${ bounds.contains(marker.position) }');
});
}
return GoogleMap(
mapType: MapType.normal,
markers: Set<Marker>.of(markers.values),
initialCameraPosition: _positionCenter,
onCameraIdle: () {
checkMarkers();
},
onMapCreated: (GoogleMapController controller) async {
_controller.complete(controller);
checkMarkers();
},
);
}
google_maps_flutter is a developer preview at version 0.0.3. Please hang in there a bit until more functionality is introduced.