How to use any iOS and Android library in React Native

How to use any iOS and Android library in React Native

How to use any iOS and Android library in React Native.In this tutorial, I will build a native loading screen overlay that can be called anywhere from React Native.

How to use any iOS and Android library in React Native. Image Source: MindInventory

  • Objective: Learn how to use any native library by creating a React Native bridge.
  • TL;DR: Check the entire code and follow the commits on GitHub.
  • Advanced feature: It’s recommended you know React Native well and have some experience with Android/iOS development.

Sometimes, you need to use a native Android or iOS library that doesn’t support React Native yet.

In my case, I wanted to use Helpshift, which is a customer support platform. If you explore their developer guide, you can see that they support every platform except React Native so I had no alternative but to build it myself.

I was also on a very tight schedule and I had to do it the fastest way possible, which is normal in the startup world, so keep reading if you find yourself in a similar situation.

Introduction

In this tutorial, I will build a native loading screen overlay that can be called anywhere from React Native.

I will use JGProgressHUD for iOS and KProgressHUD for Android. I chose these two libraries because they look very similar and have a similar API.

I named the project ReactNativeLoadingSpinnerOverlayNativeTutorial after an existing project but it uses native iOS and Android libraries instead of React Native components. It will look something like this:

iOS

1. Install the iOS library

Add this line to your pod file:

pod ‘JGProgressHUD’

To install the pod, run:

cd ios && pod install

2. Create the iOS bridge

Create the native files for your module by opening your workspace file on Xcode, select your project, and right-click to add a new file:

Select Cocoa Touch Class and click Next:

Put the name that you want for your module and click next:

Then, just click create:

Now you should have two files, in this case, LoadingOverlay.h and LoadingOverlay.m:

Create the bridge by copying this into your LoadingOverlay.h file:

//
//  BridgeTemplate.h
//  ReactNativeLoadingSpinnerOverlayNative
//
//  Created by Andre Pimenta on 11/07/2019.
//  Copyright © 2019 Facebook. All rights reserved.
//

#import "React/RCTBridgeModule.h"

// Instead of LoadingOverlay put the name of your module
@interface LoadingOverlay : NSObject <RCTBridgeModule>
@end

BridgeTemplate.h

And this into your LoadingOverlay.m file:

//
//  BridgeTemplate.m
//  ReactNativeLoadingSpinnerOverlayNative
//
//  Created by Andre Pimenta on 11/07/2019.
//  Copyright © 2019 Facebook. All rights reserved.
//

#import "React/RCTLog.h"
#import "LoadingOverlay.h" // Here put the name of your module

@implementation LoadingOverlay // Here put the name of your module

// This RCT (React) "macro" exposes the current module to JavaScript
RCT_EXPORT_MODULE();

RCT_EXPORT_METHOD(toggle:(BOOL *)show
                 resolver:(RCTPromiseResolveBlock)resolve
                 rejecter:(RCTPromiseRejectBlock)reject)
{
  dispatch_async(dispatch_get_main_queue(), ^{
    
    @try{ 
      resolve(@{ @"key": [NSNumber numberWithBool:1] });
    }
    @catch(NSException *exception){
      reject(@"get_error",exception.reason, nil);
    }
  });
}

@end

BridgeTemplate.m

This created a bridge that you can call from React Native.

As you can see, the function is called togglewhichreceives a boolean called show. Inside that function, you can play around with native code.

3. Implement the iOS native library

Let’s look at an example from JGProgressHUD:

JGProgressHUD *HUD = [JGProgressHUD progressHUDWithStyle:JGProgressHUDStyleDark];
HUD.textLabel.text = @"Loading";
[HUD showInView:self.view];
[HUD dismissAfterDelay:3.0];

They instantiate the HUD with some options, then show the HUD in a self.view, and then tell it to close in 3 seconds. OK, let’s implement this in the LoadingOverlay.m file.

We want to show it if show is true and hide it if show is false:

HUD = [JGProgressHUD progressHUDWithStyle:JGProgressHUDStyleDark];
if(show){
 UIWindow *window = [[UIApplication sharedApplication] keyWindow];
 UIView *topView = window.rootViewController.view;
 HUD.textLabel.text = @"Loading";
 [HUD showInView:topView];
}else{
 [HUD dismiss];
}

The whole file now looks like this:

//
//  LoadingOverlay.m
//  ReactNativeLoadingSpinnerOverlayNative
//
//  Created by Andre Pimenta on 11/07/2019.
//  Copyright © 2019 Facebook. All rights reserved.
//

#import "React/RCTLog.h"
#import "LoadingOverlay.h"
#import "JGProgressHUD.h"
#import <UIKit/UIKit.h>
@implementation LoadingOverlay

// This RCT (React) "macro" exposes the current module to JavaScript
RCT_EXPORT_MODULE();

JGProgressHUD *HUD;

RCT_EXPORT_METHOD(toggle:(BOOL *)show
                 resolver:(RCTPromiseResolveBlock)resolve
                 rejecter:(RCTPromiseRejectBlock)reject)
{
  dispatch_async(dispatch_get_main_queue(), ^{
    
    @try{
      if(!HUD)
        HUD = [JGProgressHUD progressHUDWithStyle:JGProgressHUDStyleDark];

      if(show){
        UIWindow *window = [[UIApplication sharedApplication] keyWindow];
        UIView *topView = window.rootViewController.view;
        HUD.textLabel.text = @"Loading";
        [HUD showInView:topView];
      }else{
        [HUD dismiss];
      }
      
      
      resolve(@{ @"key": [NSNumber numberWithBool:1] });
    }
    @catch(NSException *exception){
      reject(@"get_error",exception.reason, nil);
    }
  });
}

@end

LoadingOverlay.m

Notice I instantiate JGProgressHUD *HUD in the beginning of the file. We and then use it like a normal iOS library with the possibility of calling it from React Native.

Notice also how I get the main window where I show the HUD, this is very common when making these bridges, you will often need to get the main application window.

And that’s it for the native side. We can now call it anywhere on the React Native side:

import { NativeModules } from 'react-native';
var LoadingOverlay = NativeModules.LoadingOverlay;
//Let's show it
LoadingOverlay.toggle(true).then(result => {
  console.log('show', result)
})
// And let's hide it after 3 seconds
setTimeout(()=>{
  LoadingOverlay.toggle(false).then(result=>{
      console.log("hide", result)
  })
}, 3000)

Android

1. Install the Android library

Include this in your dependencies for your app: build.gradle inside the android/app folder.

dependencies {
    // Other dependencies
    implementation 'com.kaopiz:kprogresshud:1.2.0'
}
2. Create the Android bridge

Add two files on your project next to MainActivity.java, called LoadingOverlay.java andLoadingOverlayPackager.java:

Create the bridge by copying this into your LoadingOverlayPackager.java file:

//PUT YOUR PACKAGE HERE, IT'S THE SAME AS IN MainApplication.java
package com.reatnativeloadingspinneroverlaynativetutorial;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

//CHANGE LoadingOverlay WITH THE NAME OF YOUR CHOICE
public class LoadingOverlayPackager implements ReactPackage {

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }

    @Override
    public List<NativeModule> createNativeModules(
            ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();

        modules.add(new LoadingOverlay(reactContext));

        return modules;
    }

}

BridgeTemplateAndroidPackager.java

Important: Don’t forget to change the package name in the code.

Add this into your LoadingOverlay.java file:

//PUT YOUR PACKAGE HERE, IT'S THE SAME AS IN MainApplication.java
package com.reatnativeloadingspinneroverlaynativetutorial;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

