[Huawei Developers] Berk Özyurt:
​

Hello everyone,

In this article, I will talk about how to use HMS Map Kit in Flutter applications and I will share sample codes for all features of Map Kit.

Today, Maps are the basis of many mobile applications. Unfortunately, finding resources for the integration of maps into applications developed with Flutter is more difficult than native applications. I hope this post will be a good resource for seamlessly integrating HMS Map Kit into your Flutter applications.

What is Map Kit ?

HMS Map Kit currently include all map data of more than 200 countries and regions and supports more than 100 languages.

HMS Map Kit is a Huawei Service that is easy to integrate, has a wide range of use and offers a variety of features. Moreover, Map Kit is constantly updated to enrich its data and reflect the differences on the map even at small scales.

To customize your maps, you can add markers, add rings, lines on the map. Map Kit offers us a wide range of uses to include everything you need on the map. You can see your your location live on the map, you can zoom and change the direction of the map. You can also see live traffic on the map. I think this is one of the most important features that should be in a map. I can say that Huawei has done a very successful job in reflecting traffic data on the map instantly. Finally, you can see the world’s most important locations in 3D thanks to Huawei Maps. I am sure that this feature will add a excitement to the map experience in your mobile application.

Note: HMS Map Kit works with EMUI 5.0 and above versions on Huawei devices and Android 7.0 and above on non-Huawei devices.

Development Steps

1. Create Your App in AppGallery Connect

Firstly you should be create a developer account in AppGallery Connect. After create your developer account, you can create a new project and new app. You can find a detail of these steps on the below.

2. Add Flutter Map Kit to Your Project

After creating your application on the AGC Console and activated Map Kit, the agconnect-services file should be added to the project first.

The agconnect-services.json configuration file should be added under the android/app directory in the Flutter project.

Next, the following dependencies for HMS usage need to be added to the build.gradle file under the android directory.

buildscript {
repositories {
google()
jcenter()
maven {url 'https://developer.huawei.com/repo/'}
}

dependencies {
classpath 'com.android.tools.build:gradle:3.5.0'
classpath 'com.huawei.agconnect:agcp:1.4.2.301'
}
}

allprojects {
repositories {
google()
jcenter()
maven {url 'https://developer.huawei.com/repo/'}
}
}

Then add the following line of code to the build.gradle file under the android/app directory.

apply plugin: 'com.huawei.agconnect'

Add the following permissions to use the map to the AndroidManifest.xml file.

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="com.huawei.appmarket.service.commondata.permission.GET_COMMON_DATA"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

Finally, the Map Kit SDK should be added to the pubspec.yaml file. To do this, open the pubspec.yaml file and add the required dependency as follows.

dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
huawei_map: ^5.0.3+302

And, by clicking “pub get”, the dependencies are added to Android Studio. After all these steps are completed, your app is ready to code.

3. Crate a Map

Firstly, create a HuaweiMapController object for create your map. Create a method called onMapCreated and set this object here for load the map when the application is opened.

Next, define a center coordinate and a zoom value for that coordinate. These values will use while map is opening.

Finally, after adding your map as a design, you will get a class coded as follows. For now, the screenshot of your application will also be as follows.

​

class MapPage extends StatefulWidget {
@override
_MapPageState createState() => _MapPageState();
}

class _MapPageState extends State<MapPage> {

HuaweiMapController _huaweiMapController;

static const LatLng _centerPoint = const LatLng(41.043982, 29.014333);
static const double _zoom = 12;

bool _cameraPosChanged = false;
bool _trafficEnabled = false;

@override
void initState() {
super.initState();
}

void onMapCreated(HuaweiMapController controller) {
_huaweiMapController = controller;
}

@override
Widget build(BuildContext context) {

final huaweiMap = HuaweiMap(
onMapCreated: onMapCreated,

mapType: MapType.normal,
tiltGesturesEnabled: true,
buildingsEnabled: true,
compassEnabled: true,
zoomControlsEnabled: true,
rotateGesturesEnabled: true,
myLocationButtonEnabled: true,
myLocationEnabled: true,

trafficEnabled: _trafficEnabled,
markers: _markers,
polylines: _polylines,
polygons: _polygons,
circles: _circles,

onClick: (LatLng latLng) {
log("Map Clicked at $latLng");
},
onLongPress: (LatLng latlng) {
log("Map LongClicked at $latlng");
},
initialCameraPosition: CameraPosition(
target: _centerPoint,
zoom: _zoom,
),
);

return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Map Kit', style: TextStyle(
color: Colors.black
)),
backgroundColor: Color(0xFFF9C335),
),
body: Stack(
children: <Widget>[
huaweiMap
],
),
),
);
}
}

As you can see in the code above, we need some parameters while creating the map. The explanation and intended use of some of the most important and most used parameters are as follows.

mapType : It represents the type of map loaded. Currently there is only 2 map type support for Flutter. These are “normal” and “none”. If mapType is none, map will not be loaded. The normal type map is as seen in the image above.

zoomControlsEnabled : It represents the visibility of the zoom buttons on the right of the map. If you set this value as “true”, the buttons are automatically loaded and used on the map as above. If you set as “false”, you cannot zoom in on the map with these buttons.

myLocationEnabled : It represents whether you can see your own instant location on the map. If you set it to “true”, your location will appear as a blue point on the map. If you set it as “false”, the user location will not seen on the map.

myLocationButtonEnabled : It represents the button just below the zoom buttons at the bottom right of the map. If you have set the value of myLocationEnabled as true, when you click the button the map will automatically zoom to your location.

onClick : Here you can define the events you want to be triggered when tapped on the map. As seen in the example above, when I click on the map, I print the latitude and longitude information of the relevant point.

onLongPress : Events that will be triggered by a long tap on the map should be defined here. As you can see in the example, when I touch the map long, I print the latitude and longitude information of the relevant point.

initialCameraPosition : The starting position and zoom value to be displayed when the map is loaded must be defined here.

4. Show Traffic Data on the Map

When I was talking about the features of the Map Kit, I just mentioned that this is the feature that I like the most. It is both functional and easy to use.

To display live traffic data with a one touch, you can set the “trafficEnabled” value that we defined while creating the map to “true”.

To do this, design a small, round button on the left side of the map and prepare a method called trafficButtonOnClick. This method changes the trafficEnabled value to true and false each time the button is pressed.

void trafficButtonOnClick() {
if (_trafficEnabled) {
setState(() {
_trafficEnabled = false;
});
} else {
setState(() {
_trafficEnabled = true;
});
}
}

You can design the button as follows, create a Column under the return MaterialApp, and call all the buttons which we will create here one after another. I am sharing the button design and general design on the below. Each button that will be created from now on will be located under the trafficButton that we will add now.

@override
Widget build(BuildContext context) {
final huaweiMap = HuaweiMap(
onMapCreated: onMapCreated,

mapType: MapType.normal,
tiltGesturesEnabled: true,
buildingsEnabled: true,
compassEnabled: true,
zoomControlsEnabled: true,
rotateGesturesEnabled: true,
myLocationButtonEnabled: true,
myLocationEnabled: true,

trafficEnabled: _trafficEnabled,
markers: _markers,
polylines: _polylines,
polygons: _polygons,
circles: _circles,

onClick: (LatLng latLng) {
log("Map Clicked at $latLng");
},
onLongPress: (LatLng latlng) {
log("Map LongClicked at $latlng");
},
initialCameraPosition: CameraPosition(
target: _centerPoint,
zoom: _zoom,
),
);

final trafficButton = Padding(
padding: EdgeInsets.all(8.0),
child: FloatingActionButton(
onPressed: () => trafficButtonOnClick(),
materialTapTargetSize: MaterialTapTargetSize.padded,
backgroundColor: Color(0xFFF9C335),
tooltip: "Traffic",
child: const Icon(Icons.traffic, size: 36.0, color: Colors.black),
),
);

return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Map Kit', style: TextStyle(
color: Colors.black
)),
backgroundColor: Color(0xFFF9C335),
),
body: Stack(
children: <Widget>[
huaweiMap,
Padding(
padding: const EdgeInsets.all(16.0),
child: Align(
alignment: Alignment.topLeft,
child: Column(
children: <Widget>[
trafficButton
//other buttons here
],
),
),
),
],
),
),
);
}

After the traffic button is added, the screen of the map will be as follows.

​

5. Create 3D Map

My another favorite feature is that. But Map Kit doesn’t support 3D maps for areas in Turkey. As I said, since this feature is not supported in Turkey, I entered the latitude and longitude information of Collesium and enabled the camera to move to this point and show it to me in 3D.

Likewise, as the button is clicked, we must ensure that this feature is active and deactivated respectively. When it is active, we will see the Collesium, and when we deactivate it, we must return to the center position we first defined. For this, we create a method named moveCameraButtonOnClick as follows.

void moveCameraButtonOnClick() {
if (!_cameraPosChanged) {
_huaweiMapController.animateCamera(
CameraUpdate.newCameraPosition(
const CameraPosition(
bearing: 270.0,
target: LatLng(41.889228, 12.491780),
tilt: 45.0,
zoom: 17.0,
),
),
);
_cameraPosChanged = !_cameraPosChanged;
} else {
_huaweiMapController.animateCamera(
CameraUpdate.newCameraPosition(
const CameraPosition(
bearing: 0.0,
target: _centerPoint,
tilt: 0.0,
zoom: 12.0,
),
),
);
_cameraPosChanged = !_cameraPosChanged;
}
}

While designing the button, we must located on the left side and one under the other. By making the button design as follows, we add it under the trafficButton with the name moveCamreButton, as I mentioned in fourth section. After adding the relevant code, the screenshot will be as follows.

final moveCamreButton = Padding(
padding: EdgeInsets.all(8.0),
child: FloatingActionButton(
onPressed: () => moveCameraButtonOnClick(),
materialTapTargetSize: MaterialTapTargetSize.padded,
backgroundColor: Color(0xFFF9C335),
tooltip: "CameraMove",
child:
const Icon(Icons.airplanemode_active, size: 36.0, color: Colors.black),
),
);

​

6. Add Markers to Your Map

Markers are indispensable for map services. Thanks to this feature, you can add markers in different colors and designs on the map according to your needs. With these markers, you can named a special address and highlight it on the map.

You need some data to add a marker. These are the markerId, position, title, snippet, icon, draggable, rotation values that you will specify when creating the marker.

The code on the below contains the values and sample code required to add a normal marker. With this code, you can add a classic marker as you see it on every map.

The second marker is draggable. You can move the marker anywhere you want by holding down on it. For this, you must set the draggable value to true.

The third marker is located on the map at an angle. If you want the marker to be located at any angle such as 45' or 60' rather than perpendicular, it will be sufficient to give the angle you want to the rotation value.

The fourth and last marker will look different and colorful, unlike the others.

You can create markers in any style you want using these four features. The codes required to create markers are as follows.

