Skip to content

Instantly share code, notes, and snippets.

@garrettmac
Last active August 16, 2017 17:35
Show Gist options
  • Save garrettmac/55fc7b2f2b75396086965562078a1f97 to your computer and use it in GitHub Desktop.
Save garrettmac/55fc7b2f2b75396086965562078a1f97 to your computer and use it in GitHub Desktop.
Blog Posts for React Native - Post 1:Native ModulesPost 2: Pan Responder (Animation)

Lets start with boiler template

/* @flow */

import React, { Component } from 'react';
import {
  View,
  TouchableOpacity,
  Text,
  StyleSheet,
  PanResponder,
} from 'react-native';



export default class PanResponderDemo extends Component {
state={
  debugActions:"Not Touched",
  actions:[" ------------- Start ------------- "]
}
  componentWillMount(){
  this._panResponder = PanResponder.create({
    // Ask to be the responder:
    onStartShouldSetPanResponder: (evt, gestureState) => {
      this.setState({actions: this.state.actions.concat("1) onStartShouldSetPanResponder")})
      // return true

    },
    onStartShouldSetPanResponderCapture: (evt, gestureState) => {
      this.setState({actions: this.state.actions.concat("2) onStartShouldSetPanResponderCapture")})
      // return true

    },
    onMoveShouldSetPanResponder: (evt, gestureState) => {
      this.setState({debugActions:"3) onMoveShouldSetPanResponder"})
      // return true
    },
    onMoveShouldSetPanResponderCapture: (evt, gestureState) => {
      this.setState({actions: this.state.actions.concat("4) onMoveShouldSetPanResponderCapture")})
      // return true

    },

    onPanResponderGrant: (evt, gestureState) => {
      // The gesture has started. Show visual feedback so the user knows



      // what is happening!

      // gestureState.d{x,y} will be set to zero now
    },
    onPanResponderMove: (evt, gestureState) => {
      this.setState({actions: this.state.actions.concat("6) onPanResponderMove")})


      // The most recent move distance is gestureState.move{X,Y}

      // The accumulated gesture distance since becoming responder is
      // gestureState.d{x,y}
    },
    onPanResponderTerminationRequest: (evt, gestureState) => true,
    onPanResponderRelease: (evt, gestureState) => {
      this.setState({actions: this.state.actions.concat("7) onPanResponderRelease")})


      // The user has released all touches while this view is the
      // responder. This typically means a gesture has succeeded
    },
    onPanResponderTerminate: (evt, gestureState) => {
      this.setState({actions: this.state.actions.concat("8) onPanResponderTerminate")})


      // Another component has become the responder, so this gesture
      // should be cancelled
    },
    onShouldBlockNativeResponder: (evt, gestureState) => {
      this.setState({actions: this.state.actions.concat("9) onShouldBlockNativeResponder")})


      // Returns whether this component should block native components from becoming the JS
      // responder. Returns true by default. Is currently only supported on android.
      return true;
    },
  });
}

  render() {
    let {actions} = this.state

    if(this.state.actions.length>20){
      this.state.actions.shift()
      this.setState({actions: this.state.actions});
    }

    return (
      <View style={s.container}>
        {/* Pan Responder Item */}
        <View style={[s.panItem,]}{...this._panResponder.panHandlers}>
        </View>







        {/* DEBUG FLOATING CONTAINER */}
        <TouchableOpacity onPress={()=>this.setState({actions:[" ------------- Restarted ------------- "]})} style={[{},s.debugContainer]}>
          {this.state.actions.map((o,i)=>{
            return <Text key={i} style={s.debugActions}>{o}</Text>
          })}
        </TouchableOpacity>

      </View>
    );
  }
}

const s = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent:"center",alignItems:"center",
  },
  panItem: {
    backgroundColor:"red",
    height:50,
    width:50,
  },
  debugContainer:{
    position:"absolute",
    bottom:25,
    right:10,
    flex:1,
    zIndex:3,
    width:null,
    height:null,
    alignItems:"center",
    justifyContent:"center",
    backgroundColor:"rgba(0,0,0,.5)"
  },
  debugActions:{
    fontSize: 10,
    color:"white",
    textAlign: "center",
    margin: 0,
  },
});

Im referring to each PanResponder Function by Numbers as they are long function names:

  1. onStartShouldSetPanResponder
  2. onStartShouldSetPanResponderCapture
  3. onMoveShouldSetPanResponderCapture
  4. onPanResponderMove
  5. onPanResponderRelease
  6. onPanResponderTerminate
  7. onShouldBlockNativeResponder

