Zachary Powell

Software Programmer

Zachary Powell

Download my CV Send me a Message

Google Maps

Display location and custom pin on Google Map in iOS

Zachary Powell - 06/01/2016

Today we will look at how to Display the users current location within a Google Map, and also look at using custom pins in iOS. Much the same as we have already covered for Android HERE and HERE, also make sure to check out our last guide on setting up Google Maps for iOS HERE (if you have not already!)

Display User Location

Displaying the users location on the Google map within iOS is a very simple process. Once we have the map view set up, we just need to set myLocationEnabled to YES with self.mapView.myLocationEnabled = YES;. From here, we will have our location displayed on the map. However, the map will not move to the users current location or move the map as the user moves.

Jump to Users current location

To do this, we first need to make some changes to the mapview set up:

-(void)viewDidLoad{
...
    self.mapView.myLocationEnabled = YES;
    self.mapView.mapType = kGMSTypeNormal;
    self.mapView.settings.compassButton = YES;
    self.mapView.settings.myLocationButton = YES;
    self.mapView.delegate = self;
    [_mapView addObserver:self
               forKeyPath:@"myLocation"
                  options:NSKeyValueObservingOptionNew
                  context:NULL];
    dispatch_async(dispatch_get_main_queue(), ^{
        _mapView.myLocationEnabled = YES;
    });
...
}

So we have now added the myLocationEnabled, as well as adding the compass and myLocation button. We then need to set up a delegate to handle updating the map view to move to the users location. This is set by adding the Observer. We then need to create the actual function that will be called.

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context {
       
        CLLocation *location = [change objectForKey:NSKeyValueChangeNewKey];
        longitude = location.coordinate.longitude;
        latitude = location.coordinate.latitude;
        
        _mapView.camera = [GMSCameraPosition cameraWithTarget:location.coordinate
                                                         zoom:14];
    }
}

The above code is called when ever the location changes. We get the new location object, take the longitude and latitude and then finally move the maps camera to that location. This way, the map will always be centred on the users location as they move.

Plot Marker with default pin

Much like in Android, creating a Marker and plotting it on the Map is very easy to do, but offers a range of features we can use to customise them. Lets first look at a very simple marker.

GMSMarker *marker = [[GMSMarker alloc] init];
marker.position = CLLocationCoordinate2DMake(53.784426, -1.735840);
marker.title =  @"Test Pin";
marker.map = _mapView;

Here we create the new GMSMarker object then set its position and title, before finally setting its map as our map view. This is a very simple set up and plenty of other options are available check out THIS

Plot Marker with custom pin colour

Another example is setting the icon. We can either use a custom image or take the normal Marker and load a different colour.

UIImage *green = [GMSMarker markerImageWithColor:[UIColor greenColor]];
GMSMarker *marker = [[GMSMarker alloc] init];
marker.position = CLLocationCoordinate2DMake(53.785426, -1.735800);
marker.title = @"Green Marker";        
marker.icon = green;
marker.map = _mapView;

Here we create a green Marker icon, but we could use any UIColor.

As always, if you have any questions, comment below.

Leave a Reply

Your email address will not be published. Required fields are marked *

Tags: ,

Using Google maps in iOS

Zachary Powell - 30/12/2015

Today, we will look at setting up and using the Google Maps SDK on iOS devices. This leads on from our look at doing the same on Android HERE.

Setting up

First and foremost, make sure you have the most up to date version of Xcode. The Google Maps SDK only works for version 6.3 and above. The current version is 7.2 and I would recommend using this version for iOS 9 support.

To install the Google Maps SDK, we will be using CocoaPods. CocoaPods is an open source dependency manager for both Swift and Objective-C projects. If you don’t already have cocoapods installed, please do so now by opening a terminal and typing the below command:

sudo gem install cocoapods

Installing

If you are not using a pre existing project, now is the time to create one. Create a simple Single View Application.

Screen Shot 2015-12-21 at 20.21.08

Next we need to create a file called Podfile in the project directory. This file defines our projects dependencies, which in this case will be Google Maps. Open this file and give it the below contents:

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.1'
pod 'GoogleMaps'

Save this file and then open a terminal within the directory containing the Podfile.

in this directory run the below command:

pod install

This will install the Google Map SDK for us. Once complete, close Xcode and then open (double-click) your project’s .xcworkspace file to launch Xcode. From this time onwards, you must use the .xcworkspace file to open the project.