void markersButtonOnClick() {
if (_markers.length > 0) {
setState(() {
_markers.clear();
});
} else {
setState(() {
_markers.add(Marker(
markerId: MarkerId('normal_marker'),
position: LatLng(40.997802, 28.994978),
infoWindow: InfoWindow(
title: 'Normal Marker Title',
snippet: 'Description Here!',
onClick: () {
log("Normal Marker InfoWindow Clicked");
}),

onClick: () {
log('Normal Marker Clicked!');
},
icon: BitmapDescriptor.defaultMarker,
));

_markers.add(Marker(
markerId: MarkerId('draggable_marker'),
position: LatLng(41.027335, 29.002359),
draggable: true,
flat: true,
rotation: 0.0,
infoWindow: InfoWindow(
title: 'Draggable Marker Title',
snippet: 'Hi! Description Here!',
),
clickable: true,
onClick: () {
log('Draggable Marker Clicked!');
},
onDragEnd: (pos) {
log("Draggable onDragEnd position : ${pos.lat}:${pos.lng}");
},
icon: BitmapDescriptor.defaultMarker,
));

_markers.add(Marker(
markerId: MarkerId('angular_marker'),
rotation: 45,
position: LatLng(41.043974, 29.028881),
infoWindow: InfoWindow(
title: 'Angular Marker Title',
snippet: 'Hey! Why can not I stand up straight?',
onClick: () {
log("Angular marker infoWindow clicked");
}),
icon: BitmapDescriptor.defaultMarker,
));
});

_markers.add(Marker(
markerId: MarkerId('colorful_marker'),
position: LatLng(41.076009, 29.054630),
infoWindow: InfoWindow(
title: 'Colorful Marker Title',
snippet: 'Yeap, as you know, description here!',
onClick: () {
log("Colorful marker infoWindow clicked");
}),
onClick: () {
log('Colorful Marker Clicked');
},
icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueMagenta),
));
}
}

Again, you can create a new button to be located on the left side of the map and add it to the relevant place in the code. Don’t forget to call the above markersButtonOnClick method on the onPressed of the button you created. You can find the necessary codes and screenshot for button design below.

final markerButton = Padding(
padding: EdgeInsets.all(8.0),
child: FloatingActionButton(
onPressed: markersButtonOnClick,
materialTapTargetSize: MaterialTapTargetSize.padded,
backgroundColor: Color(0xFFF9C335),
child: const Icon(Icons.add_location, size: 36.0, color: Colors.black),
),
);

​

7. Add Circle to Your Map

To add a circle, create a method called circlesButtonOnClick and define circleId, center, radius, fillColor, strokeColor, strokeWidth, zIndex, clickable values for the circle that will be created within this method.

All of these values depending on which point on the map, what size and color you will add a circle.

As an example, I share the screenshot below with the circlesButtonOnClick method, which adds two circles when the button is pressed, and the circlesButton design that I call this method.

void circlesButtonOnClick() {
if (_circles.length > 0) {
setState(() {
_circles.clear();
});
} else {
LatLng point1 = LatLng(40.986595, 29.025362);
LatLng point2 = LatLng(41.023644, 29.014032);

setState(() {
_circles.add(Circle(
circleId: CircleId('firstCircle'),
center: point1,
radius: 1000,
fillColor: Color.fromARGB(100, 249, 195, 53),
strokeColor: Color(0xFFF9C335),
strokeWidth: 3,
zIndex: 2,
clickable: true,
onClick: () {
log("First Circle clicked");
}));
_circles.add(Circle(
circleId: CircleId('secondCircle'),
center: point2,
zIndex: 1,
clickable: true,
onClick: () {
log("Second Circle Clicked");
},
radius: 2000,
fillColor: Color.fromARGB(50, 230, 20, 50),
strokeColor: Color.fromARGB(50, 230, 20, 50),
));
});
}
}

final circlesButton = Padding(
padding: EdgeInsets.all(8.0),
child: FloatingActionButton(
onPressed: circlesButtonOnClick,
materialTapTargetSize: MaterialTapTargetSize.padded,
backgroundColor: Color(0xFFF9C335),
child: const Icon(Icons.adjust, size: 36.0, color: Colors.black),
),
);

​

8. Add Polylines to Your Map

The purpose of using polyline is to draw a straight line between 2 coordinates.

The parameters we need to draw a polyline are polylineId, points, color, zIndex, endCap, startCap, clickable values. Here you can set the start and end points with enCap and startCap values. For location values, you need to define two LatLng values as an array.

