How to build a Roulette Wheel with React Native

Ben Hur
4 min readDec 29, 2022
courtesy of Alex Quezada from unplash

Roulette Wheels or Wheels of Fortune is not a new concept when you randomly need to pick a winner or prize, I've already experienced it on other apps, but, as a developer you can feel that it stills a Math.random() behind the curtains and that make you think, do I still had a chance to win the big prize?

For this tutorial we will aim in two goals:

  • To make an animated wheel that spins based in movement, not just pressing a button.
  • The wheel should respond to the amount of strength/speed the user applies while slides the finger.
spoiler alert: the result.

To accomplish this, we will combine two libraries one for the animation and the second for the gesture handler that are widely used in the react native world:

In the docs you can find detailed instructions to install it.

Reinventing the Wheel

With everything set we will create now the two components that compose our screen, the wheel it self and the label we use to indicate the angle and the color.

UI Components

To code this wheel basically I stacked two rows of two Views each, and then rounded the corners to 50% of the width, but you can use an Image or whenever you want to spin here:

and the Info component to show the current state of our wheel:

Handling the Animation

Now, with both components ready, we will implement the animation part of the code. First we have the shared value which will be our rotation value, useSharedValue hook can update this value and using useAnimatedStyle we can rotate the wheel without triggering any re-rendering in the app. Also we will keep track of the current rotation angle as a state, so we can show and define which color is the current one.

Handling the Gesture

The next session is about handling the gesture. First we are declaring a easing based on Easing.bezier function, you can use any easing function here, or none at all, they will directly affect the spinning of the wheel, how it will accelerate or decelerate in the end, bezier was the best option that I found, other options acted quite weird.

After defining the easing function we will use Gesture.Pan() from the gesture handler lib.It does have several different callbacks, here we are using onUpdate that is according to the docs:

called every time the gesture receives an update while it’s active. This callback will receive information about change in value in relation to the last received event.

So, it can be called more than once when the finger is sliding in the screen. This function get an event data with the informations like x and y position in the screen, x and y velocity of the movement and other more, for us the important one is the velocityY, which will give us the Y axis speed of the sliding, if it is positive, it is sliding down and negative it is sliding up.

Because of that difference, for this exemple I want only positive values, and that will make our wheel spin in only one direction, but if you remove the Math.abs it can spin on both directions. The velocity I wanted to divide by 7, that gave me a more fluent and natural spin, but you can use any value here, also we will sum up with the current rotation value, so our wheel will never jump from a position to another.

To ease the rotation animation we are using withTiming function, and passing a callback function to run after the animation ends. Considering gesture functions and animation runs on UI Thread of Javascript we can'’ directly update our state, so in order to do that, we will use runOnJS function passing the mod product that will always give us a value between 0 and 359, and that is our current angle.

Knowing the Winner

Considering the wheel will spin to the right, and we have 4 segments, each color will stand for an angle of 90 degrees, anything between 0 and 90 for exemple will represent red.

Assembling everything

In the end we have our component where all the detectable area we want is inside a GestureDetector which we will pass our gesture function as props, and inside it we get our Wheel also inside an Animated.View, as I mentioned before, we can use an image here or any other component.

Final Thoughts

Combining both libs to create this was easier than I thought, and I strongly recommend to check the docs to see what amazing things can be build with these libraries. The result here is not flawless, if you download the code and spin the wheel probably you gonna notice some intermediary updates in the state before the final one, so, feel free to suggest improvements in the comments or as a PR in the final code.

Git Repo: https://github.com/BenHurMartins/react-native-wheel-of-fortune

--

--

Ben Hur

I am a React Native Developer with passion to build things.