Tile Layers

Select platform: Android iOS JavaScript

You can add images on top of your map as a Tile Layer. Tile Layers are placed overtop of a map tile at a specific zoom level. With enough tiles, you can supplement Google's map data for the entire map, at multiple zoom levels.

Introduction

Tile layers (sometimes referred to as Tile Overlays) allow you to superimpose images on top of Google's base map tiles. This is an excellent way to add data - such as points of interest or traffic information - and local imagery to your app. When combined with the kGMSTypeNone map type, tile layers effectively let you replace Google's base map data with your own.

Tile layers are useful when you wish to add extensive imagery, typically covering large geographical areas, to the map. By contrast, ground overlays are useful when you wish to fix a single image at one point on the map.

Tile coordinates

The Maps API breaks up imagery at each zoom level into a set of square map tiles, which are arranged in an ordered grid. When a map scrolls to a new location, or to a new zoom level, the Maps API determines which tiles are needed, and translates that into a set of tiles to retrieve.

For Google's implementation of the Mercator projection, the tile with coordinate (0,0) is always at the northwest corner of the map, with x values increasing from west to east and y values increasing from north to south. Tiles are indexed using x,y coordinates from that origin. For example, at zoom level 2, when the earth is divided up into 16 tiles, each tile can be referenced by a unique x,y pair:

Map of the world divided into four rows and four columns of tiles.

Each map tile is a 256x256 point square. At zoom level 0, the entire world is rendered in a single tile. Each zoom level increases the magnification by a factor of two. So, at zoom level 1 the map will be rendered as a 2x2 grid of tiles, or a 4x4 grid at zoom level 2, a 8x8 grid at zoom level 3, and so on. If you are creating images for a tile layer, you will need to create a new 256x256 point image for each tile at each zoom level that you wish to support.

Add a Tile Layer

  1. Instantiate a GMSURLTileLayer object, or a custom subclass of GMSTileLayer or GMSSyncTileLayer.
  2. Optionally modify the zIndex property to adjust its position in relation to other tile layers.
  3. Assign the GMSTileLayer object to the map by setting its map property.

The Maps SDK for iOS provides three classes that can be used to implement a tile layer. With each class, you will need to define how to fetch the correct map tile for a given set of {x,y,zoom} coordinates. The available options are:

  • Subclass GMSSyncTileLayer, providing the implementation of tileForX:y:zoom that returns UIImage instances.
  • Subclass GMSTileLayer, providing the implementation of the asynchronous method requestTileForX:y:zoom that later calls back with a tile image.
  • Use the existing class, GMSURLTileLayer, to fetch tiles automatically from URLs, providing the GMSTileURLConstructor block. GMSURLTileLayer is a concrete class that cannot be subclassed.

In the case of subclassing GMSSyncTileLayer or GMSTileLayer, providing a nil tile result will tell the Maps SDK for iOS that data is currently unavailable but that it may be available in the future. Alternatively, return kGMSTileLayerNoTile to indicate that there is no tile at this location.

For GMSURLTileLayer, returning nil from the GMSTileURLConstructor will indicate that there is no tile at this location.

Use GMSURLTileLayer to fetch tiles from URLs

The GMSURLTileLayer does not require subclassing, but you will have to implement the GMSTileURLConstructor block. The below code shows how to use GMSURLTileLayer to display the floor plan of a multistory building.

Swift

let floor = 1

// Implement GMSTileURLConstructor
// Returns a Tile based on the x,y,zoom coordinates, and the requested floor
let urls: GMSTileURLConstructor = { (x, y, zoom) in
  let url = "https://www.example.com/floorplans/L\(floor)_\(zoom)_\(x)_\(y).png"
  return URL(string: url)
}

// Create the GMSTileLayer
let layer = GMSURLTileLayer(urlConstructor: urls)

// Display on the map at a specific zIndex
layer.zIndex = 100
layer.map = mapView
      

Objective-C

NSInteger floor = 1;

// Create the GMSTileLayer
GMSURLTileLayer *layer = [GMSURLTileLayer tileLayerWithURLConstructor:^NSURL * _Nullable(NSUInteger x, NSUInteger y, NSUInteger zoom) {
  NSString *url = [NSString stringWithFormat:@"https://www.example.com/floorplans/L%ld_%lu_%lu_%lu.png",
                   (long)floor, (unsigned long)zoom, (unsigned long)x, (unsigned long)y];
  return [NSURL URLWithString:url];
}];

// Display on the map at a specific zIndex
layer.zIndex = 100;
layer.map = mapView;
      

Subclass GMSSyncTileLayer to serve tiles as a UIImage

The GMSSyncTileLayer and GMSTileLayer are abstract classes designed to be subclassed. You can use these classes to serve tiles as UIImage's. The below example shows how to render a custom image over some of the tiles on the map by subclassing GMSSyncTileLayer.

Swift

class TestTileLayer: GMSSyncTileLayer {
  override func tileFor(x: UInt, y: UInt, zoom: UInt) -> UIImage? {
    // On every odd tile, render an image.
    if (x % 2 == 1) {
      return UIImage(named: "australia")
    } else {
      return kGMSTileLayerNoTile
    }
  }
}

      

Objective-C

@interface TestTileLayer : GMSSyncTileLayer
@end

@implementation TestTileLayer

- (UIImage *)tileForX:(NSUInteger)x y:(NSUInteger)y zoom:(NSUInteger)zoom {
  // On every odd tile, render an image.
  if (x % 2 == 1) {
    return [UIImage imageNamed:@"australia"];
  } else {
    return kGMSTileLayerNoTile;
  }
}

@end
      

To add the layer to your map, instantiate the object and set its map property.

Swift

let layer = TestTileLayer()
layer.map = mapView
      

Objective-C

GMSTileLayer *layer = [[TestTileLayer alloc] init];
layer.map = mapView;
      

High DPI Tiles for Retina devices

You can use high DPI images with either GMSSyncTileLayer or GMSURLTileLayer by setting the tileSize to 512. The tileSize property indicates the number of pixels that the returned tile images will prefer to display as; this defaults to 256 — the dimension of a Google Maps tile on a non-Retina device.

If you are displaying normal DPI tiles on a high DPI device you can scale the images up by setting tileSize to 512. Note that upscaling images may reduce image quality, especially for fine lines or text. For best results, match the tileSize and image DPI to the display. Maps shown on a Retina device will look their best when displaying high DPI images with a tileSize of 512; while maps shown on a non-Retina device will look great with normal images and the default tileSize of 256.

Clearing stale tiles

If the tiles provided by the layer become 'stale', then the method clearTileCache should be called on the layer to force a refresh. This will cause all of the tiles on this layer to be reloaded.

Swift

layer.clearTileCache()
      

Objective-C

[layer clearTileCache];