In my last post about gesture decorators I came up with a rather crude solution to fix the ghost panning issue. It turns out that there is a much cleaner, much more elegant solution to this problem.

Why does ghost panning appear at all? It’s because our wrapping elements take up as much space as possible – due to flexbox. So what if we could force the wrappers to effectively display like an inline item, so that it would only take up as much space as necessary?

After attending React Europe and chatting with @vjeux it turns out we have a much cleaner method of getting our wrappers to behave properly.

By adding alignSelf: 'flex-start' to the wrapper’s style, we achieve exactly what is written above – an inline version of our element, which automatically resizes itself to its content’s size.

This enables us to remove the cruft which has been added with the last iteration and substitute it with a very tiny piece. But it does not only clean up our code, it allows to really compose our decorators together, as there is no need for any size updates to bubble up the tree. Our decorators just wrap themselves around the components as tight as possible.

That method had an unfortunate flaw though: because we are wrapping the decorated component inside a View, it can happen that touches are registered where they shouldn’t be: outside of the wrapped view. This happens because the wrapper view – by default – stretches across the whole screen due to flexbox. And when we translate the wrapped view with a transform, the wrapper view stays in place, which leads to this “ghost-touch” behavior.

Thankfully the solution to this problem is not very hard. Instead of transforming the wrapped view, we transform the wrapper view instead!

As soon as the component is mounted, we measure the wrapped component. The ref we are using for this will be assigned in render. After receiving the dimensions we set them in our state. The measurement has to be done within a setTimeout because else measure() will only return zero values.

We now support a new prop – panningDecoratorStyle. This prop can be used to style the wrapper view. The width and height properties will be overwritten though, as we set them to our previously measured values.

This component takes care of rendering our decorated component and registers a handler for onPan. Whenever this callback is called, we will update this.state.transform and re-render, while passing the transform to panningDecoratorStyle.

With the above changes we can now transform a view using translate and avoid ghost-panning.

In the above solution we relied on UIManager and did some setTimeout trickery to get the view size. Instead of doing that we could also pass a method to onLayout of the wrapped view and update our view’s size using the event data:

Both these methods help us to get rid of ghost-panning and both are valid. Using the UIManager seems a bit hacky, but does not require any additional action from the user. onLayout seems cleaner, but requires the user to be more careful when using the decorator. Use whichever method you are more comfortable with.

This issue makes it tricky to compose multiple gesture decorators together. Each decorator has to resize itself, which can lead to race conditions. This is something that needs further investigation. But for a single decorator, this fix will work.

Gestures are one of the most prevalent things on mobile. Without them our apps wouldn’t be able to function – nobody could navigate anywhere! React Native comes with basic gesture support and allows us to use TouchableOpacity and friends to create views which are tappable. But what about other gestures like panning or pinch-zooming? Those we have to implement on our own – but that’s not as bad as it sounds. In fact, implementing the two mentioned gestures is quite straight forward, so that’s what we are going to do! (This post will only show the panning gesture, pinch-zooming will follow in a future post)

The PanResponder and the gesture responder system are what we will be using to handle touches. The difference between those two is that the PanResponder provides a bit of sugar on top of responder system, mainly the gestureState argument which gets passed to the event handlers in addition to the event.

There are eleven handlers that we can attach to our view in order to be notified of events during the touch lifecycle – and we will be needing most of them! Check the docs which I’ve linked above for more details about each of them.

In order to implement our gestures, it would make sense to make them as generic as possible, so we can reuse them with different components. Using a higher order component or decorator is a good way to achieve this. It allows us to create an api like this:

MyComponent = makePannable(MyComponent);

Not bad, but how about combining multiple gestures:

MyComponent = makePannable(makePinchZoomable(MyComponent));

That is pretty nice, isn’t it? We can easily enhance our component with multiple gestures, as long as the gestures itself to not interfere with each other.

Since React Native switched over to Babel for code-transpilation, we can make use of the proposed ES7 decorator syntax:

Now if that’s not a concise and clean way to enhance your components with gestures, I don’t know what is.

What is a decorator?

In case you are not familiar with the term, here is a quick explanation. A decorator, also called higher-order component, is a component, which wraps another component to enhance it in some way. The default pattern for a decorator is:

It is a function, which takes a component class as its argument and returns a new component class. The new class renders the original component, but is able to modify the props being passed down. The decorator component can apply whatever logic it pleases (firing requests in componentDidMount, listening to flux stores etc.).

lastX and lastY will hold the absolute changes to x and y since the first pan occurred. These two values are not in state, as they are only for internal use. We need them to compute absoluteChangeX and absoluteChangeY correctly.

changeX and changeY will hold the distance the touch travelled since the last update. absoluteChangeX and absoluteChangeY on the other hand will contain the absolute change from the origin since the first pan interaction with the view. We will use the absolute values to apply a transform style to translate the view.

Each time the touch moves, this method will be called. We grab the dx and dy values from the second argument (the handy gestureState), which represent the distances the touch has moved in x and y direction since the last event.

We now calculate the absolute change using the previous position. The dx and dy values are just added verbatim to our new state object.

After setting the state, we then try to call the onPan callback with the new state. This is done in order to expose an api into which we can hook from the outside. We could use it for example to trigger a condition based on the absolute change values.

In onPanResponderTerminationRequest we just return true – we don’t want to hog the touch in case another view wants to be the responder. This might happens when another view further up the hierarchy wants to become a responder to the touch.

We delegate onPanResponderRelease and onPanResponderTerminate to handlePanResponderRelease. There we assign the current absolute changes for the x and y positions to lastX and lastY respectively, so we can reference them again in the next panning action. In addition to that we call the onPanEnd callback, if available.

We wrap the passed in BaseComponent with a view, which receives all handlers from our PanResponder instance using the spread operator. The BaseComponent receives all props – minus the callbacks – and our internal state as props.

The decorated/wrapped component can now do whatever it wants with the information it received from the decorator. Most likely it will be used to pan an element using the transform property of a style-object, but it could be used for anything really. (Color tweening, custom sliders, etc. come to mind).

Using the PanResponder to track simple panning actions is a powerful tool for implementing your own gesture recognizers/decorators.

In the next post I will cover how to create a decorator which supports pinch-zooming.

Please note: due to the fact that we are wrapping a component within a view, there can be issues with this approach. Especially if a component does not fill up the whole screen and is moved using transform, it can result in the ability to move the view even though we are touching next to it. This is because the wrapping view is not being moved.

A possible solution to the problem would be to enhance the decorator to allow styling of the wrapper node and move the transformation code into a parent component. If I figure out a good way to do this I will publish the solution in another post.

One great feature of mobile platforms is deep linking into your application from custom URLs, using custom URL schemes. We wanted this for the React Native Playground iOS app, to share applications easily from any medium, like emails or tweets, using the rnplay:// scheme.

Defining a custom URL scheme

Custom url schemes are defined in your Info.plist file. Not too long ago you would have had to manually add keys there. Luckily you don’t have to anymore! Instead you can add URL types comfortably through the XCode interface.

Select your project in the left sidebar. Then select the target you want to add URL types to. Switch to the “Info” panel and open the “URL Types” section. Copy your bundle identifier into the “Identifier” and your desired URL scheme into the “URL Schemes” field. You can ignore the other fields (we do not need an icon and “roles” are only used on OSX). You should now have something similar to this:

Now your application is ready to respond to custom urls! (In the example above it would respond to any urls starting with myapplication://.

Modifying your application delegate file

This is only necessary to handle URLs passed to a launched application. Since apps often run in the background, we should do this. In your Appdelegate.m add this to the top:

Then add this to the end of the file:

This will make sure, that whenever somebody visits a link – with an URL scheme your application registered for – you will be properly notified about it and can take action. Even if your application is already launched, hooray!

Depending on your project file header path configuration it is possible, that XCode will complain that it cannot find RCTLinkingManager.h. But fear not! There is an easy solution to the problem. In XCode, select your project in the left sidebar. In the main panel navigate to “Build Settings”. Now scroll down until you find “Header Search Paths”, or alternatively use the search box at the top right. When you found them, double click on the value and using the “+” button at the bottom add a new path with the value $(SRCROOT)/node_modules/react-native/Libraries and set it to “recursive”. That should stop XCode from crying about not finding the headers. This is how it should look:

No more changes to your Appdelegate.m are required. Your file should look similar to this now:

Hooking up the JS side of things

Check out the final code, then let’s walk through it step by step.

I’m using ES6 class syntax here – you’re welcome to use React.createClass if you prefer.

We require the LinkingIOS module first.

We want to handle incoming requests as soon as our component is mounted, so we add a listener for the url event.

To keep things tidy, we remove the handler again when the component gets unmounted, even though it’s unlikely that will happen to our root component.

The real meat is in _processURL. We grab the url prop of the event, strip our custom url scheme, and finally separate the path from the query string.

Using the qs module (from npm), we parse the query string, and log the path and params to the console. Now we have everything we need to process our custom urls.

Testing our URL scheme

Let’s try launching this application, then backgrounding it by pressing the Home button.

Open Safari and visit myapplication://some-path?param=value. We’re sent back to our app. In the Xcode console, we should see some-path and {param: ‘value’}. Yay!

But what if our application hasn’t been launched yet? Let’s try it by exiting our app completely. To do this, double tap the Home button and swipe-up on our app.

Now repeat the Safari step.

Our app launches, but just sits there displaying the home screen – no log in our console.

This happens because no url event is triggered on application start. Let’s update our code to handle this case.

Take a look at the componentDidMount method on line 16. If the application has been launched via a URL, we can retrieve it using LinkingIOS.popInitialURL() and pass the URL to our handler. Since our event handler expends an event object with a url property on it, we wrap the url accordingly. In case you are wondering: {url} is the the ES6 object short notation and is equivalent to writing {url: url}.

Now you should be ready to use all the crazy url schemes you want. Try it!

Depending on the website you’re building, a fullsize background video can really add to the atmosphere. You’d think that the worst part will be to get it to work in IE, but alas that’s not the case. In fact in IE9+ this is as easy as pie, just like in Firefox or Opera, even though you need a different format than H264 for Opera (Theora or WebM).

The real show-stopper is actually webkit. Adding a video to the background of your page using the following css leads to quite some problems:

Note: The above gist does not deal with the problem of getting the video to actually cover the full screen, since the video will always maintain its aspect ratio.

After you’ve added your video to the background you will notice that as soon as you want to position any element using position:fixed, webkit will start to act up and the element will not stay in place, but rather scroll with the content and have rendering bugs. As mentioned in this stackoverflow.com post the solution for this is rather easy. Just add the following snippet to your elements with fixed positioning and they will behave properly again:

So far so good. Unfortunately, when trying to apply a fixed background image to a container, which is stacked above your background video, this background image will have rendering issues. To be more concrete: the image will not be displayed at all or only partially. And it looks really, really ugly. There is a fix for this, but it comes with its own tradeoff. When adding any overflow rule to your html and body tags, like overflow, overflow-x or overflow-y, webkit will display the background image properly.

There are two things which are now broken though. First of all, you cannot listen to the scroll event on the window object anymore. It won’t emit anything. Luckily this can be countered by adding a listener to the body element instead.

So that’s not that bad now, is it? Unfortunately it gets worse. By adding an overflow rule, webkit browsers will lose their ability to process body.scrollTop, so you’ll end up with something like this:

Oh and window.scrollTo() is broken too.

So all in all these are quite some tradeoffs to make a background video work in webkit. If you do not need to use scrollTop or scrollTo(), then using an overflow rule will surely solve your problem. If that is not an option, the following test might help to ease the pain, by detecting browsers, which are buggy with overflow-x and then add a class to the body so backgrounds can be handled differently:

Every now and then you want to use a transition effect to spice up your layout a bit. Imagine for example a folded corner on a container which moves a bit when you hover the container.

In browsers like Chrome and Firefox this does not pose a problem. Just add your transition and you’re done. In IE on the other hand you will notice that your precious transition will not work at all, if you are targeting a pseudo element like :before and :after. The solution to this is thankfully rather easy. All you have to do, is to set a property on your parent container, in addition to your changes of the pseudo element. This does not have to be a new property, you can just re-set an existing one, for example position like this this snippet:

You cannot apply any changes to :before or :after pseudo elements in IE without also modifying their parent element to trigger a repaint. So despite the headline or this post being related to transitions on pseudo elements, this is a fix for any kind of hover-related change on pseudo elements in IE.

The following pen shows an example. Both sides will work fine in Chrome, Firefox, etc. but the left version will not work in IE. The right one will, though.