//CHANGE LoadingOverlay WITH THE NAME OF YOUR CHOICE
public class LoadingOverlayPackager implements ReactPackage {

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }

    @Override
    public List<NativeModule> createNativeModules(
            ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();

        modules.add(new LoadingOverlay(reactContext));

        return modules;
    }

}

BridgeTemplateAndroidPackager.java

Important: Don’t forget to change the package name on the code

This created a bridge that you can call from React Native. As you can see, the function is called togglewhichreceives a boolean called show. Inside that function, you can play around with native code.

In order for Android to know that your module exists, add it to your packages list in your MainActivity.java file:

new LoadingOverlayPackager()

3. Implement the Android native library

Let’s look at an example from KProgressHUD:

KProgressHUD.create(MainActivity.this)
	.setStyle(KProgressHUD.Style.SPIN_INDETERMINATE)
	.setLabel("Please wait")
	.setDetailsLabel("Downloading data")
	.setCancellable(true)
	.setAnimationSpeed(2)
	.setDimAmount(0.5f)
	.show();

They instantiate the HUD with some options, then show the HUD in an activity. OK, let’s implement this in the LoadingOverlay.java file.

We want to show it if show is true and hide it if show is false:

KProgressHUD hud = KProgressHUD.create(activity);
if(show){
 hud.setStyle(KProgressHUD.Style.SPIN_INDETERMINATE)
 .setLabel("Please wait")
 .setAnimationSpeed(2)
 .setDimAmount(0.1f)
 .show();
}else{
 hud.dismiss();
}

The whole file now looks like this:

//PUT YOUR PACKAGE HERE, IT'S THE SAME AS IN MainApplication.java
package com.reatnativeloadingspinneroverlaynativetutorial;

import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import android.app.Activity;

import com.kaopiz.kprogresshud.KProgressHUD;

//CHANGE LoadingOverlay WITH THE NAME OF YOUR CHOICE
public class LoadingOverlay extends ReactContextBaseJavaModule {

    KProgressHUD hud;

    public LoadingOverlay(ReactApplicationContext reactContext) {
        super(reactContext);
    }

    @Override
    public String getName() {
        return "LoadingOverlay";
    }

    @ReactMethod
    public void toggle(Boolean show) {
        final Activity activity = getCurrentActivity();
        // PUT YOUR NATIVE CODE HERE

        if (hud == null) {
            hud = KProgressHUD.create(activity);
        }

        if (show) {
            hud.setStyle(KProgressHUD.Style.SPIN_INDETERMINATE)
                .setLabel("Please wait")
                .setAnimationSpeed(2)
                .setDimAmount(0.1f).show();
        } else {
            hud.dismiss();
        }

    }
}

LoadingOverlay.java

Notice I instantiate KProgressHUD hud in the beginning of the file. We can then use it like a normal Android library with the possibility of calling it from React Native.

Notice also how I get the main activity where I show the HUD, as was said for iOS, this is very common when making these bridges, you will often need to get the main application activity.

And that’s it. On the React Native side, you can call both iOS and Android native modules. This is a complete example of a React Native component calling the native module:

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow
 */

import React, {Component} from 'react';
import {
  View,
  StyleSheet
} from 'react-native';
import { NativeModules } from 'react-native';

class App extends Component {

  componentDidMount(){
	var LoadingOverlay = NativeModules.LoadingOverlay;
	//Let's show it
	LoadingOverlay.toggle(true)
	// And let's hide it after 3 seconds
	setTimeout(()=>{
		LoadingOverlay.toggle(false)
	}, 3000)
  }

  render(){
	return ( <View style={styles.background}></View>)
  }
};

const styles = StyleSheet.create({
  background: {
	backgroundColor: '#6ce6cb',
	flex: 1,
  },
});

export default App

App.js

And that’s it for coding, now for the final results.

Results

  • Code: Check the entire code on GitHub.

I hope this tutorial helped you!

Let me know in the comments if you are interested in the continuation of this article where I turn the implemented example into a proper npm package. Or, I can show how to build a much more complex bridge example.

How to Share Code Between React and React Native

How to Share Code Between React and React Native

Learn how to share code between React and React Native to avoid duplicating logic. Sharing Code Between React and React-Native: What Not to Share. This question of sharing code between React and React Native, in fact, one of the hot topics among React and React native developers all over the world. React and React-Native allow a learn once write anywhere paradigm. This is great, because one tech team can build both your web app and native mobile experience. The problem is developers hate writing things twice. There have been a couple of efforts to build a unifying technology to write an application once and have it work on both web and native.

How to Share Code Between React and React Native

Sharing Code Between React and React-Native: What Not to Share - Ben Ellerby

React and React-Native allow a learn once write anywhere paradigm. This is great, because one tech team can build both your web app and native mobile experience. The problem is developers hate writing things twice. There have been a couple of efforts to build a unifying technology to write an application once and have it work on both web and native. Yet this is not always the best approach. There is value in only sharing your business and state logic; keeping your render code separate.

In this talk I will give real examples from my work with MADE.COM, migrating their web and mobile application to React and React-Native with code sharing as a primary objective.

How to Share Code Between React and React Native

Learn how to share code between React and React Native to avoid duplicating logic

Sharing Code Between React and React Native

React and React-Native allow a learn once write anywhere paradigm. This is great, because one tech team can build both your web app and native mobile experience. The problem is developers hate writing things twice. There have been a couple of efforts to build a unifying technology to write an application once and have it work on both web and native. Yet this is not always the best approach. There is value in only sharing your business and state logic; keeping your render code separate.

React Native Map components for iOS + Android

React Native Map components for iOS + Android

React Native Map components for iOS + Android.Contribute to react-native-community/react-native-maps development by creating an account on GitHub

React Native Map components for iOS + Android

Installation

See Installation Instructions.

See Setup Instructions for the Included Example Project.

Compatibility

Due to the rapid changes being made in the React Native ecosystem, we are not officially going to support this module on anything but the latest version of React Native. With that said, we will do our best to stay compatible with older versions as much that is practical, and the peer dependency of this requirement is set to "react-native": "*" explicitly for this reason. If you are using an older version of React Native with this module though, some features may be buggy.

Note about React requires

Since react-native 0.25.0, React should be required from node_modules. React Native versions from 0.18 should be working out of the box, for lower versions you should add react as a dependency in your package.json.

General Usage
source-js
import MapView from 'react-native-maps';

or

source-js
var MapView = require('react-native-maps');

This MapView component is built so that features on the map (such as Markers, Polygons, etc.) are specified as children of the MapView itself. This provides an intuitive and react-like API for declaratively controlling features on the map.

Rendering a Map with an initial region

MapView
source-js-jsx
  <MapView
    initialRegion={{
      latitude: 37.78825,
      longitude: -122.4324,
      latitudeDelta: 0.0922,
      longitudeDelta: 0.0421,
    }}
  />

Using a MapView while controlling the region as state

source-js-jsx
getInitialState() {
  return {
    region: {
      latitude: 37.78825,
      longitude: -122.4324,
      latitudeDelta: 0.0922,
      longitudeDelta: 0.0421,
    },
  };
}

onRegionChange(region) {
  this.setState({ region });
}

render() {
  return (
    <MapView
      region={this.state.region}
      onRegionChange={this.onRegionChange}
    />
  );
}

Rendering a list of markers on a map

source-js-jsx
import { Marker } from 'react-native-maps';

<MapView
  region={this.state.region}
  onRegionChange={this.onRegionChange}
>
  {this.state.markers.map(marker => (
    <Marker
      coordinate={marker.latlng}
      title={marker.title}
      description={marker.description}
    />
  ))}
</MapView>

Rendering a Marker with a custom view

source-js-jsx
<Marker coordinate={marker.latlng}>
  <MyCustomMarkerView {...marker} />
</Marker>

Rendering a Marker with a custom image

source-js-jsx
<Marker
  coordinate={marker.latlng}
  image={require('../assets/pin.png')}
/>

Rendering a custom Marker with a custom Callout

source-js-jsx
import { Callout } from 'react-native-maps';

<Marker coordinate={marker.latlng}>
  <MyCustomMarkerView {...marker} />
  <Callout>
    <MyCustomCalloutView {...marker} />
  </Callout>
</Marker>

Draggable Markers

source-js-jsx
<MapView initialRegion={...}>
  <Marker draggable
    coordinate={this.state.x}
    onDragEnd={(e) => this.setState({ x: e.nativeEvent.coordinate })}
  />
</MapView>

Using a custom Tile Overlay

Tile Overlay using tile server

source-js-jsx
import { UrlTile } from 'react-native-maps';

<MapView
  region={this.state.region}
  onRegionChange={this.onRegionChange}
>
  <UrlTile
    /**
     * The url template of the tile server. The patterns {x} {y} {z} will be replaced at runtime
     * For example, http://c.tile.openstreetmap.org/{z}/{x}/{y}.png
     */
    urlTemplate={this.state.urlTemplate}
    /**
     * The maximum zoom level for this tile overlay. Corresponds to the maximumZ setting in
     * MKTileOverlay. iOS only.
     */
    maximumZ={19}
    /**
     * flipY allows tiles with inverted y coordinates (origin at bottom left of map)
     * to be used. Its default value is false.
     */
    flipY={false}
  />
</MapView>

For Android: add the following line in your AndroidManifest.xml

text-xml
<uses-permission android:name="android.permission.INTERNET" />

For IOS: configure App Transport Security in your app

Tile Overlay using local tiles

Tiles can be stored locally within device using xyz tiling scheme and displayed as tile overlay as well. This is usefull especially for offline map usage when tiles are available for selected map region within device storage.

source-js-jsx
import { LocalTile } from 'react-native-maps';

<MapView
  region={this.state.region}
  onRegionChange={this.onRegionChange}
>
  <LocalTile
   /**
    * The path template of the locally stored tiles. The patterns {x} {y} {z} will be replaced at runtime
    * For example, /storage/emulated/0/mytiles/{z}/{x}/{y}.png
    */
   pathTemplate={this.state.pathTemplate}
   /**
    * The size of provided local tiles (usually 256 or 512).
    */
   tileSize={256}
  />
</MapView>

For Android: LocalTile is still just overlay over original map tiles. It means that if device is online, underlying tiles will be still downloaded. If original tiles download/display is not desirable set mapType to 'none'. For example:

<MapView
  mapType={Platform.OS == "android" ? "none" : "standard"}
>

See OSM Wiki for how to download tiles for offline usage.

Overlaying other components on the map

Place components you that wish to overlay MapView underneath the MapView closing tag. Absolutely position these elements.

source-js-jsx
render() {
  return (
    <MapView
      region={this.state.region}
    />
    <OverlayComponent
      style={{position: “absolute”, bottom: 50}}
    />
  );
}

Customizing the map style

Create the json object, or download a generated one from the google style generator.

source-js-jsx
// The generated json object
mapStyle = [ ... ]

render() {
  return (
    <MapView
      region={this.state.region}
      onRegionChange={this.onRegionChange}
      customMapStyle={mapStyle}
    />
  );
}

For iOS, in addition to providing the mapStyle you will need to do the following

source-js-jsx
import MapView, { PROVIDER_GOOGLE } from 'react-native-maps'

// ...

<MapView
  provider={PROVIDER_GOOGLE}
  customMapStyle={MapStyle}
>

Then add the AirGoogleMaps directory:

https://github.com/react-native-community/react-native-maps/blob/1e71a21f39e7b88554852951f773c731c94680c9/docs/installation.md#ios

An unofficial step-by-step guide is also available at https://gist.github.com/heron2014/e60fa003e9b117ce80d56bb1d5bfe9e0