Get API Key

Getting the key is pretty straight forward, but best described in the official guide from Google. Check out the details HERE

Using Map

Below is the most simple map set up we can do (future posts will look at more advanced features).

#import "YourViewController.h"
@import GoogleMaps;

@implementation YourViewController {
  GMSMapView *mapView_;
}

- (void)viewDidLoad {
 
  GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-33.86
                                                          longitude:151.20
                                                               zoom:6];
  mapView_ = [GMSMapView mapWithFrame:CGRectZero camera:camera];
  self.view = mapView_;
}

@end

So we import the GoogleMaps library, then we create a GMSMapView object. This allows us to create a view within the ViewController that will display the Map on the Screen.

Then, we create a CameraPosition object. Initialising the Map with this will make the map display at that location and zoom level.

And thats it the most simple Google Map created.

As always if you have any questions leave them below.

Leave a Reply

Your email address will not be published. Required fields are marked *

Tags: ,

Adding custom Markers to Google Map

Zachary Powell - 17/12/2015

At this point, we have quite a nice little Google map application and we can now get the users location and display it on a Google map (see HERE if you have not caught up yet).

Now this works well, but what if we want to display extra data on the map? Perhaps there are locations that we want to highlight to the user. Below we will explore how we can add custom markers to the map and what can be done with them.

Plot marker with default pin

The most basic marker can be added with just a few lines of code.

LatLng position = new LatLng(53.779558, -4.042969);
MarkerOptions markerOption = new MarkerOptions().position(position);

markerOption.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE));
markerOption.title("Marker with default Pin");
mMap.addMarker(markerOption);

First we create the LatLng for the position we want to put the pin in (this is just a random point near England). We can then use the MarkerOptions object to set a few custom options. For the most simple, we can leave this with just the initial code, but we can also change many settings for the Marker – See HERE.

Changing the Icon, we can use the default section of marker colours.

We can also set the title. This is displayed when the user clicks the marker like below.

Screenshot_20151214-114449  Screenshot_20151214-114454

Plot marker with custom image

A great way to customise these pins, is to use our own image for the pin. For example:

private void plotMarkerWithCustomImage(){
    LatLng position = new LatLng(53.784426, -1.735840);
    MarkerOptions markerOption = new MarkerOptions().position(position);

    markerOption.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_launcher));

    markerOption.title("Marker with custom image");
    mMap.addMarker(markerOption);
}

Gives us the below:

Screenshot_20151214-120522Screenshot_20151214-120526

Plot marker with canvas

Another more complex method, is to use a canvas to display other information in the marker itself. For example:

private void plotMarkerWithCanvas(){
   LatLng position = new LatLng(53.209322, -3.405762);
   MarkerOptions markerOption = new MarkerOptions().position(position);

   Bitmap.Config conf = Bitmap.Config.ARGB_8888;
   Bitmap bmp = Bitmap.createBitmap(80, 80, conf);
   Canvas canvas1 = new Canvas(bmp);

   Paint color = new Paint();
   color.setTextSize(35);
   color.setColor(Color.BLACK);

   canvas1.drawBitmap(BitmapFactory.decodeResource(getResources(),
                R.drawable.ic_launcher), 0,0, color);

   canvas1.drawText("User Name!", 30, 40, color);

   markerOption.icon(BitmapDescriptorFactory.fromBitmap(bmp));

   markerOption.title("Marker with canvas");
   mMap.addMarker(markerOption);
}

Here we create a new Bitmap image and a Canvas on that image. We can then create any custom Bitmap that we want. For example, adding text to the image, or loading another bitmap onto it.

Once created we can use this to set the icon. The above would give us:

Screenshot_20151214-121324 Screenshot_20151214-121328

For the complete example, as always check out the github project HERE. If you have any comments or questions please ask below

 

Leave a Reply

Your email address will not be published. Required fields are marked *

Tags: , ,

Display Users current location on Google Map

Zachary Powell - 14/12/2015

Before starting this guide, check out the Google Map example HERE if you have not already read it.

Now that we have a working Map, there is a range of examples we can cover. One that is very widely required, is displaying the users current location. When using a map, it is often the case that the user will want to be able to see where they currently are. Below we will explore what needs to be added to our Google Map example to display the users current location and update the marker as the user moves.

Manifest Changes

First we need to set some permissions in the Android manifest of our project. In Android studio, open the Manifest folder and open AndroidManifest.xml

