The screenshots above are from what I have built. On the left is the list of cards currently zoomed out. You can swipe through them. You can also pull them up and have them go full screen. In which case, now you can paginate through them full screen, one by one. Compare this with a similar interaction model on Facebook Paper below.

The zoomed out carousel of cards at the bottom.

A video showcasing the original interactions of the app. See the 1:15 mark.

It starts with instantiating two state variables. One to store the pan values and another to store progress of the docking animation from 0 to 1. This progress variable is interpolated based on the pan values.

let pan = new Animated.ValueXY();

this.state = {

pan: pan,

dockAnimation: pan.y.interpolate({

inputRange: [-300, 0],

outputRange: [0, 1],

})

}

Now we need to create a panResponder. This is a sophisticated gesture handling concept with various methods that determine when the geture should activate and events on their completion. In our case, we want to track when the gesture is in progress and when it ends.

this._panResponder = PanResponder.create({

onStartShouldSetPanResponder: (evt, gestureState) => true,

onStartShouldSetPanResponderCapture: (evt, gestureState) => true,

onMoveShouldSetPanResponder: (evt, gestureState) => true,

onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,

onPanResponderGrant: () => {},

onPanResponderMove: Animated.event([null, {dx: this.state.pan.x, dy: this.state.pan.y}]),

onPanResponderRelease: (evt, gestureState) => {

// dragging stopped, animate the item to the correct position

}

})

Refer to the actual code to see the full implementaion of the onPanResponderRelease block. It basically deals with first figuring out whether the user has dragged far enough to actually toggle the state. If yes, it animates this movement.

transform: [{

scale: this.state.dockAnimation.interpolate({

inputRange: [0, 1],

outputRange: [1, 0.5],

})

}

A multitude of transforms are applied as a style to the ListView. I have shown the scale transform as an example. Here again we use the concept of an interpolation to control the animation.

<AnimatedListView

style={this.getListViewStyle()}

{...this._panResponder.panHandlers}

/>

Finally, the styles and the panHandlers from the panResponder are all hooked up to the ListView. Note that an a composed version of the ListView was created as AnimatedListView so that the Animated library can parse out the animatable values from the style object.

That’s all there is to be done for the animations! The rest is using flex-box layouts to build those beautiful cards. Jason Brown has written a nice book about the Animated library in React Native: http://browniefed.com/react-native-animation-book

I have shared all the code on Github. Feel free to hack away!

Currently I ran this only on iOS. But you can attempt to run this on Android and open a PR on the repo. I don’t seem to have used any iOS specific APIs, so theoretically, it should work on Android too!