diff --git a/CHANGELOG.md b/CHANGELOG.md index 4793ed145..e747a551f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,54 @@ # Change Log + +## 0.22.1 (November 8, 2018) +* Common: [#2548](https://github.com/react-community/react-native-maps/pull/2548) Moved `babel-plugin-module-resolver` and `babel-preset-react-native` from dependencies to devDependencies +* Android: [#2555](https://github.com/react-community/react-native-maps/pull/2555) Fixed [#2507](https://github.com/react-community/react-native-maps/issues/2507) +* Android: [#2545](https://github.com/react-community/react-native-maps/pull/2545) Fixed “The specified child already has a parent” +* Docs: [#2541](https://github.com/react-community/react-native-maps/pull/2541) Improve installation docs +* Docs: [#2550](https://github.com/react-community/react-native-maps/pull/2550) Specify how to use Google Maps +* Docs: [#2559](https://github.com/react-community/react-native-maps/pull/2559) Clarify cacheEnabled is apple maps only + +## 0.22.0 (October 11, 2018) +* Common: [#2049](https://github.com/react-community/react-native-maps/pull/2049) Added `animateToNavigation` method to `MapView` +* Common: [#2207](https://github.com/react-community/react-native-maps/pull/2207), [#2232](https://github.com/react-community/react-native-maps/pull/2232) Added `timestamp` property to `onUserLocationChange` event callback +* Common: [#2479](https://github.com/react-community/react-native-maps/pull/2479), [#2524](https://github.com/react-community/react-native-maps/pull/2524) Added `edgePadding` to `fitToSuppliedMarkers` function +* Common: [#2448](https://github.com/react-community/react-native-maps/pull/2448) Added custom indoor picker level +* Common: [#2238](https://github.com/react-community/react-native-maps/pull/2238) Support the `asset://` scheme for images +* Common: [#2136](https://github.com/react-community/react-native-maps/pull/2136), [#2184](https://github.com/react-community/react-native-maps/pull/2184) Modifications/Enhancements to MapView.UrlTile +* Common: [#2039](https://github.com/react-community/react-native-maps/pull/2039) Fix for `pointForCoordinate` and `coordinateForPoint` +* Common: [#2217](https://github.com/react-community/react-native-maps/pull/2217) Using `ColorPropType` to validate all color props more accurately +* iOS: [#2396](https://github.com/react-community/react-native-maps/pull/2396) Added installation for iOS via `react-native link` +* iOS: [#2243](https://github.com/react-community/react-native-maps/pull/2243) Added support of `lineDashPattern` polyline props to iOS Google Maps +* iOS: [#2149](https://github.com/react-community/react-native-maps/pull/2149) Added `paddingAdjustmentBehavior` for Google Maps on iOS +* iOS: [#2231](https://github.com/react-community/react-native-maps/pull/2231) Prefix DummyView class +* iOS: [#2229](https://github.com/react-community/react-native-maps/pull/2229) Use global imports for new Pods dependencies in AIRGoogleMap +* iOS: [#2248](https://github.com/react-community/react-native-maps/pull/2248) Make tiles display at the same physical size regardless of pixel density on iOS devices +* iOS: [#2306](https://github.com/react-community/react-native-maps/pull/2306) Prefix or eliminate globals in AIRMapMarker +* iOS: [#2351](https://github.com/react-community/react-native-maps/pull/2351) Added support for `calloutAnchor` with Google Maps on iOS +* iOS: [#2501](https://github.com/react-community/react-native-maps/pull/2501) Fixed issue that app crashes after trigger Marker `onDragEnd` +* iOS: [#2359](https://github.com/react-community/react-native-maps/pull/2359) Fixed zIndex didn't work on map moving on iOS 11 +* iOS: [#2185](https://github.com/react-community/react-native-maps/pull/2185) Fixed Xcode warnings for format, pointer type, unused var +* iOS: [#2154](https://github.com/react-community/react-native-maps/pull/2154) Fixed CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF warnings +* iOS: [#2341](https://github.com/react-community/react-native-maps/pull/2341) Fixed warnings about `self` +* Android: [#2224](https://github.com/react-community/react-native-maps/pull/2224) Respect `tappable` prop on Android +* Android: [#2390](https://github.com/react-community/react-native-maps/pull/2390) Consider pixel density in coordinate<->point conversion +* Android: [#2477](https://github.com/react-community/react-native-maps/pull/2477), [#2487](https://github.com/react-community/react-native-maps/pull/2487) Implemented `tracksViewChanges` on Android +* Android: [#2478](https://github.com/react-community/react-native-maps/pull/2478) Let `onVisibilityChanged()` be called on children (mainly fixes `Image` issues) +* Android: [#2375](https://github.com/react-community/react-native-maps/pull/2375) Fixed `lineCap` of Polyline +* Android: [#2320](https://github.com/react-community/react-native-maps/pull/2320) Fixed custom marker updates on Android +* Android: [#2197](https://github.com/react-community/react-native-maps/pull/2197) Fixed overlay removal bug +* Android: [#2317](https://github.com/react-community/react-native-maps/pull/2317) Fixed disabling the toolbar and my location button +* Android: [#2472](https://github.com/react-community/react-native-maps/pull/2472) Fixed compilation error due to minSDK in manifest +* Android: [#2172](https://github.com/react-community/react-native-maps/pull/2172) Fixed crash for Android API level below 18 on isFromMockProvider +* Internal: [#2462](https://github.com/react-community/react-native-maps/pull/2462) Fixed packager script path in `pacakage.json` +* Internal: [#2480](https://github.com/react-community/react-native-maps/pull/2480) Fix peer dependencies +* TypeScript: [#2165](https://github.com/react-community/react-native-maps/pull/2165) Typings improvements & fixes +* Docs: [#2541](https://github.com/react-community/react-native-maps/pull/2541) Vastly improved installation guideline +* Docs: [#2171](https://github.com/react-community/react-native-maps/pull/2171) Add 'none' option to docs for `mapType` of `MapView` +* Docs: [#2174](https://github.com/react-community/react-native-maps/pull/2174) Add opacity to `Marker` API docs +* Docs: [#2181](https://github.com/react-community/react-native-maps/pull/2181), [#2219](https://github.com/react-community/react-native-maps/pull/2219) Add note about mandatory `NSLocationWhenInUseUsageDescription` +* Docs: [#2381](https://github.com/react-community/react-native-maps/pull/2381), [#2358](https://github.com/react-community/react-native-maps/pull/2358), [#2363](https://github.com/react-community/react-native-maps/pull/2363), [#2429](https://github.com/react-community/react-native-maps/pull/2429), [#2425](https://github.com/react-community/react-native-maps/pull/2425) Documentation improvements + ## 0.21.0 (March 31, 2018) * Common: [#2030](https://github.com/react-community/react-native-maps/pull/2030) Broadened peer-dependency support * Common: [#2035](https://github.com/react-community/react-native-maps/pull/2035), [#2113](https://github.com/react-community/react-native-maps/pull/2113), & [#2141](https://github.com/react-community/react-native-maps/pull/2141) Typescript improvements and fixes @@ -22,7 +72,6 @@ * Common: [hotfix PROVIDER_GOOGLE](https://github.com/react-community/react-native-maps/commit/cd868ea7b33a04c8bdd5e909cf134a133b2cb316) * iOS: [#2019](https://github.com/airbnb/react-native-maps/pull/2019) Exposing the maximumZ property to AIRMapUrlTile - ## 0.20.0 (February 9, 2018) * Common: [#1889](https://github.com/airbnb/react-native-maps/pull/1889) Fix for 'Animated.Region undefined constructor' in recent react-native version. * iOS: [#1853](https://github.com/airbnb/react-native-maps/pull/1853) Fixed onMapReady no longer getting called on iOS diff --git a/docs/installation.md b/docs/installation.md index 27c6818a7..4baa0bc30 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -1,30 +1,50 @@ # Installation -First, download the library from npm: +Install the library from npm: -``` +```sh npm install react-native-maps --save ``` +The library ships with platform native code that needs to be compiled +together with React Native. This requires you to configure your build +tools. + +The actual map implementation depends on the platform. On Android, one +has to use [Google +Maps](https://developers.google.com/maps/documentation/), which in turn +requires you to obtain an API key for the [Android +SDK](https://developers.google.com/maps/documentation/android-sdk/signup). -## Get a Google Maps API key +On iOS, one can choose between Google Maps or the native [Apple +Maps](https://developer.apple.com/documentation/mapkit/) implementation. -Go to https://developers.google.com/maps/documentation/ios-sdk/get-api-key and https://developers.google.com/maps/documentation/android-api/signup to get your keys for both iOS and Android. +When using Google Maps on iOS, you need to also register for the [iOS +SDK](https://developers.google.com/maps/documentation/ios-sdk/get-api-key) +and include the Google Maps library in your build. The native Apple Maps +based implementation works out-of-the-box and is therefore simpler to +use at the price of missing some of the features supported by the Google +Maps backend. -Make sure that Google Maps Android API and Google Maps SDK for iOS are enabled for the current project. -https://console.developers.google.com/apis/library/maps-android-backend.googleapis.com/ -https://console.developers.google.com/apis/library/maps-ios-backend.googleapis.com +## Build configuration on iOS -Without an API key the Google Maps map won't render anything. +### Using React Native Link +Run `react-native link react-native-maps` after which you should be able +to use this library on iOS. Note that by default this will use Apple +Maps and you will miss some of the features provided by Google (see the +instruction on manually enabling Google Maps below). -## iOS - CocoaPods +### Using CocoaPods -Setup your `Podfile` (found at `/ios/Podfile` as below, replace all references to `_YOUR_PROJECT_TARGET_` with your project target (it's the same as project name by default), and then run `pod install` while in the `ios` folder. +> If the CocoaPods package manager is new to you, please first review +> its [installation guide](https://guides.cocoapods.org/using/getting-started.html) -Please make sure to use `.xcworkspace`, not `.xcproject` after that. +Setup your `Podfile` (found at `ios/Podfile` as below, replacing all +references to `_YOUR_PROJECT_TARGET_` with your project target (it's the +same as project name by default). -~~~ +```ruby # Uncomment the next line to define a global platform for your project # platform :ios, '9.0' @@ -61,9 +81,9 @@ target '_YOUR_PROJECT_TARGET_' do # react-native-maps dependencies pod 'react-native-maps', path: rn_maps_path - pod 'react-native-google-maps', path: rn_maps_path # Remove this line if you don't want to support GoogleMaps on iOS - pod 'GoogleMaps' # Remove this line if you don't want to support GoogleMaps on iOS - pod 'Google-Maps-iOS-Utils' # Remove this line if you don't want to support GoogleMaps on iOS + # pod 'react-native-google-maps', path: rn_maps_path # Unomment this line if you want to support GoogleMaps on iOS + # pod 'GoogleMaps' # Uncomment this line if you want to support GoogleMaps on iOS + # pod 'Google-Maps-iOS-Utils' # Uncomment this line if you want to support GoogleMaps on iOS end post_install do |installer| @@ -78,23 +98,20 @@ post_install do |installer| end end end -~~~ - -## iOS - ReactNative Link +``` -Run `react-native link react-native-maps`. Note that by default this will use -Apple Maps and that the configuration of Google Maps will be more difficult. +Then run in the `ios` folder -Functionality that depends on `Google-Maps-iOS-Utils` has been disabled for this -configuration via runtime errors due to the fact that this framework is not -available for download as a pre-compiled binary. An exception will be raised if -you try to use the following features: +```sh +pod install +``` -- Making markers via KML files +and open the produced workspace file (`.xcworkspace`) in XCode to build your project. -## If you want to use Google maps +### Enabling Google Maps on iOS -Add to `ios/_YOUR_PROJECT_NAME_/AppDelegate.m: +If you want to enable Google Maps on iOS, obtain the Google API key and +edit your `AppDelegate.m` as follows: ```objc + #import @@ -108,35 +125,58 @@ Add to `ios/_YOUR_PROJECT_NAME_/AppDelegate.m: ... ``` -This should be the **first line** of the method. +The `[GMSServices provideAPIKey]` should be the **first call** of the method. -#### If you are not using CocoaPods +Then, do either of the following -If you installed via `react-native-link`, add the following to your -`package.json` and replace the `REPLACE_ME_RELATIVE_PATH_TO_GOOGLE_MAPS_INSTALL` -with the relative path from your project root to the directory in which you -installed the Google Maps frameworks: +1. If you are using CocoaPods to manage your dependecies, uncomment the +lines related to Google Maps from the `Podfile` and run `pod install`. -```json -{ - "name": "your-app", - "scripts": { - "postinstall": "./node_modules/react-native-maps/enable-google-maps REPLACE_ME_RELATIVE_PATH_TO_GOOGLE_MAPS_INSTALL" - } -} -``` +2. If you used React Native link, you may include Google Maps manually as a +XCode framework following the instructions from [SDK docs -> Install +manually](https://developers.google.com/maps/documentation/ios-sdk/start). Then, to link this library to the framework, add the following to your +`package.json` and replace the +`REPLACE_ME_RELATIVE_PATH_TO_GOOGLE_MAPS_INSTALL` with the relative path +from your project root to the directory in which you installed the +Google Maps frameworks: + + ```json + { + "name": "your-app", + "scripts": { + "postinstall": "./node_modules/react-native-maps/enable-google-maps REPLACE_ME_RELATIVE_PATH_TO_GOOGLE_MAPS_INSTALL" + } + } + ``` -Re-run `npm install` or `yarn` to ensure the `postinstall` script is run. + Re-run `npm install` or `yarn` to ensure the `postinstall` script is run. +3. Import and add `{PROVIDER_GOOGLE}` to your JavaScript: + ```javascript + import MapView, { PROVIDER_GOOGLE } from 'react-native-maps'; + ... + + + + ``` -## Notes on running on a real ios device +## Build configuration on Android -The steps are as described in https://facebook.github.io/react-native/docs/running-on-device.html , however instead of opening the .xcodeproj file you should open .xcworkspace file. +Ensure your build files match the following requirements: +1. Define the `react-native-maps` project in `android/settings.gradle`: -## Android +```groovy +... +include ':react-native-maps' +project(':react-native-maps').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-maps/lib/android') +``` -1. In your `android/app/build.gradle` add: +2. Add the `react-native-maps` as an dependency of your app in `android/app/build.gradle`: ```groovy ... @@ -146,7 +186,10 @@ dependencies { } ``` -If you've defined *[project-wide properties](https://developer.android.com/studio/build/gradle-tips.html)* (**recommended**) in your root `build.gradle`, this library will detect the presence of the following properties: +If you've defined *[project-wide +properties](https://developer.android.com/studio/build/gradle-tips.html)* +(**recommended**) in your root `build.gradle`, this library will detect +the presence of the following properties: ```groovy buildscript {...} @@ -165,7 +208,9 @@ ext { } ``` - If you do **not** have *project-wide properties* defined and have a different play-services version than the one included in this library, use the following instead (switch 10.0.1 for the desired version): +If you do **not** have *project-wide properties* defined and have a +different play-services version than the one included in this library, +use the following instead (switch 10.0.1 for the desired version): ```groovy ... @@ -180,14 +225,6 @@ dependencies { } ``` -2. In your `android/settings.gradle` add: - -```groovy -... -include ':react-native-maps' -project(':react-native-maps').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-maps/lib/android') -``` - 3. Specify your Google Maps API Key: Add your API key to your manifest file (`android/app/src/main/AndroidManifest.xml`): @@ -200,9 +237,17 @@ project(':react-native-maps').projectDir = new File(rootProject.projectDir, '../ android:value="Your Google maps API Key Here"/> ``` - > Note: As shown above, com.google.android.geo.API_KEY is the recommended metadata name for the API key. A key with this name can be used to authenticate to multiple Google Maps-based APIs on the Android platform, including the Google Maps Android API. For backwards compatibility, the API also supports the name com.google.android.maps.v2.API_KEY. This legacy name allows authentication to the Android Maps API v2 only. An application can specify only one of the API key metadata names. If both are specified, the API throws an exception. -Source: https://developers.google.com/maps/documentation/android-api/signup +> Note: As shown above, `com.google.android.geo.API_KEY` is the +> recommended metadata name for the API key. A key with this name can be +> used to authenticate to multiple Google Maps-based APIs on the Android +> platform, including the Google Maps Android API. For backwards +> compatibility, the API also supports the name +> `com.google.android.maps.v2.API_KEY`. This legacy name allows +> authentication to the Android Maps API v2 only. An application can +> specify only one of the API key metadata names. If both are specified, +> the API throws an exception. +Source: https://developers.google.com/maps/documentation/android-api/signup 4. Add `import com.airbnb.android.react.maps.MapsPackage;` and `new MapsPackage()` in your `MainApplication.java` : @@ -218,40 +263,40 @@ import com.airbnb.android.react.maps.MapsPackage; } ``` - 5. Ensure that you have Google Play Services installed: - * For Genymotion you can follow [these instructions](https://www.genymotion.com/help/desktop/faq/#google-play-services). - * For a physical device you need to search on Google for 'Google Play Services'. There will be a link that takes you to the Play Store and from there you will see a button to update it (do not search within the Play Store). + + * For the Genymotion emulator, you can follow [these instructions](https://www.genymotion.com/help/desktop/faq/#google-play-services). + * For a physical device you need to search on Google for 'Google Play + Services'. There will be a link that takes you to the Play Store and + from there you will see a button to update it (do not search within the + Play Store). + ## Troubleshooting -If you have a blank map issue, ([#118](https://github.com/airbnb/react-native-maps/issues/118), [#176](https://github.com/airbnb/react-native-maps/issues/176), [#684](https://github.com/airbnb/react-native-maps/issues/684)), try the following lines : +### The map background is blank (Google Maps) -### On iOS: +If google logo/markers/polylines etc are displayed but the map +background is otherwise blank, this is likely an API key issue. Verify +your API keys and their restrictions. Ensure the native `provideAPIKey` +call is the first line of `didFinishLaunchingWithOptions`. -If google logo/markers/polylines etc are displayed, this is likely an API key issue. Verify your API keys and their restrictions. Ensure the native `provideAPIKey` call is the first line of `didFinishLaunchingWithOptions`. +Ensure also that the relevant Google APIs have been enabled for your +project from the URLs below: -If you use Xcode with version less than 9 you may get `use of undeclared identifier 'MKMapTypeMutedStandard'` or `Entry, ":CFBundleIdentifier", Does Not Exist` errors. In this case you have to update your Xcode. +- [Google Maps SDK Android](https://console.developers.google.com/apis/library/maps-android-backend.googleapis.com/) +- [Google Maps SDK iOS (if required)](https://console.developers.google.com/apis/library/maps-ios-backend.googleapis.com) -### On Android: +For reference, you may read the relevant issue reports: ([#118](https://github.com/airbnb/react-native-maps/issues/118), [#176](https://github.com/airbnb/react-native-maps/issues/176), [#684](https://github.com/airbnb/react-native-maps/issues/684)). -1. Be sure to have `new MapsPackage()` in your `MainApplication.java` : +### No map whatsoever + +Ensure the map component and its container have viewport dimensions. An +example is below: -```java -import com.airbnb.android.react.maps.MapsPackage; -... - @Override - protected List getPackages() { - return Arrays.asList( - new MainReactPackage(), - new MapsPackage() - ); - } -``` -1. Set this Stylesheet in your map component ```jsx -import MapView from 'react-native-maps'; +import MapView, { PROVIDER_GOOGLE } from 'react-native-maps'; // remove PROVIDER_GOOGLE import if not using Google Maps ... const styles = StyleSheet.create({ container: { @@ -266,56 +311,104 @@ const styles = StyleSheet.create({ }, }); -export default class MyApp extends React.Component { - render() { - const { region } = this.props; - console.log(region); - - return ( - - - - - ); - } -} -``` -1. Run "android" and make sure all packages are up-to-date. -1. If not installed yet, you have to install the following packages : - - Extras / Google Play services - - Extras / Google Repository - - Android 6.0 (API 23) / Google APIs Intel x86 Atom System Image Rev. 19 - - Android SDK Build-tools 23.0.3 -1. Go to [Google API Console](https://console.developers.google.com/flows/enableapi?apiid=maps_android_backend) and select your project, or create one. -Then, once enabled, select `Go to credentials`. -Select `Google Maps Android API` and create a new key. -Enter the name of the API key and create it. - -1. Clean the cache : -``` -watchman watch-del-all -npm cache clean +export default () => ( + + + + +); ``` -1. When starting emulator, make sure you have enabled `Wipe user data`. +### Build issues with Google Maps iOS Utils (iOS) -1. Run `react-native run-android` +If your XCode project uses dynamic frameworks (e.g. you also have Swift +code in your project), you cannot install `Google-Maps-iOS-Utils` with +CocoaPods. The issue and a workaround for it has been documented +[here](https://github.com/googlemaps/google-maps-ios-utils/blob/master/Swift.md). -1. If you encounter `com.android.dex.DexException: Multiple dex files define Landroid/support/v7/appcompat/R$anim`, then clear build folder. -``` +### Runtime errors on iOS (Apple Maps) + +If you are trying to mount the map with the `GOOGLE_PROVIDER` during +runtime, but your build has been configured for the Apple Maps backend, +a runtime exception will be raised. + +In addition, when using Apple Maps, some Google-only functionalities +have been disabled via runtime errors. + +An exception will be raised if you try to use advanced features that +depend on the [Google Maps SDK for +iOS](https://github.com/googlemaps/google-maps-ios-utils). These include + +- Making markers from KML files +- Heatmap rendering +- Marker clustering +- etc. + +### Clearing caches + +Run these commands to clean caches + +```sh +# NPM +watchman watch-del-all +npm cache clean + +# Android, if you encounter `com.android.dex.DexException: Multiple dex files define Landroid/support/v7/appcompat/R$anim`, then clear build folder. cd android ./gradlew clean cd .. ``` -1. If you are using Android Virtual Devices (AVD), ensure that `Use Host GPU` is checked in the settings for your virtual device. +### When using XCode <9 + +If you use Xcode with version less than 9 you may get `use of undeclared +identifier 'MKMapTypeMutedStandard'` or `Entry, ":CFBundleIdentifier", +Does Not Exist` errors. In this case you have to update your Xcode. + +### When using Android studio + +Make sure your Android studio is up to date and set up following the +[React Native +docs](https://facebook.github.io/react-native/docs/getting-started.html). + +In particular, the following packages have to be installed: + + - Extras / Google Play services + - Extras / Google Repository + - Android 6.0 (API 23) / Google APIs Intel x86 Atom System Image Rev. 19 + - Android SDK Build-tools 23.0.3 + +### No native module found exception on Android + +Be sure to have `new MapsPackage()` in your `MainApplication.java` : + +```java +import com.airbnb.android.react.maps.MapsPackage; +... + @Override + protected List getPackages() { + return Arrays.asList( + new MainReactPackage(), + new MapsPackage() + ); + } +``` + +### Android emulator issues -1. If using an emulator and the only thing that shows up on the screen is the message: `[APPNAME] won't run without Google Play services which are not supported by your device.`, you need to change the emulator CPU/ABI setting to a system image that includes Google APIs. These may need to be downloaded from the Android SDK Manager first. +- When starting Android emulator, make sure you have enabled `Wipe user data`. +- If you are using Android Virtual Devices (AVD), ensure that `Use Host GPU` is checked in the settings for your virtual device. +- If using an emulator and the only thing that shows up on the screen is + the message: `[APPNAME] won't run without Google Play services which + are not supported by your device.`, you need to change the emulator + CPU/ABI setting to a system image that includes Google APIs. These may + need to be downloaded from the Android SDK Manager first. diff --git a/docs/mapview.md b/docs/mapview.md index edbe23a85..f933d89c6 100644 --- a/docs/mapview.md +++ b/docs/mapview.md @@ -7,6 +7,8 @@ | `provider` | `string` | | The map framework to use.