To create a polyline, create a method called polylinesButtonOnClick and set the above values according to your needs. For button design, create a method called polylinesButton and call the polylinesButtonOnClick method in onPress. The screenshot after adding all the codes and polyline is as follows.

void polylinesButtonOnClick() {
if (_polylines.length > 0) {
setState(() {
_polylines.clear();
});
} else {
List<LatLng> line1 = [
LatLng(41.068698, 29.030855),
LatLng(41.045916, 29.059351),
];
List<LatLng> line2 = [
LatLng(40.999551, 29.062441),
LatLng(41.025975, 29.069651),
];

setState(() {
_polylines.add(Polyline(
polylineId: PolylineId('firstLine'),
points: line1,
color: Colors.pink,
zIndex: 2,
endCap: Cap.roundCap,
startCap: Cap.squareCap,
clickable: true,
onClick: () {
log("First Line Clicked");
}));
_polylines.add(Polyline(
polylineId: PolylineId('secondLine'),
points: line2,
width: 2,
patterns: [PatternItem.dash(20)],
jointType: JointType.bevel,
endCap: Cap.roundCap,
startCap: Cap.roundCap,
color: Color(0x900072FF),
zIndex: 1,
clickable: true,
onClick: () {
log("Second Line Clicked");
}));
});
}
}

final polylinesButton = Padding(
padding: EdgeInsets.all(8.0),
child: FloatingActionButton(
onPressed: polylinesButtonOnClick,
materialTapTargetSize: MaterialTapTargetSize.padded,
backgroundColor: Color(0xFFF9C335),
child: const Icon(Icons.waterfall_chart, size: 36.0, color: Colors.black),
),
);

​

9. Add Polygon to Your Map

Polygon is exactly the same as polyline. The only difference is that when adding polygons, you can draw the shapes you want, such as triangles and pentagons, by specifying more than two points.

The parameters we need to draw a polygon are polygonId, points, fillColor, strokeColor, strokeWidth, zIndex, clickable values. For Points value, you need to define more than two LatLng values as an array.

To add polygons, create a method called polygonsButtonOnClick and set the above values according to your needs. For button design, create a method named polygonsButton and call the polygonsButtonOnClick method in onPress. After adding all the codes and polygon, the screenshot is as follows.

void polygonsButtonOnClick() {
if (_polygons.length > 0) {
setState(() {
_polygons.clear();
});
} else {
List<LatLng> points1 = [
LatLng(40.989306, 29.021242),
LatLng(40.980753, 29.024590),
LatLng(40.982632, 29.031885),
LatLng(40.991273, 29.024676)
];
List<LatLng> points2 = [
LatLng(41.090321, 29.025598),
LatLng(41.085146, 29.018045),
LatLng(41.077124, 29.016844),
LatLng(41.075441, 29.026285),
LatLng(41.079582, 29.036928),
LatLng(41.086828, 29.031435)
];

setState(() {
_polygons.add(Polygon(
polygonId: PolygonId('polygon1'),
points: points1,
fillColor: Color.fromARGB(100, 129, 95, 53),
strokeColor: Colors.brown[900],
strokeWidth: 1,
zIndex: 2,
clickable: true,
onClick: () {
log("Polygon 1 Clicked");
}));
_polygons.add(Polygon(
polygonId: PolygonId('polygon2'),
points: points2,
fillColor: Color.fromARGB(190, 242, 195, 99),
strokeColor: Colors.yellow[900],
strokeWidth: 1,
zIndex: 1,
clickable: true,
onClick: () {
log("Polygon 2 Clicked");
}));
});
}
}

final polygonsButton = Padding(
padding: EdgeInsets.all(8.0),
child: FloatingActionButton(
onPressed: polygonsButtonOnClick,
materialTapTargetSize: MaterialTapTargetSize.padded,
backgroundColor: Color(0xFFF9C335),
tooltip: "Polygons",
child: const Icon(Icons.crop_square, size: 36.0, color: Colors.black),
),
);

​

10. Clear Your Map

