Flutter map_view use map_view as widget - google-maps

I would like to ask on how to show the map fullscreen using the function MapView.Show function on map_view dart framework which I couldn't implement as a widget in flutter. see my code below:
MapView showMap() {
return _mapView.show(new MapOptions(
mapViewType: MapViewType.normal,
initialCameraPosition:
new CameraPosition(new Location(10.31264, 123.91139), 12.0),
showUserLocation: true,
));
}
should be put inside the child in widget.
#override
Widget build(BuildContext context) {
return new Container(
color: Colors.red,
height: double.infinity,
width: double.infinity,
child: showMap(), // surprisingly not working
);
}
I looked into tutorials on this implementation but it seems I haven't seen any liable sources on this implementation. Does anyone knew how to implement this one? Thanks!
Note: I want to implement as a fullscreen widget.

As far as I know, you have to show the Map_View calling a function when an event happens (like when a button is pressed). It's not a Widget like a Text or a Padding.
If you want to open a fullscreen Map I'd suggest you to try, for example, this.
#override
Widget build(BuildContext context) {
return new Container(
color: Colors.red,
height: double.infinity,
width: double.infinity,
child: Center(
child: RaisedButton(
onPressed: () => showMap(),
child: Text("Click me!"),
),
),
);
}

Related

Stateless widget and Widget function difference

I have read the difference between Stateless widgets and functions that return a Widget and I know that the framework can recognize classes but not functions. In the below code, I have a floating button, in which I call the setState() and in both cases the appbar rebuilds (stateless widget and function), so in this context are these two any different?
appBar:
AppBarv1(title: widget.title,)
// customAppBar(title: widget.title)
,
floatingActionButton: FloatingActionButton(backgroundColor: Colors.blue,onPressed: (){
setState(() {
});
},),
body:
Center(
),
);
PreferredSizeWidget customAppBar({String title}) {
print('appbar is built');
return AppBar(
title: Text(title),
actions: [],
);
}
class AppBarv1 extends PreferredSize {
const AppBarv1({this.title});
final String title;
#override
Size get preferredSize => Size.fromHeight(kToolbarHeight);
#override
Widget build(BuildContext context) {
print('appbar is built');
return AppBar(
title: Text(title),
actions: [],
);
}
}
Thanks in advance!
They are no different, other than that the function executes before the Widget is returned. The Widget-Tree you end up with, is identical.

Flutter: How to animate the camera of Google Maps

I'm trying to build an app that loads a GoogleMap(), then after getting the user latitude and longitude moves to the that specific location.
I came up with this idea (code below), but it works only if I restart the app and if I don't it gives error: animateCamera was called on null.
How is it possible ? and how can i fix it ?
Thanks for answering :D
...
var mapController;
...
GoogleMap createMap() {
var initMap = GoogleMap(
onMapCreated: onMapCreated,
initialCameraPosition:
CameraPosition(target: LatLng(47.290542, 8.322641), zoom: 6.7),
);
return initMap;
}
...
void onMapCreated(controller) {
mapController = controller;
}
...
void moveCameraToUserLocation(searchedLocation2) async {
var location = await Geocode().getLatLng(searchedLocation2);
print("moving to: $location");
mapController.animateCamera(
CameraUpdate.newCameraPosition(
CameraPosition(
target: location,
zoom: 20,
),
),
);
...
build(context) {
return Scaffold(
body: createMap(),
...
Based on how you describe the problem, it looks like you are only calling the animate function as the map loads.
I suggest that you create a button that would handle and trigger the animate function and move the camera to the device location whenever tapped.
The following code snippet uses a ClipOval button and inside the OnTap() event you can call the method to get the device current location which will be triggered whenever the button is tapped.
ClipOval(
child: Material(
color: Colors.green[100], // button color
child: InkWell(
splashColor: Colors.green, // inkwell color
child: SizedBox(
width: 56,
height: 56,
child: Icon(Icons.my_location),
),
onTap: () {
// Add methods here that will be called whenever the button is tapped
mapController.animateCamera(CameraUpdate.newCameraPosition(CameraPosition(
target: LatLng(_currentPosition.latitude, _currentPosition.longitude),
zoom: 17.0)));
setState(() {
allMarkers.add(Marker(
markerId: MarkerId('Current Position'),
draggable: false,
position:
LatLng(_currentPosition.latitude, _currentPosition.longitude)));
});
},
),
),
)
Probably you are calling moveCameraToUserLocation function before map is created. From this part of the code I cannot se when you call thi function but my guess is that you call it from initstate. If you want to call this function immediately after widget is created move it to onMapCreated.
void onMapCreated(controller) {
mapController = controller;
moveCameraToUserLocation();
}

WebView in Flutter for Web is not loading Google Maps or others

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

How to mock 'google_maps_flutter' package for flutter tests?

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

Flutter Maps Overlay Issue

I'm working on Flutter for an app that uses Google Maps. The app is made up of 2 activities: a list and the map.
This paragraph is just some background information. You may skip it. Usually Google Maps let you call a map by tapping a static map which opens into a dynamic one. The static map is just a small widget. The app need to directly display a full screen map on a single activity.
The issue we faced has to do with Overlays. Auby Khan from medium.com provided the code needed to display a full screen map. So we created the first activity with a button that navigates you to the second activity:
new IconButton(
icon: new Icon(Icons.map),
tooltip: 'openMap',
onPressed: (){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ControlParkMapNormal()),
);
},
),
And in the second activity, it would display the map:
final size = MediaQueryData.fromWindow(ui.window).size;
final GoogleMapOverlayController controller =
GoogleMapOverlayController.fromSize(
width: size.width,
height: size.height,
);
final mapController = controller.mapController;
final Widget mapWidget = GoogleMapOverlay(controller: controller);
class ControlParkMapNormal extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: new Scaffold(
appBar: AppBar(
title: Text("ControlPark"),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.list),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ControlPark()),
);
},
),
],
),
body: MapsDemo(mapWidget, controller.mapController),
),
navigatorObservers: <NavigatorObserver>[controller.overlayController],
);
}
}
class MapsDemo extends StatelessWidget {
MapsDemo(this.mapWidget, this.controller);
final Widget mapWidget;
final GoogleMapController controller;
#override
Widget build(BuildContext context) {
return Center(child: mapWidget);
}
}
When Navigating from Activity 1 > Activity 2 > Activity 1, the map would remain displayed. It would seem that the map is permanently overlayed on all subsequent activities. The transition from Activity 1 > Activity 2 > Activity 1 > Activity 2 yields this error:
I/flutter (12701): Another exception was thrown: 'package:flutter/src/widgets/navigator.dart': Failed assertion: line 1303 pos 14: 'observer.navigator == null': is not true.
Here's the block of code for the observer navigator:
#override
void initState() {
super.initState();
for (NavigatorObserver observer in widget.observers) {
assert(observer.navigator == null);
observer._navigator = this;
}
Is there any way to resolve this?