-
Notifications
You must be signed in to change notification settings - Fork 9.7k
[google_maps_flutter_platform_interface] add custom tile support #3418
Changes from 1 commit
f34a94a
8313237
c88447d
9322f98
fd0b1e3
38d4d5a
52dba31
c2e2a3f
a5a6dca
5cded00
375164d
8ff2313
0469f42
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
format doc updates compelete tests
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,7 @@ | ||
| ## 1.2.0 | ||
|
|
||
| * Add TileOverlay support. | ||
|
|
||
| ## 1.1.0 | ||
|
|
||
| * Add support for holes in Polygons. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -33,6 +33,10 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { | |
| return _channels[mapId]; | ||
| } | ||
|
|
||
| // Keep a collection of id -> GetTileCallback | ||
| // Every method call passes the int mapId | ||
| final Map<int, MapGetTileCallback> _getTileCallbacks = {}; | ||
|
|
||
| /// Initializes the platform interface with [id]. | ||
| /// | ||
| /// This method is called when the plugin is first initialized. | ||
|
|
@@ -184,6 +188,15 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { | |
| LatLng.fromJson(call.arguments['position']), | ||
| )); | ||
| break; | ||
| case 'tileOverlay#getTile': | ||
| final getTileCallback = _getTileCallbacks[mapId]; | ||
| final Tile tile = await getTileCallback( | ||
|
||
| call.arguments['tileOverlayId'], | ||
| call.arguments['x'], | ||
| call.arguments['y'], | ||
| call.arguments['zoom'], | ||
| ); | ||
| return tile.toJson(); | ||
| default: | ||
| throw MissingPluginException(); | ||
| } | ||
|
|
@@ -281,6 +294,40 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { | |
| ); | ||
| } | ||
|
|
||
| /// Updates tile overlay configuration. | ||
| /// | ||
| /// Change listeners are notified once the update has been made on the | ||
| /// platform side. | ||
| /// | ||
| /// The returned [Future] completes after listeners have been notified. | ||
| @override | ||
| Future<void> updateTileOverlays( | ||
| TileOverlayUpdates tileOverlayUpdates, { | ||
| @required int mapId, | ||
| }) { | ||
| assert(tileOverlayUpdates != null); | ||
|
||
| return channel(mapId).invokeMethod<void>( | ||
| 'tileOverlays#update', | ||
| tileOverlayUpdates.toJson(), | ||
| ); | ||
| } | ||
|
|
||
| /// Clears the tile cache so that all tiles will be requested again from the | ||
| /// [TileProvider]. The current tiles from this tile overlay will also be | ||
| /// cleared from the map after calling this method. The API maintains a small | ||
| /// in-memory cache of tiles. If you want to cache tiles for longer, you | ||
| /// should implement an on-disk cache. | ||
| @override | ||
| Future<void> clearTileCache( | ||
| TileOverlayId tileOverlayId, { | ||
| @required int mapId, | ||
| }) { | ||
| return channel(mapId) | ||
| .invokeMethod<void>('tileOverlays#clearTileCache', <String, dynamic>{ | ||
| 'tileOverlayId': tileOverlayId.value, | ||
| }); | ||
| } | ||
|
|
||
| /// Starts an animated change of the map camera position. | ||
| /// | ||
| /// The returned [Future] completes after the change has been started on the | ||
|
|
@@ -451,6 +498,16 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { | |
| return channel(mapId).invokeMethod<Uint8List>('map#takeSnapshot'); | ||
| } | ||
|
|
||
| /// Sets the `MapGetTileCallback` with mapId. | ||
| /// | ||
| /// `mapId` and `callback` must not be null. | ||
| @override | ||
| void setGetTileCallback( | ||
| {@required int mapId, @required MapGetTileCallback callback}) { | ||
| assert(mapId != null && callback != null); | ||
| _getTileCallbacks[mapId] = callback; | ||
| } | ||
|
|
||
| /// This method builds the appropriate platform view where the map | ||
| /// can be rendered. | ||
| /// The `mapId` is passed as a parameter from the framework on the | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,6 +15,10 @@ import 'package:google_maps_flutter_platform_interface/src/method_channel/method | |
| import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; | ||
| import 'package:plugin_platform_interface/plugin_platform_interface.dart'; | ||
|
|
||
| /// Callback method for when a [Tile] is requested from a [TileProvider]. | ||
| typedef Future<Tile> MapGetTileCallback( | ||
|
||
| TileOverlayId tileOverlayId, int x, int y, int zoom); | ||
|
|
||
| /// The interface that platform-specific implementations of `google_maps_flutter` must extend. | ||
| /// | ||
| /// Avoid `implements` of this interface. Using `implements` makes adding any new | ||
|
|
@@ -115,6 +119,31 @@ abstract class GoogleMapsFlutterPlatform extends PlatformInterface { | |
| throw UnimplementedError('updateCircles() has not been implemented.'); | ||
| } | ||
|
|
||
| /// Updates tile overlay configuration. | ||
| /// | ||
| /// Change listeners are notified once the update has been made on the | ||
| /// platform side. | ||
| /// | ||
| /// The returned [Future] completes after listeners have been notified. | ||
| Future<void> updateTileOverlays( | ||
| TileOverlayUpdates tileOverlayUpdates, { | ||
| @required int mapId, | ||
| }) { | ||
| throw UnimplementedError('updateTileOverlays() has not been implemented.'); | ||
| } | ||
|
|
||
| /// Clears the tile cache so that all tiles will be requested again from the | ||
cyanglaz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| /// [TileProvider]. The current tiles from this tile overlay will also be | ||
| /// cleared from the map after calling this method. The API maintains a small | ||
|
||
| /// in-memory cache of tiles. If you want to cache tiles for longer, you | ||
| /// should implement an on-disk cache. | ||
| Future<void> clearTileCache( | ||
| TileOverlayId tileOverlayId, { | ||
| @required int mapId, | ||
| }) { | ||
| throw UnimplementedError('clearTileCache() has not been implemented.'); | ||
| } | ||
|
|
||
| /// Starts an animated change of the map camera position. | ||
| /// | ||
| /// The returned [Future] completes after the change has been started on the | ||
|
|
@@ -246,6 +275,12 @@ abstract class GoogleMapsFlutterPlatform extends PlatformInterface { | |
| throw UnimplementedError('takeSnapshot() has not been implemented.'); | ||
| } | ||
|
|
||
| /// Set the [MapGetTileCallback] for the map, which will be called | ||
| /// when a [Tile] is requested for an added [TileProvider]. | ||
| void setGetTileCallback({@required int mapId, MapGetTileCallback callback}) { | ||
|
||
| throw UnimplementedError('onGetTile() has not been implemented.'); | ||
| } | ||
|
|
||
| // The following are the 11 possible streams of data from the native side | ||
| // into the plugin | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| // Copyright 2018 The Chromium Authors. All rights reserved. | ||
| // Use of this source code is governed by a BSD-style license that can be | ||
| // found in the LICENSE file. | ||
|
|
||
| import 'dart:typed_data'; | ||
| import 'package:meta/meta.dart' show immutable; | ||
|
|
||
| /// Contains information about a Tile that is returned by a [TileProvider]. | ||
| @immutable | ||
| class Tile { | ||
| /// Creates an immutable representation of a [Tile] to draw by [TileProvider]. | ||
| const Tile(this.width, this.height, this.data); | ||
|
|
||
| /// The width of the image encoded by data in pixels. | ||
cyanglaz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| final int width; | ||
|
|
||
| /// The height of the image encoded by data in pixels. | ||
| final int height; | ||
|
|
||
| /// A byte array containing the image data. | ||
cyanglaz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| final Uint8List data; | ||
|
|
||
| /// Converts this object to JSON. | ||
| dynamic toJson() { | ||
cyanglaz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| final Map<String, dynamic> json = <String, dynamic>{}; | ||
|
|
||
| void addIfPresent(String fieldName, dynamic value) { | ||
| if (value != null) { | ||
| json[fieldName] = value; | ||
| } | ||
| } | ||
|
|
||
| addIfPresent('width', width); | ||
| addIfPresent('height', height); | ||
| addIfPresent('data', data); | ||
|
|
||
| return json; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,159 @@ | ||
| // Copyright 2018 The Chromium Authors. All rights reserved. | ||
| // Use of this source code is governed by a BSD-style license that can be | ||
| // found in the LICENSE file. | ||
|
|
||
| import 'types.dart'; | ||
| import 'package:meta/meta.dart' show immutable, required; | ||
|
|
||
| /// Uniquely identifies a [TileOverlay] among [GoogleMap] tile overlays. | ||
| /// | ||
| /// This does not have to be globally unique, only unique among the list. | ||
cyanglaz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| @immutable | ||
| class TileOverlayId { | ||
| /// Creates an immutable identifier for a [TileOverlay]. | ||
| TileOverlayId(this.value) : assert(value != null); | ||
|
|
||
| /// value of the [TileOverlayId]. | ||
| final String value; | ||
cyanglaz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| @override | ||
| bool operator ==(Object other) { | ||
| if (identical(this, other)) return true; | ||
| if (other.runtimeType != runtimeType) return false; | ||
| final TileOverlayId typedOther = other; | ||
cyanglaz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| return value == typedOther.value; | ||
| } | ||
|
|
||
| @override | ||
| int get hashCode => value.hashCode; | ||
|
|
||
| @override | ||
| String toString() { | ||
| return 'TileOverlay{value: $value}'; | ||
|
||
| } | ||
| } | ||
|
|
||
| /// A Tile Overlay is a set of images which are displayed on top of the base map tiles. | ||
cyanglaz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| /// These tiles may be transparent, allowing you to add features to existing maps. | ||
| /// | ||
| /// Tile Coordinates | ||
cyanglaz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| /// | ||
| /// Note that the world is projected using the Mercator projection | ||
| /// (see [Wikipedia](https://en.wikipedia.org/wiki/Mercator_projection)) with the left (west) side | ||
| /// of the map corresponding to -180 degrees of longitude and the right (east) side of the map | ||
| /// corresponding to 180 degrees of longitude. To make the map square, the top (north) side of the | ||
| /// map corresponds to 85.0511 degrees of latitude and the bottom (south) side of the map | ||
| /// corresponds to -85.0511 degrees of latitude. Areas outside this latitude range are not rendered. | ||
| /// | ||
| /// At each zoom level, the map is divided into tiles and only the tiles that overlap the screen are | ||
| /// downloaded and rendered. Each tile is square and the map is divided into tiles as follows: | ||
| /// | ||
| /// * At zoom level 0, one tile represents the entire world. The coordinates of that tile are | ||
| /// (x, y) = (0, 0). | ||
| /// * At zoom level 1, the world is divided into 4 tiles arranged in a 2 x 2 grid. | ||
| /// * ... | ||
| /// * At zoom level N, the world is divided into 4N tiles arranged in a 2N x 2N grid. | ||
| /// | ||
| /// Note that the minimum zoom level that the camera supports (which can depend on various factors) | ||
| /// is GoogleMap.getMinZoomLevel and the maximum zoom level is GoogleMap.getMaxZoomLevel. | ||
| /// | ||
| /// The coordinates of the tiles are measured from the top left (northwest) corner of the map. | ||
| /// At zoom level N, the x values of the tile coordinates range from 0 to 2N - 1 and increase from | ||
| /// west to east and the y values range from 0 to 2N - 1 and increase from north to south. | ||
| /// | ||
| class TileOverlay { | ||
| /// Creates an immutable representation of a [TileOverlay] to draw on [GoogleMap]. | ||
| const TileOverlay({ | ||
| @required this.tileOverlayId, | ||
| this.fadeIn = true, | ||
| this.tileProvider, | ||
| this.transparency = 0.0, | ||
| this.zIndex, | ||
| this.visible = true, | ||
| this.tileSize = 256, | ||
| }) : assert(transparency >= 0.0 && transparency <= 1.0); | ||
|
|
||
| /// Uniquely identifies a [TileOverlay]. | ||
| final TileOverlayId tileOverlayId; | ||
|
|
||
| /// Whether the tiles should fade in. The default is true. | ||
| final bool fadeIn; | ||
|
|
||
| /// The tile provider to use for this tile overlay. | ||
| final TileProvider tileProvider; | ||
|
|
||
| /// The transparency of the tile overlay. The default transparency is 0 (opaque). | ||
| final double transparency; | ||
|
|
||
| /// The tile overlay's zIndex, i.e., the order in which it will be drawn where | ||
| /// overlays with larger values are drawn above those with lower values | ||
| final int zIndex; | ||
|
|
||
| /// The visibility for the tile overlay. The default visibility is true. | ||
| final bool visible; | ||
|
|
||
| /// Specifies the number of pixels (not points) that the returned tile images will prefer | ||
cyanglaz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| /// to display as. iOS only. | ||
| /// | ||
| /// Defaults to 256, which is the traditional size of Google Maps tiles. | ||
| /// As an example, an application developer may wish to provide retina tiles (512 pixel edge length) | ||
| /// on retina devices, to keep the same number of tiles per view as the default value of 256 | ||
| /// would give on a non-retina device. | ||
| final int tileSize; | ||
|
|
||
| /// Creates a new [Polygon] object whose values are the same as this instance, | ||
cyanglaz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| /// unless overwritten by the specified parameters. | ||
| TileOverlay copyWith({ | ||
| TileOverlayId tileOverlayId, | ||
| bool fadeInParam, | ||
| double transparencyParam, | ||
| int zIndexParam, | ||
| bool visibleParam, | ||
| int tileSizeParam, | ||
| }) { | ||
| return TileOverlay( | ||
| tileOverlayId: tileOverlayId, | ||
| fadeIn: fadeInParam ?? fadeIn, | ||
| transparency: transparencyParam ?? transparency, | ||
| zIndex: zIndexParam ?? zIndex, | ||
| visible: visibleParam ?? visible, | ||
| tileSize: tileSizeParam ?? tileSize, | ||
| ); | ||
| } | ||
|
|
||
| /// Converts this object to JSON. | ||
| dynamic toJson() { | ||
cyanglaz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| final Map<String, dynamic> json = <String, dynamic>{}; | ||
|
|
||
| void addIfPresent(String fieldName, dynamic value) { | ||
| if (value != null) { | ||
| json[fieldName] = value; | ||
| } | ||
| } | ||
|
|
||
| addIfPresent('tileOverlayId', tileOverlayId.value); | ||
| addIfPresent('fadeIn', fadeIn); | ||
| addIfPresent('transparency', transparency); | ||
| addIfPresent('zIndex', zIndex); | ||
| addIfPresent('visible', visible); | ||
| addIfPresent('tileSize', tileSize); | ||
|
|
||
| return json; | ||
| } | ||
|
|
||
| @override | ||
| bool operator ==(Object other) { | ||
| if (identical(this, other)) return true; | ||
| if (other.runtimeType != runtimeType) return false; | ||
| final TileOverlay typedOther = other; | ||
cyanglaz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| return tileOverlayId == typedOther.tileOverlayId && | ||
| fadeIn == typedOther.fadeIn && | ||
| transparency == typedOther.transparency && | ||
| zIndex == typedOther.zIndex && | ||
| visible == typedOther.visible && | ||
| tileSize == typedOther.tileSize; | ||
| } | ||
|
|
||
| @override | ||
| int get hashCode => tileOverlayId.hashCode; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: specify type
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done