You can use all of the features on your map at the same time. You can combine the features you want according to the needs of your application and to increase the user experience to higher levels. After adding all these features at the same time, the final view of your map will be as follows.

​

To delete all the elements you added on the map with a single button, you can create a method called clearMap and clear the map in this method.

void clearMap() {
setState(() {
_markers.clear();
_polylines.clear();
_polygons.clear();
_circles.clear();
});
}

final clearButton = Padding(
padding: EdgeInsets.all(8.0),
child: FloatingActionButton(
onPressed: () => clearMap(),
materialTapTargetSize: MaterialTapTargetSize.padded,
backgroundColor: Color(0xFFF9C335),
tooltip: "Clear",
child: const Icon(Icons.refresh, size: 36.0, color: Colors.black),
),
);

After all the methods are added, your code structure should be as follows.

class MapPage extends StatefulWidget {
@override
_MapPageState createState() => _MapPageState();

}

class _MapPageState extends State<MapPage> {

HuaweiMapController _huaweiMapController;

static const LatLng _centerPoint = const LatLng(41.043982, 29.014333);
static const double _zoom = 12;

final Set<Marker> _markers = {};
final Set<Polyline> _polylines = {};
final Set<Polygon> _polygons = {};
final Set<Circle> _circles = {};

bool _cameraPosChanged = false;
bool _trafficEnabled = false;

@override
void initState() {
super.initState();
}

void onMapCreated(HuaweiMapController controller) {
_huaweiMapController = controller;
}

void clearMap() {
setState(() {
_markers.clear();
_polylines.clear();
_polygons.clear();
_circles.clear();
});
}

void log(msg) {
print(msg);
}

void markersButtonOnClick() {
if (_markers.length > 0) {
setState(() {
_markers.clear();
});
} else {
setState(() {
_markers.add(Marker(
markerId: MarkerId('normal_marker'),
position: LatLng(40.997802, 28.994978),
infoWindow: InfoWindow(
title: 'Normal Marker Title',
snippet: 'Description Here!',
onClick: () {
log("Normal Marker InfoWindow Clicked");
}),

onClick: () {
log('Normal Marker Clicked!');
},
icon: BitmapDescriptor.defaultMarker,
));
_markers.add(Marker(
markerId: MarkerId('draggable_marker'),
position: LatLng(41.027335, 29.002359),
draggable: true,
flat: true,
rotation: 0.0,
infoWindow: InfoWindow(
title: 'Draggable Marker Title',
snippet: 'Hi! Description Here!',
),
clickable: true,
onClick: () {
log('Draggable Marker Clicked!');
},
onDragEnd: (pos) {
log("Draggable onDragEnd position : ${pos.lat}:${pos.lng}");
},
icon: BitmapDescriptor.defaultMarker,
));
_markers.add(Marker(
markerId: MarkerId('angular_marker'),
rotation: 45,
position: LatLng(41.043974, 29.028881),
infoWindow: InfoWindow(
title: 'Angular Marker Title',
snippet: 'Hey! Why can not I stand up straight?',
onClick: () {
log("Angular marker infoWindow clicked");
}),
icon: BitmapDescriptor.defaultMarker,
));
});
_markers.add(Marker(
markerId: MarkerId('colorful_marker'),
position: LatLng(41.076009, 29.054630),
infoWindow: InfoWindow(
title: 'Colorful Marker Title',
snippet: 'Yeap, as you know, description here!',
onClick: () {
log("Colorful marker infoWindow clicked");
}),
onClick: () {
log('Colorful Marker Clicked');
},
icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueMagenta),
));
}
}

void polygonsButtonOnClick() {
if (_polygons.length > 0) {
setState(() {
_polygons.clear();
});
} else {
List<LatLng> points1 = [
LatLng(40.989306, 29.021242),
LatLng(40.980753, 29.024590),
LatLng(40.982632, 29.031885),
LatLng(40.991273, 29.024676)
];
List<LatLng> points2 = [
LatLng(41.090321, 29.025598),
LatLng(41.085146, 29.018045),
LatLng(41.077124, 29.016844),
LatLng(41.075441, 29.026285),
LatLng(41.079582, 29.036928),
LatLng(41.086828, 29.031435)
];

setState(() {
_polygons.add(Polygon(
polygonId: PolygonId('polygon1'),
points: points1,
fillColor: Color.fromARGB(100, 129, 95, 53),
strokeColor: Colors.brown[900],
strokeWidth: 1,
zIndex: 2,
clickable: true,
onClick: () {
log("Polygon 1 Clicked");
}));
_polygons.add(Polygon(
polygonId: PolygonId('polygon2'),
points: points2,
fillColor: Color.fromARGB(190, 242, 195, 99),
strokeColor: Colors.yellow[900],
strokeWidth: 1,
zIndex: 1,
clickable: true,
onClick: () {
log("Polygon 2 Clicked");
}));
});
}
}

void polylinesButtonOnClick() {
if (_polylines.length > 0) {
setState(() {
_polylines.clear();
});
} else {
List<LatLng> line1 = [
LatLng(41.068698, 29.030855),
LatLng(41.045916, 29.059351),
];
List<LatLng> line2 = [
LatLng(40.999551, 29.062441),
LatLng(41.025975, 29.069651),
];

setState(() {
_polylines.add(Polyline(
polylineId: PolylineId('firstLine'),
points: line1,
color: Colors.pink,
zIndex: 2,
endCap: Cap.roundCap,
startCap: Cap.squareCap,
clickable: true,
onClick: () {
log("First Line Clicked");
}));
_polylines.add(Polyline(
polylineId: PolylineId('secondLine'),
points: line2,
width: 2,
patterns: [PatternItem.dash(20)],
jointType: JointType.bevel,
endCap: Cap.roundCap,
startCap: Cap.roundCap,
color: Color(0x900072FF),
zIndex: 1,
clickable: true,
onClick: () {
log("Second Line Clicked");
}));
});
}
}

void circlesButtonOnClick() {
if (_circles.length > 0) {
setState(() {
_circles.clear();
});
} else {
LatLng point1 = LatLng(40.986595, 29.025362);
LatLng point2 = LatLng(41.023644, 29.014032);

setState(() {
_circles.add(Circle(
circleId: CircleId('firstCircle'),
center: point1,
radius: 1000,
fillColor: Color.fromARGB(100, 249, 195, 53),
strokeColor: Color(0xFFF9C335),
strokeWidth: 3,
zIndex: 2,
clickable: true,
onClick: () {
log("First Circle clicked");
}));
_circles.add(Circle(
circleId: CircleId('secondCircle'),
center: point2,
zIndex: 1,
clickable: true,
onClick: () {
log("Second Circle Clicked");
},
radius: 2000,
fillColor: Color.fromARGB(50, 230, 20, 50),
strokeColor: Color.fromARGB(50, 230, 20, 50),
));
});
}
}

void moveCameraButtonOnClick() {
if (!_cameraPosChanged) {
_huaweiMapController.animateCamera(
CameraUpdate.newCameraPosition(
const CameraPosition(
bearing: 270.0,
target: LatLng(41.889228, 12.491780),
tilt: 45.0,
zoom: 17.0,
),
),
);
_cameraPosChanged = !_cameraPosChanged;
} else {
_huaweiMapController.animateCamera(
CameraUpdate.newCameraPosition(
const CameraPosition(
bearing: 0.0,
target: _centerPoint,
tilt: 0.0,
zoom: 12.0,
),
),
);
_cameraPosChanged = !_cameraPosChanged;
}
}

void trafficButtonOnClick() {
if (_trafficEnabled) {
setState(() {
_trafficEnabled = false;
});
} else {
setState(() {
_trafficEnabled = true;
});
}
}