Either `"google"` for GoogleMaps, otherwise `null` or `undefined` to use the native map framework (`MapKit` in iOS and `GoogleMaps` in android). | `region` | `Region` | | The region to be displayed by the map.

The region is defined by the center coordinates and the span of coordinates to display. | `initialRegion` | `Region` | | The initial region to be displayed by the map. Use this prop instead of `region` only if you don't want to control the viewport of the map besides the initial region.

Changing this prop after the component has mounted will not result in a region change.

This is similar to the `initialValue` prop of a text input. +| `camera` | `Camera` | | The camera view the map should display. If you use this, the `region` property is ignored. +| `initialCamera` | `Camera` | | Like `initialRegion`, use this prop instead of `camera` only if you don't want to control the viewport of the map besides the initial camera setting.

Changing this prop after the component has mounted will not result in a region change.

This is similar to the `initialValue` prop of a text input. | `mapPadding` | `EdgePadding` | | Adds custom padding to each side of the map. Useful when map elements/markers are obscured. **Note** Google Maps only. | `paddingAdjustmentBehavior` | 'always'\|'automatic'\|'never' | 'never' | Indicates how/when to affect padding with safe area insets (`GoogleMaps` in iOS only) | `liteMode` | `Boolean` | `false` | Enable lite mode. **Note**: Android only. @@ -31,7 +33,7 @@ | `scrollEnabled` | `Boolean` | `true` | If `false` the user won't be able to change the map region being displayed. | `pitchEnabled` | `Boolean` | `true` | If `false` the user won't be able to adjust the camera’s pitch angle. | `toolbarEnabled` | `Boolean` | `true` | `Android only` If `false` will hide 'Navigate' and 'Open in Maps' buttons on marker press -| `cacheEnabled` | `Boolean` | `false` | If `true` map will be cached and displayed as an image instead of being interactable, for performance usage. +| `cacheEnabled` | `Boolean` | `false` | If `true` map will be cached and displayed as an image instead of being interactable, for performance usage. **Note:** Apple Maps only | `loadingEnabled` | `Boolean` | `false` | If `true` a loading indicator will show while the map is loading. | `loadingIndicatorColor` | `Color` | `#606060` | Sets loading indicator color, default to `#606060`. | `loadingBackgroundColor` | `Color` | `#FFFFFF` | Sets loading background color, default to `#FFFFFF`. @@ -62,6 +64,8 @@ To access event data, you will need to use `e.nativeEvent`. For example, `onPres | `onMarkerDragStart` | `{ coordinate: LatLng, position: Point }` | Callback that is called when the user initiates a drag on a marker (if it is draggable) | `onMarkerDrag` | `{ coordinate: LatLng, position: Point }` | Callback called continuously as a marker is dragged | `onMarkerDragEnd` | `{ coordinate: LatLng, position: Point }` | Callback that is called when a drag on a marker finishes. This is usually the point you will want to setState on the marker's coordinate again +| `onIndoorLevelActivated` | `IndoorLevel` | Callback that is called when a level on indoor building is activated +| `onIndoorBuildingFocused` | `IndoorBuilding` | Callback that is called when a indoor building is focused/unfocused @@ -69,14 +73,19 @@ To access event data, you will need to use `e.nativeEvent`. For example, `onPres | Method Name | Arguments | Notes |---|---|---| -| `animateToNavigation` | `location: LatLng`, `bearing: Number`, `angle: Number`, `duration: Number` | +| `getCamera` | | Returns a `Camera` structure indicating the current camera configuration. +| `animateCamera` | `camera: Camera`, `{ duration: Number }` | Animate the camera to a new view. You can pass a partial camera object here; any property not given will remain unmodified. +| `setCamera` | `camera: Camera`, `{ duration: Number }` | Like `animateCamera`, but sets the new view instantly, without an animation. | `animateToRegion` | `region: Region`, `duration: Number` | -| `animateToCoordinate` | `coordinate: LatLng`, `duration: Number` | -| `animateToBearing` | `bearing: Number`, `duration: Number` | -| `animateToViewingAngle` | `angle: Number`, `duration: Number` | +| `animateToNavigation` | `location: LatLng`, `bearing: Number`, `angle: Number`, `duration: Number` | Deprecated. Use `animateCamera` instead. +| `animateToCoordinate` | `coordinate: LatLng`, `duration: Number` | Deprecated. Use `animateCamera` instead. +| `animateToBearing` | `bearing: Number`, `duration: Number` | Deprecated. Use `animateCamera` instead. +| `animateToViewingAngle` | `angle: Number`, `duration: Number` | Deprecated. Use `animateCamera` instead. +| `getMapBoundaries` | | `Promise<{northEast: LatLng, southWest: LatLng}>` | `setMapBoundaries` | `northEast: LatLng`, `southWest: LatLng` | `GoogleMaps only` +| `setIndoorActiveLevelIndex` | `levelIndex: Number` | | `fitToElements` | `animated: Boolean` | -| `fitToSuppliedMarkers` | `markerIDs: String[]`, `animated: Boolean` | If you need to use this in `ComponentDidMount`, make sure you put it in a timeout or it will cause performance problems. +| `fitToSuppliedMarkers` | `markerIDs: String[], options: { edgePadding: EdgePadding, animated: Boolean }` | If you need to use this in `ComponentDidMount`, make sure you put it in a timeout or it will cause performance problems. | `fitToCoordinates` | `coordinates: Array, options: { edgePadding: EdgePadding, animated: Boolean }` | If called in `ComponentDidMount` in android, it will cause an exception. It is recommended to call it from the MapView `onLayout` event. | `pointForCoordinate` | `coordinate: LatLng` | Converts a map coordinate to a view coordinate (`Point`). Returns a `Promise`. | `coordinateForPoint` | `point: Point` | Converts a view coordinate (`Point`) to a map coordinate. Returns a `Promise`. @@ -94,6 +103,26 @@ type Region { } ``` +``` +type Camera = { + center: { + latitude: number, + longitude: number, + }, + pitch: number, + heading: number + + // Only on iOS MapKit, in meters. The property is ignored by Google Maps. + altitude: number. + + // Only when using Google Maps. + zoom: number +} +``` + +Note that when using the `Camera`, MapKit on iOS and Google Maps differ in how the height is specified. For a cross-platform app, it is necessary +to specify both the zoom level and the altitude separately. + ``` type LatLng { latitude: Number, @@ -161,3 +190,19 @@ type KmlContainer { markers: [Marker] } ``` + +``` +type IndoorBuilding { + underground: boolean, + activeLevelIndex: Number, + levels: Array, +} +``` + +``` +type IndoorLevel { + activeLevelIndex: Number, + name: String, + shortName: String, +} +``` \ No newline at end of file diff --git a/docs/marker.md b/docs/marker.md index 8df3a3f2a..36e506e16 100644 --- a/docs/marker.md +++ b/docs/marker.md @@ -44,6 +44,7 @@ To access event data, you will need to use `e.nativeEvent`. For example, `onPres | `showCallout` | | Shows the callout for this marker | `hideCallout` | | Hides the callout for this marker | `animateMarkerToCoordinate` | `coordinate: LatLng, duration: number` | Animates marker movement. **Note**: Android only +| `redraw` | | Causes a redraw of the marker. Useful when there are updates to the marker and `tracksViewChanges` comes with a cost that is too high. diff --git a/example/App.js b/example/App.js index 7b6231e61..cea488d0d 100644 --- a/example/App.js +++ b/example/App.js @@ -25,6 +25,7 @@ import DefaultMarkers from './examples/DefaultMarkers'; import CustomMarkers from './examples/CustomMarkers'; import CachedMap from './examples/CachedMap'; import LoadingMap from './examples/LoadingMap'; +import MapBoundaries from './examples/MapBoundaries'; import TakeSnapshot from './examples/TakeSnapshot'; import FitToSuppliedMarkers from './examples/FitToSuppliedMarkers'; import FitToCoordinates from './examples/FitToCoordinates'; @@ -42,6 +43,8 @@ import ImageOverlayWithAssets from './examples/ImageOverlayWithAssets'; import ImageOverlayWithURL from './examples/ImageOverlayWithURL'; import AnimatedNavigation from './examples/AnimatedNavigation'; import OnPoiClick from './examples/OnPoiClick'; +import IndoorMap from './examples/IndoorMap'; +import CameraControl from './examples/CameraControl'; const IOS = Platform.OS === 'ios'; const ANDROID = Platform.OS === 'android'; @@ -147,6 +150,7 @@ class App extends React.Component { [TakeSnapshot, 'Take Snapshot', true, '(incomplete)'], [CachedMap, 'Cached Map'], [LoadingMap, 'Map with loading'], + [MapBoundaries, 'Get visible map boundaries', true], [FitToSuppliedMarkers, 'Focus Map On Markers', true], [FitToCoordinates, 'Fit Map To Coordinates', true], [LiteMapView, 'Android Lite MapView'], @@ -162,6 +166,8 @@ class App extends React.Component { [ImageOverlayWithURL, 'Image Overlay Component with URL', true], [AnimatedNavigation, 'Animated Map Navigation', true], [OnPoiClick, 'On Poi Click', true], + [IndoorMap, 'Indoor Map', true], + [CameraControl, 'CameraControl', true], ] // Filter out examples that are not yet supported for Google Maps on iOS. .filter(example => ANDROID || (IOS && (example[2] || !this.state.useGoogleMaps))) diff --git a/example/examples/AnimatedNavigation.js b/example/examples/AnimatedNavigation.js index ce7b85f99..4b853539a 100644 --- a/example/examples/AnimatedNavigation.js +++ b/example/examples/AnimatedNavigation.js @@ -43,7 +43,7 @@ export default class NavigationMap extends Component { updateMap() { const { curPos, prevPos, curAng } = this.state; const curRot = this.getRotation(prevPos, curPos); - this.map.animateToNavigation(curPos, curRot, curAng); + this.map.animateCamera({ heading: curRot, center: curPos, pitch: curAng }); } render() { diff --git a/example/examples/CameraControl.js b/example/examples/CameraControl.js new file mode 100644 index 000000000..dc746bc93 --- /dev/null +++ b/example/examples/CameraControl.js @@ -0,0 +1,126 @@ +import React from 'react'; +import { + StyleSheet, + View, + TouchableOpacity, + Text, + Alert, +} from 'react-native'; + +import MapView, { ProviderPropType } from 'react-native-maps'; + +const LATITUDE = 37.78825; +const LONGITUDE = -122.4324; + + +class CameraControl extends React.Component { + async getCamera() { + const camera = await this.map.getCamera(); + Alert.alert( + 'Current camera', + JSON.stringify(camera), + [ + { text: 'OK' }, + ], + { cancelable: true } + ); + } + + async setCamera() { + const camera = await this.map.getCamera(); + // Note that we do not have to pass a full camera object to setCamera(). + // Similar to setState(), we can pass only the properties you like to change. + this.map.setCamera({ + heading: camera.heading + 10, + }); + } + + async animateCamera() { + const camera = await this.map.getCamera(); + camera.heading += 40; + camera.pitch += 10; + camera.altitude += 1000; + camera.zoom -= 1; + camera.center.latitude += 0.5; + this.map.animateCamera(camera, { duration: 2000 }); + } + + render() { + return ( + + { + this.map = ref; + }} + style={styles.map} + initialCamera={{ + center: { + latitude: LATITUDE, + longitude: LONGITUDE, + }, + pitch: 45, + heading: 90, + altitude: 1000, + zoom: 10, + }} + /> + + this.getCamera()} + style={[styles.bubble, styles.button]} + > + Get current camera + + this.setCamera()} + style={[styles.bubble, styles.button]} + > + Set Camera + + this.animateCamera()} + style={[styles.bubble, styles.button]} + > + Animate Camera + + + + ); + } +} + +CameraControl.propTypes = { + provider: ProviderPropType, +}; + + +const styles = StyleSheet.create({ + container: { + ...StyleSheet.absoluteFillObject, + justifyContent: 'flex-end', + alignItems: 'center', + }, + map: { + ...StyleSheet.absoluteFillObject, + }, + bubble: { + backgroundColor: 'rgba(255,255,255,0.7)', + paddingHorizontal: 18, + paddingVertical: 12, + borderRadius: 20, + }, + button: { + marginTop: 12, + paddingHorizontal: 12, + alignItems: 'center', + marginHorizontal: 10, + }, + buttonContainer: { + flexDirection: 'column', + marginVertical: 20, + backgroundColor: 'transparent', + }, +}); + +export default CameraControl; diff --git a/example/examples/DisplayLatLng.js b/example/examples/DisplayLatLng.js index a896bc53d..5117bde6f 100644 --- a/example/examples/DisplayLatLng.js +++ b/example/examples/DisplayLatLng.js @@ -44,15 +44,15 @@ class DisplayLatLng extends React.Component { } animateRandomCoordinate() { - this.map.animateToCoordinate(this.randomCoordinate()); + this.map.animateCamera({ center: this.randomCoordinate() }); } animateToRandomBearing() { - this.map.animateToBearing(this.getRandomFloat(-360, 360)); + this.map.animateCamera({ heading: this.getRandomFloat(-360, 360) }); } animateToRandomViewingAngle() { - this.map.animateToViewingAngle(this.getRandomFloat(0, 90)); + this.map.animateCamera({ pitch: this.getRandomFloat(0, 90) }); } getRandomFloat(min, max) { diff --git a/example/examples/IndoorMap.js b/example/examples/IndoorMap.js new file mode 100644 index 000000000..01f3911af --- /dev/null +++ b/example/examples/IndoorMap.js @@ -0,0 +1,72 @@ +import React from 'react'; +import { StyleSheet, View, Dimensions, Button, Alert } from 'react-native'; +import MapView from 'react-native-maps'; + +const { width, height } = Dimensions.get('window'); +const ASPECT_RATIO = width / height; +const LATITUDE = 1.3039991; +const LONGITUDE = 103.8316911; +const LATITUDE_DELTA = 0.003; +const LONGITUDE_DELTA = LATITUDE_DELTA * ASPECT_RATIO; + +class IndoorMap extends React.Component { + constructor(props) { + super(props); + this.setIndoorLevel = this.setIndoorLevel.bind(this); + } + + handleIndoorFocus(event) { + const { indoorBuilding } = event.nativeEvent; + const { defaultLevelIndex, levels } = indoorBuilding; + const levelNames = levels.map(lv => lv.name || ''); + const msg = `Default Level: ${defaultLevelIndex}\nLevels: ${levelNames.toString()}`; + Alert.alert( + 'Indoor building focused', + msg + ); + } + + setIndoorLevel(level) { + this.map.setIndoorActiveLevelIndex(level); + } + + render() { + return ( + + { this.map = map; }} + /> +