Examples

To run examples:

source-shell
npm i
npm start

#Android
npm run run:android

#iOS
npm run build:ios
npm run run:ios

MapView Events

The <MapView /> component and its child components have several events that you can subscribe to. This example displays some of them in a log as a demonstration.

Tracking Region / Location

Programmatically Changing Region

One can change the mapview's position using refs and component methods, or by passing in an updated region prop. The component methods will allow one to animate to a given position like the native API could.

Changing the style of the map

Arbitrary React Views as Markers

Using the MapView with the Animated API

The <MapView /> component can be made to work with the Animated API, having the entire region prop be declared as an animated value. This allows one to animate the zoom and position of the MapView along with other gestures, giving a nice feel.

Further, Marker views can use the animated API to enhance the effect.

Issue: Since android needs to render its marker views as a bitmap, the animations APIs may not be compatible with the Marker views. Not sure if this can be worked around yet or not.

Markers' coordinates can also be animated, as shown in this example:

Polygon Creator

Other Overlays

So far, <Circle />, <Polygon />, and <Polyline /> are available to pass in as children to the <MapView /> component.

Gradient Polylines (iOS MapKit only)

Gradient polylines can be created using the strokeColors prop of the <Polyline> component.

Default Markers

Default markers will be rendered unless a custom marker is specified. One can optionally adjust the color of the default marker by using the pinColor prop.

Custom Callouts

Callouts to markers can be completely arbitrary react views, similar to markers. As a result, they can be interacted with like any other view.

Additionally, you can fall back to the standard behavior of just having a title/description through the <Marker />'s title and description props.

Custom callout views can be the entire tooltip bubble, or just the content inside of the system default bubble.

To handle press on specific subview of callout use <CalloutSubview /> with onPress. See Callouts.js example.

Image-based Markers

Markers can be customized by just using images, and specified using the image prop.

Draggable Markers

Markers are draggable, and emit continuous drag events to update other UI during drags.

Lite Mode ( Android )

Enable lite mode on Android with liteMode prop. Ideal when having multiple maps in a View or ScrollView.

On Poi Click (Google Maps Only)

Poi are clickable, you can catch the event to get its information (usually to get the full detail from Google Place using the placeId).

Animated Region

The MapView can accept an AnimatedRegion value as its region prop. This allows you to utilize the Animated API to control the map's center and zoom.

source-js-jsx
import MapView, { AnimatedRegion, Animated } from 'react-native-maps';

getInitialState() {
  return {
    region: new AnimatedRegion({
      latitude: LATITUDE,
      longitude: LONGITUDE,
      latitudeDelta: LATITUDE_DELTA,
      longitudeDelta: LONGITUDE_DELTA,
    }),
  };
}

onRegionChange(region) {
  this.state.region.setValue(region);
}

render() {
  return (
    <Animated
      region={this.state.region}
      onRegionChange={this.onRegionChange}
    />
  );
}

Animated Marker Position

Markers can also accept an AnimatedRegion value as a coordinate.

source-js-jsx
import Mapview, { AnimatedRegion, Marker } from 'react-native-maps';

getInitialState() {
  return {
    coordinate: new AnimatedRegion({
      latitude: LATITUDE,
      longitude: LONGITUDE,
    }),
  };
}

componentWillReceiveProps(nextProps) {
  const duration = 500

  if (this.props.coordinate !== nextProps.coordinate) {
    if (Platform.OS === 'android') {
      if (this.marker) {
        this.marker._component.animateMarkerToCoordinate(
          nextProps.coordinate,
          duration
        );
      }
    } else {
      this.state.coordinate.timing({
        ...nextProps.coordinate,
        duration
      }).start();
    }
  }
}

render() {
  return (
    <MapView initialRegion={...}>
      <MapView.Marker.Animated
        ref={marker => { this.marker = marker }}
        coordinate={this.state.coordinate}
      />
    </MapView>
  );
}

