ZOFTINO.COM android and web dev tutorials

Android MapView Tutorial

This tutorial is a continuation of Google maps in android apps tutorial and shows how to use MapView instead of SupportMapFragment to display Google maps in android applications. It also covers Google maps UI controls or settings, gestures, events and lite mode topics which were not covered in the previous tutorial Google maps android tutorial. You can find initial setup required to use Google maps android API in android projects at Google maps android tutorial.

If you want to learn android and its latest features with examples. Please visit android tutorials to learn android concepts, components and libraries with examples.

Defining MapView in Layout

To display maps in your android app, you need to first add MapView to activity layout.

 <?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <com.google.android.gms.maps.MapView
        android:id="@+id/map_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/toolbar">
    </com.google.android.gms.maps.MapView>
</android.support.constraint.ConstraintLayout>
 

Activity MapView

In the activity, get the MapView object and call getMapAsync on it passing OnMapReadyCallback handler. And also you need to make sure that you call onCreate, onSaveInstanceState, onResume, onStart, onStop, onPause, onDestroy and onLowMemory methods on MapView object in the corresponding activity lifecycle methods.

In the OnMapReadyCallback’s onMapReady method you can get GoogleMap object and apply required settings to customize the map.

 import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.model.LatLng;

public class MapViewActivity extends AppCompatActivity implements OnMapReadyCallback{
    private MapView mapView;
    private GoogleMap gmap;

    private static final String MAP_VIEW_BUNDLE_KEY = "MapViewBundleKey";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.mapview_layout);

        Toolbar tb = findViewById(R.id.toolbar);
        setSupportActionBar(tb);
        tb.setSubtitle("MapView");

        Bundle mapViewBundle = null;
        if (savedInstanceState != null) {
            mapViewBundle = savedInstanceState.getBundle(MAP_VIEW_BUNDLE_KEY);
        }

        mapView = findViewById(R.id.map_view);
        mapView.onCreate(mapViewBundle);
        mapView.getMapAsync(this);
    }
    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);

        Bundle mapViewBundle = outState.getBundle(MAP_VIEW_BUNDLE_KEY);
        if (mapViewBundle == null) {
            mapViewBundle = new Bundle();
            outState.putBundle(MAP_VIEW_BUNDLE_KEY, mapViewBundle);
        }

        mapView.onSaveInstanceState(mapViewBundle);
    }
    @Override
    protected void onResume() {
        super.onResume();
        mapView.onResume();
    }

    @Override
    protected void onStart() {
        super.onStart();
        mapView.onStart();
    }

    @Override
    protected void onStop() {
        super.onStop();
        mapView.onStop();
    }
    @Override
    protected void onPause() {
        mapView.onPause();
        super.onPause();
    }
    @Override
    protected void onDestroy() {
        mapView.onDestroy();
        super.onDestroy();
    }
    @Override
    public void onLowMemory() {
        super.onLowMemory();
        mapView.onLowMemory();
    }
    @Override
    public void onMapReady(GoogleMap googleMap) {
        gmap = googleMap;
        gmap.setMinZoomPreference(12);
        LatLng ny = new LatLng(40.7143528, -74.0059731);
        gmap.moveCamera(CameraUpdateFactory.newLatLng(ny));
    }
}
 
android mapview example

Google Maps UI Controls

You can enable UI controls such as compass, zoom controls, indoor level picker, and map tool bar by setting related attributes in xml or programmatically. By default UI controls are not displayed.

Compass will be visible on rotating the map.

Map toolbar will be visible on touching a marker. Map tool bar contains actions which take you to directions screen, google map app etc.

Indoor level picker is applicable for building with floor plans, which allow you to see floor plan of selected level. First you need to enable indoor maps by calling setIndoorEnabled and setting it true on GoogleMap object.

 mMap = googleMap;
mMap.setMinZoomPreference(12);
mMap.setIndoorEnabled(true);
UiSettings uiSettings = mMap.getUiSettings();
uiSettings.setIndoorLevelPickerEnabled(true);
uiSettings.setMyLocationButtonEnabled(true);
uiSettings.setMapToolbarEnabled(true);
uiSettings.setCompassEnabled(true);
uiSettings.setZoomControlsEnabled(true);

LatLng ny = new LatLng(40.7143528, -74.0059731);

MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(ny);
mMap.addMarker(markerOptions);