We then need to add the below lines to manifest our side of the application tag.

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />

If you are using my Google Map Example code your manifest should then look like this:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.zpwebsites.basicgooglemapexample">

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />


    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        
        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="@string/google_maps_key" />

        <activity
            android:name=".MapsActivity"
            android:label="@string/title_activity_maps">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

These permissions are required to get the users current location. We want the file location when available, but if there is no GPS connection, the coarse location can be used to get a rough user location based on a mobile signal.

Centre Map on Current Location

We are going to create a method called centerMapOnMyLocation(). This will be called once the map is loaded and will grab the users current location using GPS if available. The complete method:

private void centerMapOnMyLocation() {
        LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        Criteria criteria = new Criteria();

        Location location = null;

        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {

            location = locationManager.getLastKnownLocation(locationManager.getBestProvider(criteria, false));
        }

        if (location != null)
        {
            Long = location.getLongitude();
            Lat = location.getLatitude();
            mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(
                    new LatLng(location.getLatitude(), location.getLongitude()), 13));

            CameraPosition cameraPosition = new CameraPosition.Builder()
                    .target(new LatLng(location.getLatitude(), location.getLongitude()))      // Sets the center of the map to location user
                    .zoom(17)                   // Sets the zoom
                    .bearing(0)                // Sets the orientation of the camera to east
                    .tilt(40)                   // Sets the tilt of the camera to 30 degrees
                    .build();                   // Creates a CameraPosition from the builder
            mMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
        }else{
            mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(53.779558, -4.042969), 5.5f));
            CharSequence text = "Sorry, we where unable to get your location, please check your GPS";
            int duration = Toast.LENGTH_LONG;
            Toast.makeText(this.getBaseContext(), text, duration).show();
        }
    }

First we set up a couple of variables which will be used within the method.

LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
Location location = null;

The LocationManager will be used to get the current location from the system. This handles querying the GPS for the location. The Location object will then be used to store the Location that is returned by the LocationManager.

if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
            location = locationManager.getLastKnownLocation(locationManager.getBestProvider(criteria, false));
        }

Next, as of Android API level 23 (Android version 6.0), we now have to check that the permissions we require have been accepted by the user. If they have been accepted, we can go ahead and use the LocationManager to call the .getLastKnownLocation(). This will return the last location from the system. If GPS is available, this will return the current location.

if (location != null)
        {
            Long = location.getLongitude();
            Lat = location.getLatitude();
           
            CameraPosition cameraPosition = new CameraPosition.Builder()
                    .target(new LatLng(Lat, Long))      // Sets the center of the map to location user
                    .zoom(17)                   // Sets the zoom
                    .bearing(0)                // Sets the orientation of the camera to east
                    .tilt(40)                   // Sets the tilt of the camera to 30 degrees
                    .build();                   // Creates a CameraPosition from the builder
            mMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
        }

If the location has been returned, we can then get the locations longitude and latitude using the getter methods.  Once we have the location in the form of co-ordinates, we build a CameraPosition object, setting the target to the users position and setting up other camera settings, zoom level, bearing and tilt.

Finally, by passing this CameraPosition object to the animateCamera() method of the Google map object, we can move the maps view to centre on the users location.

else{
            mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(53.779558, -4.042969), 5.5f));
            CharSequence text = "Sorry, we where unable to get your location, please check your GPS";
            int duration = Toast.LENGTH_LONG;
            Toast.makeText(this.getBaseContext(), text, duration).show();
        }

We then use an else statement to cover if the location was not returned, either because the user declined the permissions or for some reason, theLocationManager failed to return the location object. In this else statement, we just move the camera to a pre-defined location and display a Toast message to let the user know we failed to get their position.

Then we need to edit our onMapRead() function to call our centerMapOnMyLocation() method, once our map is ready to use. We also call setMyLocationEnabled(true) so that the map will display a marker at the users location.

public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;
        mMap.setMyLocationEnabled(true);
        centerMapOnMyLocation();
}

Using LocationListener to update the users location

At this point, we have an app that centres to the users location on starting up the map, but if the user then moves it will not update the map. This is where we need to set up a LocationListener to monitor for location changes and update the map accordingly.

LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
        LocationListener locationListener = new LocationListener() {
            public void onLocationChanged(Location location) {
                Long = location.getLongitude();
                Lat = location.getLatitude();
            }

            public void onStatusChanged(String provider, int status, Bundle extras) {
            }

            public void onProviderEnabled(String provider) {
            }

            public void onProviderDisabled(String provider) {
            }
        };

        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
            locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
        }

Within the onCreate() method we add the above code. This sets up a LocationManager and a LocationListener. The LocationManager is the same as before using the Location service, while the LocationListener sets up the code to be run when a location changes. Within the onLocationChanged() method, we get the new Longitude and Latitude and update our Long and Lat variables.

Then, we need to run the same check to make sure the user has accepted our permissions again. If they have, we can then go ahead and register the LocationListener with the LocationManager. This allows the onLocationChanged() code to be run when the users location changes.

Complete Example

Once we have added all the above code, the app can not be run and display the current users location.

If you would like to check out the complete applications code, you can find it HERE. This code will be updated in the future to hold all example code for Google Maps.

As always if you have any questions please comment below.

Leave a Reply

Your email address will not be published. Required fields are marked *

Tags: , , ,

Using Google Maps within Android app

Zachary Powell - 11/12/2015

Don’t worry, there is a pattern to my posts, honestly! All will become clear further down the line.

Google has a range of great APIs and extras, and one that comes in pretty handy from time to time, is the Google Maps API. This allows you to display a custom Google Map within your own application. This is useful if you have any location based information you might want to display *cough* buildings *cough*

Google actually has a pretty good guide on the subject over at https://developers.google.com/maps/documentation/android-api/start. Do check it out, Though, I will cover all your need below and its worth a read for extra tips and hints!

Set up

For this (and all Android) guide we will be using Android studio. It is now the only supported IDE by Google and has come a long way in the few years its been in development. If you are not already using it, download and install Android Studio now.

Next, (again if you have not already) make sure to install the Google Play services package into the Android SDK, details of this are to be found HERE.

Creating Activity that displays map

Screen Shot 2015-12-08 at 13.43.43

The easiest way to create a new activity that displays a Google Map is by using Android studios built in “New Activity” menu. As long as you have the above set up correctly, you will see in this list the option for a “Google Map Activity”. This will create all the files needed and handle the basic set up. Now that is all well and good, but lets actually have a look at what is created and what the code that has been generated does.

MapsActivity.java

The activity file that handles the actual code, the generated code:

public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {

    private GoogleMap mMap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_maps);
        // Obtain the SupportMapFragment and get notified when the map is ready to be used.
        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);
    }
    
    @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;

        LatLng sydney = new LatLng(-34, 151);
        mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney"));
        mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));
    }
}

As you can see, the code required is actually pretty minimal to get a map displayed. The main code that is important is within the onCreate() method. Here we set up the MapFragment view and then fire off the fragments getMapAsync() method. This handles the background code to actually connect to the Google Map API and load a new map.

The onMapReady() method then takes care of any post processing we want to do on the Map. Here we set up the private GoogleMap variable to allow us to manipulate the Map from other methods within our activity.

We then set up an example LatLng object. We are using Sydney, but of course it could be any location in the world.

LatLng sydney = new LatLng(-34, 151);

Then we add a basic marker to the map at the created location.

mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney"));

And finally we move the screen to focus to that location.

        mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));

activity_map.xml

This is the fragment view for the map, again very simple.

<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:map="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/map"
    android:name="com.google.android.gms.maps.SupportMapFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.zpwebsites.basicgooglemapexample.MapsActivity" />

Nothing special about this as we insert the map into the fragment from code.

google_map_api.xml

<resources>
    <string name="google_maps_key" templateMergeStrategy="preserve" translatable="false">YOUR_KEY_HERE</string>
</resources>

This is the final file created. Here is where we need to insert out API Key from Google to allow us to talk to the Google Map server and actually display a map.

Getting API Key

So now we have a very basic app ready to run, but if you try to run the app as it is, the map will not load. We need to get a API Key from Google to allow us to display the map.

To get this set up, follow the steps in the Google Guide HERE

Complete Example

Once you have added the key to your google_map_api.xml, you should now be able to run the application and see a map.

If you would like to checkout the complete applications code you can find it HERE. This code will be updated in the future to hold all example code for Google Maps.

As always if you have any questions please comment below.

Leave a Reply

Your email address will not be published. Required fields are marked *

Tags: , ,

“ Any fool can write code that a computer can understand. Good programmers write code that humans can understand. ”

-Martin Fowler