diff --git a/releases/next/docs/cameraroll.html b/releases/next/docs/cameraroll.html index 4f97dd464da..c4a5b6ba718 100644 --- a/releases/next/docs/cameraroll.html +++ b/releases/next/docs/cameraroll.html @@ -6,7 +6,7 @@ app will use this data. This key will appear as Privacy - Camera Usage Des or a local video file URI (remote or data URIs are not supported for saving video at this time).

If the tag has a file extension of .mov or .mp4, it will be inferred as a video. Otherwise it will be treated as a photo. To override the automatic choice, you can pass an optional type parameter that must be one of 'photo' or 'video'.

Returns a Promise which will resolve with the new URI.

static getPhotos(params) #

Returns a Promise with photo identifier objects from the local camera -roll of the device matching shape defined by getPhotosReturnChecker.

Expects a params object of the following shape:

  • first : {number} : The number of photos wanted in reverse order of the photo application (i.e. most recent first for SavedPhotos).
  • after : {string} : A cursor that matches page_info { end_cursor } returned from a previous call to getPhotos.
  • groupTypes : {string} : Specifies which group types to filter the results to. Valid values are:
    • Album
    • All
    • Event
    • Faces
    • Library
    • PhotoStream
    • SavedPhotos // default
  • groupName : {string} : Specifies filter on group names, like 'Recent Photos' or custom album titles.
  • assetType : {string} : Specifies filter on asset type. Valid values are:
    • All
    • Videos
    • Photos // default
  • mimeTypes : {string} : Filter by mimetype (e.g. image/jpeg).

Returns a Promise which when resolved will be of the following shape:

  • edges : {Array<node>} An array of node objects
    • node: {object} An object with the following shape:
      • type: {string}
      • group_name: {string}
      • image: {object} : An object with the following shape:
        • uri: {string}
        • height: {number}
        • width: {number}
        • isStored: {boolean}
      • timestamp: {number}
      • location: {object} : An object with the following shape:
        • latitude: {number}
        • longitude: {number}
        • altitude: {number}
        • heading: {number}
        • speed: {number}
  • page_info : {object} : An object with the following shape:
    • has_next_page: {boolean}
    • start_cursor: {boolean}
    • end_cursor: {boolean}

You can edit the content above on GitHub and send us a pull request!

Examples #

Edit on GitHub
'use strict'; +roll of the device matching shape defined by getPhotosReturnChecker.

@param {object} params See getPhotosParamChecker.

Returns a Promise which when resolved will be of shape getPhotosReturnChecker.

You can edit the content above on GitHub and send us a pull request!

Examples #

Edit on GitHub
'use strict'; const React = require('react'); const ReactNative = require('react-native'); diff --git a/releases/next/docs/native-components-ios.html b/releases/next/docs/native-components-ios.html index 9aed7cb5406..ed87b80e356 100644 --- a/releases/next/docs/native-components-ios.html +++ b/releases/next/docs/native-components-ios.html @@ -1,12 +1,12 @@ -Native UI Components

Native UI Components #

There are tons of native UI widgets out there ready to be used in the latest apps - some of them are part of the platform, others are available as third-party libraries, and still more might be in use in your very own portfolio. React Native has several of the most critical platform components already wrapped, like ScrollView and TextInput, but not all of them, and certainly not ones you might have written yourself for a previous app. Fortunately, it's quite easy to wrap up these existing components for seamless integration with your React Native application.

Like the native module guide, this too is a more advanced guide that assumes you are somewhat familiar with iOS programming. This guide will show you how to build a native UI component, walking you through the implementation of a subset of the existing MapView component available in the core React Native library.

iOS MapView example #

Let's say we want to add an interactive Map to our app - might as well use MKMapView, we just need to make it usable from JavaScript.

Native views are created and manipulated by subclasses of RCTViewManager. These subclasses are similar in function to view controllers, but are essentially singletons - only one instance of each is created by the bridge. They vend native views to the RCTUIManager, which delegates back to them to set and update the properties of the views as necessary. The RCTViewManagers are also typically the delegates for the views, sending events back to JavaScript via the bridge.

Vending a view is simple:

  • Create the basic subclass.
  • Add the RCT_EXPORT_MODULE() marker macro.
  • Implement the -(UIView *)view method.
// RNTMapManager.m +Native UI Components

Native UI Components #

There are tons of native UI widgets out there ready to be used in the latest apps - some of them are part of the platform, others are available as third-party libraries, and still more might be in use in your very own portfolio. React Native has several of the most critical platform components already wrapped, like ScrollView and TextInput, but not all of them, and certainly not ones you might have written yourself for a previous app. Fortunately, it's quite easy to wrap up these existing components for seamless integration with your React Native application.

