While reading Jake Murzy’s post: Implement FoldView in React Native and understanding how a view can rotate around its shifted origin, I was inspired another UI challenge, rendering an interactive cube using 6 views with different origins. I know you can’t resist your temper to make the following cube. Don’t worry, you will be guided to do it through this post. Let’s move on!

Interaction

In order to rotate a view as you drag it, it is required to get information about where you touch and drag. PanResponder in React Native makes you able to do it. Here’s a simple example of interactive view:

As you drag the view, handlePanResponderView function is consistently called and change the style of the view: rotateX and rotateY. dx and dy are the distance of the gesture since your touch started and we want to rotate the view further as you drag further. Simply, rotateX and rotateY can be set as dx and dy. Don’t forget that rotateX and rotateY takes only string format of ‘XXdeg’.

dx and dy are assigned to y and x respectively since the view will rotate horizontally around y-axis as it is dragged horizontally and vice versa. Similarly, the reason of additive inverse of dy shown in line number 27, is to make the view rotate in the same direction of your touch. It is totally up to you how you will rotate it!

Using setNativeProps method upon the view, it is possible to directly change its style without using state/prop and triggering a re-render of the entire subtree, which is useful regarding performance especially when we are about to change the style rapidly as dragging. This is s0-called direct manipulation.

Cool! Now, it rotates in three-dimensional space following your gesture. Have you noticed it is rotating around it’s center in xy-plane? Yes, it is the default origin where rotateX and rotateY use. In order to achieve cube-like rotation, we will shift it’s origin somewhere behind it in z-axis. Forget rotateX and rotateY from now on, but rather, we are going to use matrix.

Shifting Origin

React Native supports matrix in Transforms where you can change origins. If you are not sure about how rotation matrix works, I recommend you to read this post first which was mentioned earlier.

Since it is rotating about two arbitrary axes, the following general rotation matrix will be used. Don’t freak out. It is a simple plugging-in work. You can plug in zero to one of three variables: alpha, beta, and gamma.

Here, I have plugged in zero to gamma and assigned dx and dy to alpha and beta which are rotation degree in x and y axes respectively.

Similar to rotateX method used in react-native-foldView, this rotateXY will spin a view around x and y axes. Then, this method suppose to be invoked as you drag.

Considering the square as the front side of a cube, its origin should fall back half-length of the side in z-axis. Now, it is ready to spin the square around shifted origin! Here is the demo:

Comparing this to the previous, it is clear that it rotates around its origin shfited back by half-length of the side in z-axis. Let’s fill the other sides too.

Since dx and dy we are assigning to rotateXY method can be considered as rotation degrees, you can render left, right, and back side of a cube by simply adding -90, 90, and 180 to dx respectively. Here’s the demo again:

It is a little different story for rendering the top and bottom. If you render them by simply adding and substituting 90 to dy, it won’t rotate as you expected since they are on different plane. I used xz-plane by plugging in zero to beta from the general rotation matrix shown above. Here’s another rotate method for the top and bottom.

Add the following gist in your handlePanResponder method and your top and bottom views will spin perfectly.

Perfect! Were you able to play with the cube I have shown in the first demo? You can check the complete code here for your convenience.