mMap.moveCamera(CameraUpdateFactory.newLatLng(ny));
 
android google maps ui controls, zoom, level picker, compass, map toolbar example

Google Maps Gestures Setting

By default user can tilt, pinch to stretch, zoom, rotate and scroll map. If you don’t want to provide these options to user, you can disable any or all of the gestures. Below example shows how to disable gestures by calling setRotateGesturesEnabled, setScrollGesturesEnabled, setTiltGesturesEnabled and setZoomGesturesEnabled methods on UiSettings object.

 UiSettings uiSettings = mMap.getUiSettings();
uiSettings.setRotateGesturesEnabled(false);
uiSettings.setScrollGesturesEnabled(false);
uiSettings.setTiltGesturesEnabled(false);
uiSettings.setZoomGesturesEnabled(false);

Google Maps Camera Position

You can change the camera position programmatically or in xml. Some of the camera position attributes are target position, bearing, tilt and zoom. Bearing is the direction the camera is pointing, which is in degrees clock wise from north. Tilt is camera angle in degrees from the line when it is directly facing the earth.

Classes which are used to configure camera position are CameraPosition.Builder, CameraPosition, CameraUpdate and CameraUpdateFactory. Using CameraPosition.Builder, you can define camera position and then you can apply new camera position to GoogleMap using moveCamera method which takes CameraUpdate as parameter.

To get CameraUpdate object, you need to CameraUpdateFactory and its methods. If you use CameraPosition.Builder and create CameraPosition, you can get CameraUpdate object for that using newCameraPosition method of CameraUpdateFactory.

You can update camera position in response to events. Below example shows how to update camera position.

 @Override
public void onMapReady(GoogleMap googleMap) {
    mMap = googleMap;

    LatLng ny = new LatLng(40.7143528, -74.0059731);

    CameraPosition.Builder camBuilder = CameraPosition.builder();
    camBuilder.bearing(45);
    camBuilder.tilt(30);
    camBuilder.target(ny);
    camBuilder.zoom(15);

    CameraPosition cp = camBuilder.build();

    mMap.moveCamera(CameraUpdateFactory.newCameraPosition(cp));
} 

Camera Position Update in Response to Events

Camera position can be updated in response to events, below example shows zoom change in response to OnMapClick event using OnMapClickListener as shown below.

 gmap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
    @Override
    public void onMapClick(LatLng latLng) {
        if(MapViewActivity.this.cameraPositionUpdate){
            MapViewActivity.this.cameraPositionUpdate = false;
            gmap.moveCamera(CameraUpdateFactory.zoomTo(18));
        }else{
            MapViewActivity.this.cameraPositionUpdate = true;
            gmap.moveCamera(CameraUpdateFactory.zoomTo(15));
        }
    }
});
 

Google Maps Event Listeners

There are several event handlers which you can implement and add to GoogleMap to provide custom behavior in response to user interaction on Google maps.

OnCameraIdleListener

OnCameraIdleListener’s onCameraIdle method is called after camera moves. You can add the listener to GoogleMap object by calling setOnCameraIdleListener.

 gmap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
    @Override
    public void onCameraIdle() {
        Toast.makeText(MapViewActivity.this, gmap.getUiSettings().toString(),Toast.LENGTH_SHORT);
    }
});

OnCameraMoveListener

OnCameraMoveListener’s onCameraMove method is called while camera moves. You can add the listener to GoogleMap object by calling setOnCameraMoveListener.

 gmap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() {
    @Override
    public void onCameraMove() {

//do something
    }
});
 

OnCameraMoveStartedListener

OnCameraMoveStartedListener’s onCameraMoveStarted method is called when camera motion starts. You can add the listener to GoogleMap object by calling setOnCameraMoveStartedListener. Based on the reason for camera motion, you can do something. Possible reasons for camera motion are GoogleMap.OnCameraMoveStartedListener.REASON_API_ANIMATION, GoogleMap.OnCameraMoveStartedListener.REASON_DEVELOPER_ANIMATION and GoogleMap.OnCameraMoveStartedListener.REASON_GESTURE

 gmap.setOnCameraMoveStartedListener(new GoogleMap.OnCameraMoveStartedListener() {
    @Override
    public void onCameraMoveStarted(int i) {
        if(GoogleMap.OnCameraMoveStartedListener.REASON_API_ANIMATION == i){
            //do something
        }
    }
});
 