Like the native module guide, this too is a more advanced guide that assumes you are somewhat familiar with iOS programming. This guide will show you how to build a native UI component, walking you through the implementation of a subset of the existing MapView component available in the core React Native library.

iOS MapView example #

Let's say we want to add an interactive Map to our app - might as well use MKMapView, we just need to make it usable from JavaScript.

Native views are created and manipulated by subclasses of RCTViewManager. These subclasses are similar in function to view controllers, but are essentially singletons - only one instance of each is created by the bridge. They vend native views to the RCTUIManager, which delegates back to them to set and update the properties of the views as necessary. The RCTViewManagers are also typically the delegates for the views, sending events back to JavaScript via the bridge.

Vending a view is simple:

  • Create the basic subclass.
  • Add the RCT_EXPORT_MODULE() marker macro.
  • Implement the -(UIView *)view method.
// RCTMapManager.m #import <MapKit/MapKit.h> #import <React/RCTViewManager.h> -@interface RNTMapManager : RCTViewManager +@interface RCTMapManager : RCTViewManager @end -@implementation RNTMapManager +@implementation RCTMapManager RCT_EXPORT_MODULE() @@ -15,12 +15,12 @@ return [[MKMapView alloc] init]; } -@end

Note: Do not attempt to set the frame or backgroundColor properties on the UIView instance that you vend through the -view method. React Native will overwrite the values set by your custom class in order to match your JavaScript component's layout props. If you need this granularity of control it might be better to wrap the UIView instance you want to style in another UIView and return the wrapper UIView instead. See Issue 2948 for more context.

In the example above, we prefixed our class name with RNT. Prefixes are used to avoid name collisions with other frameworks. Apple frameworks use two-letter prefixes, and React Native uses RCT as a prefix. In order to avoid name collisions, we recommend using a three-letter prefix other than RCT in your own classes.

Then you just need a little bit of JavaScript to make this a usable React component:

// MapView.js +@end

Note: Do not attempt to set the frame or backgroundColor properties on the UIView instance that you vend through the -view method. React Native will overwrite the values set by your custom class in order to match your JavaScript component's layout props. If you need this granularity of control it might be better to wrap the UIView instance you want to style in another UIView and return the wrapper UIView instead. See Issue 2948 for more context.

Then you just need a little bit of JavaScript to make this a usable React component:

// MapView.js import { requireNativeComponent } from 'react-native'; -// requireNativeComponent automatically resolves this to "RNTMapManager" -module.exports = requireNativeComponent('RNTMap', null);

This is now a fully-functioning native map view component in JavaScript, complete with pinch-zoom and other native gesture support. We can't really control it from JavaScript yet, though :(

Properties #

The first thing we can do to make this component more usable is to bridge over some native properties. Let's say we want to be able to disable pitch control and specify the visible region. Disabling pitch is a simple boolean, so we add this one line:

// RNTMapManager.m +// requireNativeComponent automatically resolves this to "RCTMapManager" +module.exports = requireNativeComponent('RCTMap', null);

This is now a fully-functioning native map view component in JavaScript, complete with pinch-zoom and other native gesture support. We can't really control it from JavaScript yet, though :(

Properties #

The first thing we can do to make this component more usable is to bridge over some native properties. Let's say we want to be able to disable pitch control and specify the visible region. Disabling pitch is a simple boolean, so we add this one line:

// RCTMapManager.m RCT_EXPORT_VIEW_PROPERTY(pitchEnabled, BOOL)

Note that we explicitly specify the type as BOOL - React Native uses RCTConvert under the hood to convert all sorts of different data types when talking over the bridge, and bad values will show convenient "RedBox" errors to let you know there is an issue ASAP. When things are straightforward like this, the whole implementation is taken care of for you by this macro.

Now to actually disable pitch, we set the property in JS:

// MyApp.js <MapView pitchEnabled={false} />

This isn't very well documented though - in order to know what properties are available and what values they accept, the client of your new component needs to dig through the Objective-C code. To make this better, let's make a wrapper component and document the interface with React PropTypes:

// MapView.js import React from 'react'; @@ -28,7 +28,7 @@ import { requireNativeComponent MapView extends React.Component { render() { - return <RNTMap {...this.props} />; + return <RCTMap {...this.props} />; } } @@ -43,10 +43,10 @@ MapView.propTypes : React.PropTypes.bool, }; -var RNTMap = requireNativeComponent('RNTMap', MapView); +var RCTMap = requireNativeComponent('RCTMap', MapView); -module.exports = MapView;