@override
Widget build(BuildContext context) {
final huaweiMap = HuaweiMap(
onMapCreated: onMapCreated,

mapType: MapType.normal,
tiltGesturesEnabled: true,
buildingsEnabled: true,
compassEnabled: true,
zoomControlsEnabled: true,
rotateGesturesEnabled: true,
myLocationButtonEnabled: true,
myLocationEnabled: true,
trafficEnabled: _trafficEnabled,
markers: _markers,
polylines: _polylines,
polygons: _polygons,
circles: _circles,
onClick: (LatLng latLng) {
log("Map Clicked at $latLng");
},
onLongPress: (LatLng latlng) {
log("Map LongClicked at $latlng");
},
initialCameraPosition: CameraPosition(
target: _centerPoint,
zoom: _zoom,
),
);

final markerButton = Padding(
padding: EdgeInsets.all(8.0),
child: FloatingActionButton(
onPressed: markersButtonOnClick,
materialTapTargetSize: MaterialTapTargetSize.padded,
backgroundColor: Color(0xFFF9C335),
child: const Icon(Icons.add_location, size: 36.0, color: Colors.black),
),
);

final circlesButton = Padding(
padding: EdgeInsets.all(8.0),
child: FloatingActionButton(
onPressed: circlesButtonOnClick,
materialTapTargetSize: MaterialTapTargetSize.padded,
backgroundColor: Color(0xFFF9C335),
child: const Icon(Icons.adjust, size: 36.0, color: Colors.black),
),
);

final polylinesButton = Padding(
padding: EdgeInsets.all(8.0),
child: FloatingActionButton(
onPressed: polylinesButtonOnClick,
materialTapTargetSize: MaterialTapTargetSize.padded,
backgroundColor: Color(0xFFF9C335),
child: const Icon(Icons.waterfall_chart, size: 36.0, color: Colors.black),
),
);

final polygonsButton = Padding(
padding: EdgeInsets.all(8.0),
child: FloatingActionButton(
onPressed: polygonsButtonOnClick,
materialTapTargetSize: MaterialTapTargetSize.padded,
backgroundColor: Color(0xFFF9C335),
tooltip: "Polygons",
child: const Icon(Icons.crop_square, size: 36.0, color: Colors.black),
),
);

final clearButton = Padding(
padding: EdgeInsets.all(8.0),
child: FloatingActionButton(
onPressed: () => clearMap(),
materialTapTargetSize: MaterialTapTargetSize.padded,
backgroundColor: Color(0xFFF9C335),
tooltip: "Clear",
child: const Icon(Icons.refresh, size: 36.0, color: Colors.black),
),
);

final moveCamreButton = Padding(
padding: EdgeInsets.all(8.0),
child: FloatingActionButton(
onPressed: () => moveCameraButtonOnClick(),
materialTapTargetSize: MaterialTapTargetSize.padded,
backgroundColor: Color(0xFFF9C335),
tooltip: "CameraMove",
child:
const Icon(Icons.airplanemode_active, size: 36.0, color: Colors.black),
),
);

final trafficButton = Padding(
padding: EdgeInsets.all(8.0),
child: FloatingActionButton(
onPressed: () => trafficButtonOnClick(),
materialTapTargetSize: MaterialTapTargetSize.padded,
backgroundColor: Color(0xFFF9C335),
tooltip: "Traffic",
child: const Icon(Icons.traffic, size: 36.0, color: Colors.black),
),
);

return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Map Kit', style: TextStyle(
color: Colors.black
)),
backgroundColor: Color(0xFFF9C335),
),
body: Stack(
children: <Widget>[
huaweiMap,
Padding(
padding: const EdgeInsets.all(16.0),
child: Align(
alignment: Alignment.topLeft,
child: Column(
children: <Widget>[
clearButton,
trafficButton,
moveCamreButton,
markerButton,
circlesButton,
polylinesButton,
polygonsButton
],
),
),
),
],
),
),
);
}
}