OnCircleClickListener

OnCircleClickListener’s onCircleClick method is called when a circle on the maps is clicked. You can add the listener to GoogleMap object by calling setOnCircleClickListener. In onCircleClick method, you can use Circle object, which is clicked, to change circle settings or other customizations on map.

 gmap.setOnCircleClickListener(new GoogleMap.OnCircleClickListener() {
    @Override
    public void onCircleClick(Circle circle) {
        circle.setFillColor(R.color.colorAccent);
    }
});
 

OnInfoWindowClickListener

OnInfoWindowClickListener’s onInfoWindowClick method is called when marker’s info window is clicked. You can add the listener to GoogleMap object by calling setOnInfoWindowClickListener. Method onInfoWindowClick is passed the Marker object to which info window anchored. Using the Marker object, you can customize marker or info window in the handler method.

 gmap.setOnInfoWindowClickListener(new GoogleMap.OnInfoWindowClickListener() {
    @Override
    public void onInfoWindowClick(Marker marker) {
        marker.hideInfoWindow();
    }
});
 

OnInfoWindowCloseListener

OnInfoWindowCloseListener’s onInfoWindowClose method is called when info window is closed. You can add the listener to GoogleMap object by calling setOnInfoWindowCloseListener.

 gmap.setOnInfoWindowCloseListener(new GoogleMap.OnInfoWindowCloseListener() {
    @Override
    public void onInfoWindowClose(Marker marker) {
        marker.setIcon(BitmapDescriptorFactory.defaultMarker( BitmapDescriptorFactory.HUE_BLUE));
    }
});
 

OnMarkerClickListener

OnMarkerClickListener’s onMarkerClick method is called when a marker is clicked. You can add the listener to GoogleMap object by calling setOnMarkerClickListener. Return true to override the default behavior.

        gmap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
            @Override
            public boolean onMarkerClick(Marker marker) {
                marker.showInfoWindow();
                return true;
            }
        }); 

OnPoiClickListener

OnPoiClickListener’s onPoiClick method is called when any point of interest on the map is clicked. You can add the listener to GoogleMap object by calling setOnPoiClickListener method. PointOfInterest object which is passed to onPoiClick method can be used to get information about point of interest and do something like adding marker to POI and moving camera to POI as shown in the below example.

        gmap.setOnPoiClickListener(new GoogleMap.OnPoiClickListener() {
            @Override
            public void onPoiClick(PointOfInterest pointOfInterest) {
                MarkerOptions markerOptions = new MarkerOptions();
                markerOptions.position(pointOfInterest.latLng);
                gmap.addMarker(markerOptions);
                gmap.moveCamera(CameraUpdateFactory.newLatLng(pointOfInterest.latLng));
            }
        }); 

OnPolygonClickListener

OnPolygonClickListener’s onPolygonClick method is called when a polygon is clicked. You can add the listener to GoogleMap object by calling setOnPolygonClickListener, using polygon object passed to the handler method, you can customize the map.

        gmap.setOnPolygonClickListener(new GoogleMap.OnPolygonClickListener() {
            @Override
            public void onPolygonClick(Polygon polygon) {
                polygon.setStrokeColor(Color.DKGRAY);
            }
        }); 

Google Map Lite

You can display Google map in lite mode in android apps by setting lite mode attribute to true in xml or programmatically. You can set zoom, add marker, info window and shapes and select one of the supported map types to map, but lite mode doesn’t support camera tilt and bearing. User viewing the lite map can’t zoom or pan.

Lite mode xml attribute

To enable lite mode in xml layout, you need to set liteMode attribute to true.

    <com.google.android.gms.maps.MapView
        android:id="@+id/map_view"
	. . .
        app:liteMode="true"/> 

Enabling lite mode programmatically

To enable lite mode in code, you need to instantiate MapView passing GoogleMapOptions object to constructor and then add the MapView object to layout. GoogleMapOptions contains lite mode attribute which you need to set to true.

LinearLayout ll = findViewById(R.id.map_view_layout);

GoogleMapOptions options = new GoogleMapOptions().liteMode(true);

mapView = new MapView(this, options);
ll.addView(mapView);

mapView.onCreate(mapViewBundle);
mapView.getMapAsync(this);