Now we have a nicely documented wrapper component that is easy to work with. Note that we changed the second argument to requireNativeComponent from null to the new MapView wrapper component. This allows the infrastructure to verify that the propTypes match the native props to reduce the chances of mismatches between the ObjC and JS code.

Next, let's add the more complex region prop. We start by adding the native code:

// RNTMapManager.m -RCT_CUSTOM_VIEW_PROPERTY(region, MKCoordinateRegion, RNTMap) +module.exports = MapView;

Now we have a nicely documented wrapper component that is easy to work with. Note that we changed the second argument to requireNativeComponent from null to the new MapView wrapper component. This allows the infrastructure to verify that the propTypes match the native props to reduce the chances of mismatches between the ObjC and JS code.

Next, let's add the more complex region prop. We start by adding the native code:

// RCTMapManager.m +RCT_CUSTOM_VIEW_PROPERTY(region, MKCoordinateRegion, RCTMap) { [view setRegion:json ? [RCTConvert MKCoordinateRegion:json] : defaultView.region animated:YES]; }

Ok, this is more complicated than the simple BOOL case we had before. Now we have a MKCoordinateRegion type that needs a conversion function, and we have custom code so that the view will animate when we set the region from JS. Within the function body that we provide, json refers to the raw value that has been passed from JS. There is also a view variable which gives us access to the manager's view instance, and a defaultView that we use to reset the property back to the default value if JS sends us a null sentinel.

You could write any conversion function you want for your view - here is the implementation for MKCoordinateRegion via two categories on RCTConvert:

@implementation RCTConvert(CoreLocation) @@ -128,35 +128,35 @@ MapView.propTypes return <MapView region={region} />; }

Here you can see that the shape of the region is explicit in the JS documentation - ideally we could codegen some of this stuff, but that's not happening yet.

Sometimes you'll have some special properties that you need to expose for the native component, but don't actually want them as part of the API for the associated React component. For example, Switch has a custom onChange handler for the raw native event, and exposes an onValueChange handler property that is invoked with just the boolean value rather than the raw event. Since you don't want these native only properties to be part of the API, you don't want to put them in propTypes, but if you don't you'll get an error. The solution is simply to call them out via the nativeOnly option, e.g.

var RCTSwitch = requireNativeComponent('RCTSwitch', Switch, { nativeOnly: { onChange: true } -});

Events #

So now we have a native map component that we can control easily from JS, but how do we deal with events from the user, like pinch-zooms or panning to change the visible region? The key is to declare an event handler property on RNTMapManager, make it a delegate for all the views it vends, and forward events to JS by calling the event handler block from the native view. This looks like so (simplified from the full implementation):

// RNTMap.h +});

Events #

So now we have a native map component that we can control easily from JS, but how do we deal with events from the user, like pinch-zooms or panning to change the visible region? The key is to declare an event handler property on RCTMapManager, make it a delegate for all the views it vends, and forward events to JS by calling the event handler block from the native view. This looks like so (simplified from the full implementation):

// RCTMap.h #import <MapKit/MapKit.h> #import <React/RCTComponent.h> -@interface RNTMap: MKMapView +@interface RCTMap: MKMapView @property (nonatomic, copy) RCTBubblingEventBlock onChange; -@end
// RNTMap.m +@end
// RCTMap.m -#import "RNTMap.h" +#import "RCTMap.h" -@implementation RNTMap +@implementation RCTMap -@end
// RNTMapManager.m +@end
// RCTMapManager.m -#import "RNTMapManager.h" +#import "RCTMapManager.h" #import <MapKit/MapKit.h> -#import "RNTMap.h" +#import "RCTMap.h" #import <React/UIView+React.h> -@interface RNTMapManager() <MKMapViewDelegate> +@interface RCTMapManager() <MKMapViewDelegate> @end -@implementation RNTMapManager +@implementation RCTMapManager RCT_EXPORT_MODULE() @@ -164,14 +164,14 @@ MapView.propTypes - (UIView *)view { - RNTMap *map = [RNTMap new]; + RCTMap *map = [RCTMap new]; map.delegate = self; return map; } #pragma mark MKMapViewDelegate -- (void)mapView:(RNTMap *)mapView regionDidChangeAnimated:(BOOL)animated +- (void)mapView:(RCTMap *)mapView regionDidChangeAnimated:(BOOL)animated { if (!mapView.onChange) { return; @@ -199,7 +199,7 @@ class MapView extends this.props.onRegionChange(event.nativeEvent.region); } render() { - return <RNTMap {...this.props} onChange={this._onChange} />; + return <RCTMap {...this.props} onChange={this._onChange} />; } } MapView.propTypes = {