If you need a smoother animation to move the marker on Android, you can modify the previous example:

source-js-jsx
// ...

componentWillReceiveProps(nextProps) {
  const duration = 500

  if (this.props.coordinate !== nextProps.coordinate) {
    if (Platform.OS === 'android') {
      if (this.marker) {
        this.marker._component.animateMarkerToCoordinate(
          nextProps.coordinate,
          duration
        );
      }
    } else {
      this.state.coordinate.timing({
        ...nextProps.coordinate,
        duration
      }).start();
    }
  }
}

render() {
  return (
    <MapView initialRegion={...}>
      <Marker.Animated
        ref={marker => { this.marker = marker }}
        coordinate={this.state.coordinate}
      />
    </MapView>
  );
}

Take Snapshot of map

source-js-jsx
import MapView, { Marker } from 'react-native-maps';

getInitialState() {
  return {
    coordinate: {
      latitude: LATITUDE,
      longitude: LONGITUDE,
    },
  };
}

takeSnapshot () {
  // 'takeSnapshot' takes a config object with the
  // following options
  const snapshot = this.map.takeSnapshot({
    width: 300,      // optional, when omitted the view-width is used
    height: 300,     // optional, when omitted the view-height is used
    region: {..},    // iOS only, optional region to render
    format: 'png',   // image formats: 'png', 'jpg' (default: 'png')
    quality: 0.8,    // image quality: 0..1 (only relevant for jpg, default: 1)
    result: 'file'   // result types: 'file', 'base64' (default: 'file')
  });
  snapshot.then((uri) => {
    this.setState({ mapSnapshot: uri });
  });
}

render() {
  return (
    <View>
      <MapView initialRegion={...} ref={map => { this.map = map }}>
        <Marker coordinate={this.state.coordinate} />
      </MapView>
      <Image source={{ uri: this.state.mapSnapshot.uri }} />
      <TouchableOpacity onPress={this.takeSnapshot}>
        Take Snapshot
      </TouchableOpacity>
    </View>
  );
}

Zoom to Specified Markers

Pass an array of marker identifiers to have the map re-focus.

Zoom to Specified Coordinates

Pass an array of coordinates to focus a map region on said coordinates.

Troubleshooting

My map is blank

  • Make sure that you have properly installed react-native-maps.
  • Check in the logs if there is more informations about the issue.
  • Try setting the style of the MapView to an absolute position with top, left, right and bottom values set.
  • Make sure you have enabled Google Maps API in Google developer console
source-js
const styles = StyleSheet.create({
  map: {
    ...StyleSheet.absoluteFillObject,
  },
});
source-js-jsx
<MapView
  style={styles.map}
  // other props
/>

Inputs don't focus

  • When inputs don't focus or elements don't respond to tap, look at the order of the view hierarchy, sometimes the issue could be due to ordering of rendered components, prefer putting MapView as the first component.

Bad:

source-js-jsx
<View>
  <TextInput/>
  <MapView/>
</View>

Good:

source-js-jsx
<View>
  <MapView/>
  <TextInput/>
</View>

React Native vs Flutter | Difference Between React Native & Flutter

React Native vs Flutter | Difference Between React Native & Flutter

This video on React Interview Questions will help you crack your next React interview with ease. React is the most popular front-end JavaScript library today and is being adopted by many big companies like Netflix, Airbnb, New York Times, and many more...

This video on React Interview Questions will help you crack your next React interview with ease. React is the most popular front-end JavaScript library today and is being adopted by many big companies like Netflix, Airbnb, New York Times, and many more. It is also used in small projects by web developers to showcase their skills in the field of web development. The video includes general React interview questions as well as questions focused on Redux, Hooks, and Styling. This video is ideal for both beginners as well as experienced professionals who are appearing for React web development job interviews. Learn the most important React interview questions and answers and know what will set you apart in the interview process.