(URL to Imgur Album - http://imgur.com/a/F6abq) Lets first make some observations. Here I have 1,2,3 & 4 returning false

Open in Imgur (New Tab) - https://i.imgur.com/escV7Ol.gif

Result: only calls 1 & 4 when touched

Now Lets make them (1,2,3 & 4) return true

Open in Imgur (New Tab) - http://i.imgur.com/t3aAGRK.gif

Result: calls 1,5,6,8,7 when touched

Objective-C basics for Web Developers

Project Starter Files / Structure

When you start a project you'll start with the following:

AppDelegate.h
AppDelegate.m

ViewController.h
ViewController.m

Everything in the AppDelegate is Global. Any View the user is currently in will have access to the logic inside the AppDelegate.

And together these ViewController.* and AppDelegate.* files create the AppDelegate Class.

Notice how you have an AppDelegate.h as well as another one with a “.m” extension.

Header Files (Files With .h Extensions)

These are called the Header Files. Everything in here is Public.

complies all .c and .m files and replaces any #include *, or #import * directives with the entire text of those files where that directive #include *, or #import * statement was.

Example


Assume you have the following: Example.c

Alice
#include "Example.h"
Wonderland

Example.h

in

Compiled Result

Alice
in
Wonderland

Whats Happening The compiler would, after processing the replaces any #include *, or #import * directives with the entire compiled outout would show:

Implementation Files (Files With .m Extensions)

Is called the Implementation Files (where the .m I assume stands for "Model", seeing as Objective-C uses the MV Architecture), Everything in here is Private. It's public when it's methods are included in the .h header file.

These are where your logic goes.

Syntax

Example using NSLog

NSLog

notice:

1. NSLog(@"My Log %@")

%@

Is a Placeholder for Objects but NSString and NSNumber are both classes, and emit object instances of themselves when we create pointers with them

Defining A String:

You're not supposed to use int, string, const, or char's in Objective-C

1| NSLog(@"My Log %@")
2| NSString *myString = @"Hello World"
      ^        ^            ^
      |        |            |
  Definition   |      `@` says its a string
               |
         A Pointer You Created

Lets that exand that by adding a number

1| NSLog(@"My Log %@")
2| NSString *myString = @"Hello World"
3| NSNumber *myNumber = [NSNumber numberWithInt:420]
      ^        ^            ^
      |        |            |
  Definition   |      * See Below
               |
         A Pointer You Created
4| NSLog(@"My Log: %@",myString)
output >> "My Log: Hello World"

Notice the scary

[NSNumber numberWithInt:420]

All this is saying is

[<CLASS> <CLASS METHOD>:<PARAM>]

Where you use the [] brackets to call a method of a class.

Now lets log both our numbers and strings

1| //NSLog(@"My Log %@")
2| NSString *myString = @"Hello World"
3| NSNumber *myNumber = [NSNumber numberWithInt:420]
4| NSLog(@"%@ let's %@ it up in here", myString, myNumber)
output >> "Hello World let's 420 it up in here"

Importing And Exporting

Include

For C and C++ Files

Import

For Objective-C Files

Terminology

Interface

A Skeleton or Schema to create Objects or Arrays

Take the follwing

1| @interface Person : NSObject{
2|      NSString *name
3| }

Instance Variables: Anything inside the @interface's {}s

To Create an Instance Method do it outside the @interface's {}s Instance Methods use -(void):

1| @interface Person : NSObject{
2|      NSString *name
3| }
4| -(void)

Class Variables use +(void):

1| @interface Person : NSObject{
2|      NSString *name
3| }
4| +(void)

Resources

@garrettmac
Copy link
Author

garrettmac commented May 21, 2017

Project Starter Files / Structure

When you start a project you'll start with the following:

AppDelegate.h
AppDelegate.m

ViewController.h
ViewController.m

Everything in the AppDelegate is Global. Any View the user is currently in will have access to the logic inside the AppDelegate.

And together these ViewController.* and AppDelegate.* files create the AppDelegate Class.

Notice how you have an AppDelegate.h as well as another one with a “.m” extension.

Header Files (Files With .h Extensions)

These are called the Header Files. Everything in here is Public.

complies all .c and .m files and replaces any #include *, or #import * directives with the entire text of those files where that directive #include *, or #import * statement was.

Example


Assume you have the following:
Example.c

Alice
#include "Example.h"
Wonderland

Example.h

in

Compiled Result

Alice
in
Wonderland

Whats Happening
The compiler would, after processing the replaces any #include *, or #import * directives with the entire compiled outout would show:

Implementation Files (Files With .m Extensions)

Is called the Implementation Files (where the .m I assume stands for "Model", seeing as Objective-C uses the MV Architecture), Everything in here is Private. It's public when it's methods are included in the .h header file.

These are where your logic goes.

Syntax

Example using NSLog

NSLog

notice:

1. NSLog(@"My Log %@")

%@

Is a Placeholder for Objects but NSString and NSNumber are both classes, and emit object instances of themselves when we create pointers with them

Defining A String:

You're not supposed to use int, string, const, or char's in Objective-C

1| NSLog(@"My Log %@")
2| NSString *myString = @"Hello World"
      ^        ^            ^
      |        |            |
  Definition   |      `@` says its a string
               |
         A Pointer You Created

Lets that exand that by adding a number

1| NSLog(@"My Log %@")
2| NSString *myString = @"Hello World"
3| NSNumber *myNumber = [NSNumber numberWithInt:420]
      ^        ^            ^
      |        |            |
  Definition   |      * See Below
               |
         A Pointer You Created
4| NSLog(@"My Log: %@",myString)
output >> "My Log: Hello World"

Notice the scary

[NSNumber numberWithInt:420]

All this is saying is

[<CLASS> <CLASS METHOD>:<PARAM>]

Where you use the [] brackets to call a method of a class.

Now lets log both our numbers and strings

1| //NSLog(@"My Log %@")
2| NSString *myString = @"Hello World"
3| NSNumber *myNumber = [NSNumber numberWithInt:420]
4| NSLog(@"%@ let's %@ it up in here", myString, myNumber)
output >> "Hello World let's 420 it up in here"

Importing And Exporting

Include

For C and C++ Files

Import

For Objective-C Files

Terminology

Interface

A Skeleton or Schema to create Objects or Arrays

Take the follwing

1| @interface Person : NSObject{
2|      NSString *name
3| }

Instance Variables: Anything inside the @interface's {}s

To Create an Instance Method do it outside the @interface's {}s
Instance Methods use -(void):

1| @interface Person : NSObject{
2|      NSString *name
3| }
4| -(void)

Class Variables use +(void):

1| @interface Person : NSObject{
2|      NSString *name
3| }
4| +(void)

Resources

@garrettmac
Copy link
Author

garrettmac commented May 21, 2017

Creating A Native React Native Module

By The end of this tutorial you will have created a native module that will look like the following in Javascript:

 import { NativeModules } from 'react-native';

 NativeModules.FabricKit.addEvent('Birthday Party', '4 Privet Drive, Surrey');

Right Click your apps self titled folder inside your project RNFabricKit.xcodeproject > RNFabricKit Then Add New File > Cocoa Touch Class, Name it, I named mine RNStripe and whatever you named it will add a .h and .m file of that name, in my case it created a RNStripe.h and RNStripe.m once done your new .m file should look like this:

//
//  RNStripe.m
//  RNFabricKit
//
//  Created by vyga on 5/21/17.
//  Copyright © 2017 Facebook. All rights reserved.
//

#import "RNStripe.h"

@implementation RNStripe

@end

Now lets put in our React Native Bridge Boilerplate

//
//  RNFabricKit.m
//  portPal
//
//  Created by vyga on 5/21/17.
//  Copyright © 2017 Facebook. All rights reserved.
//

#import "RNFabricKit.h"
#import "React/RCTLog.h"

@implementation RNFabricKit
// To export a module by default name RNFabricKit
//RCT_EXPORT_MODULE();
// or to export a module by different name do something like
RCT_EXPORT_MODULE(FabricKit);





## METHODS


### EXAMPLE
#### In Objective-C
```objectivec
 ........... ........... ........... ...........
 RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location){
     RCTLogInfo(@"Pretending to create an event %@ at %@", name, location);
 }

In Javascript

 import { NativeModules } from 'react-native';

 NativeModules.CalendarManager.addEvent('Birthday Party', '4 Privet Drive, Surrey');

RCT_EXPORT_METHOD

This supports all standard JSON object types, such as:

  • string (NSString)
  • number (NSInteger, float, double, CGFloat, NSNumber)
  • boolean (BOOL, NSNumber)
  • array (NSArray) of any types from this list
  • object (NSDictionary) with string keys and values of any type from this list
  • function (RCTResponseSenderBlock)

/* USE RCTConvert
The RCTConvert helper functions all accept a JSON value as input and map it to a native Objective-C type or class.
*/

 We must explicitly expose methods otherwise JavaScript can't access anything
```objectivec
RCT_EXPORT_METHOD(get)
{
  //float volume = [AVAudioSession sharedInstance].outputVolume;
  //RCTLogInfo(@"The system volume level is %f", volume);
}
@end

Resources

Blog Guide - http://blog.tylerbuchea.com/how-to-create-a-react-native-ios-native-module/
React Native Docs Walkthrough - http://facebook.github.io/react-native/docs/native-modules-ios.html

@garrettmac
Copy link
Author

Im referring to each PanResponder Function by Numbers as they are long function names:

  1. onStartShouldSetPanResponder
  2. onStartShouldSetPanResponderCapture
  3. onMoveShouldSetPanResponderCapture
  4. onPanResponderMove
  5. onPanResponderRelease
  6. onPanResponderTerminate
  7. onShouldBlockNativeResponder

Lets first make some observations. Here I have 1,2,3 & 4 returning false


Open in Imgur (New Tab) - https://i.imgur.com/escV7Ol.gif

Result: only calls 1 & 4 when touched

Now Lets make them (1,2,3 & 4) return true


Open in Imgur (New Tab) - http://i.imgur.com/t3aAGRK.gif

Result: calls 1,5,6,8,7 when touched

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment