How to Build an Interactive “Wheel of Fortune” Animation with React Native

Rate this content

- Intro - Cleo & our mission

- What we want to build, how it fits into our product & purpose, run through designs

- Getting started with environment set up & “hello world”

- Intro to React Native Animation

- Step 1: Spinning the wheel on a button press

- Step 2: Dragging the wheel to give it velocity

- Step 3: Adding friction to the wheel to slow it down

- Step 4 (stretch): Adding haptics for an immersive feel

60 min
10 Jun, 2021

AI Generated Video Summary

This workshop focuses on building an interactive wheel of fortune feature with React Native. The feature, called spin to win, incentivizes users to save more by allowing them to spin a wheel and contribute to their savings. The tutorial covers setting up the pan responder to detect user gestures, calculating rotation using gesture handling, mapping animation values to rotation, adding momentum to the wheel for a realistic spinning effect, and addressing issues such as incorrect rotation and lack of velocity. The workshop also explores extensions like adding confetti and haptic feedback for a better user experience.

1. Introduction to the Wheel of Fortune Tutorial

Short description:

Let's kick it off. Cool. Thank you everyone for joining and welcome to this kind of webinar. We're gonna talk about how to build an interactive wheel of fortune or spin to win animation with React Native. We'll give a quick overview of Clio and our mission, as well as the spin to win idea. Then we'll get up and running with Expo and go through the main steps of dragging the wheel, adding momentum and animation, and implementing competitive tactics and further improvements. We'll wrap up with a Q&A. Clio is a money app that aims to redefine personal finance management by changing how people feel about their money. Our AI-powered app helps users with budgeting, saving, managing bills, and building credit scores. We strive to fight for the world's financial health. The spin to win idea aligns with our mission by helping users build a safety net. Let's dive into the tutorial and create an engaging feature for our users.

Let's kick it off. Cool. So yeah, thank you everyone for joining and welcome to this kind of webinar. My name is Oli, I'm a front end developer and tech lead at Clio and I'm joined by Alan as well. Yeah, I'm Alan, I'm a back end developer but yeah, I do some React, React native stuff as well every now and then. And I've been at Clio as well for a couple of years.

So yeah, so we're gonna talk about or kind of walk through a little tutorial on how to build an interactive kind of wheel of fortune or kind of spin to win as we like to call it animation with React native. So this is something we'll talk a little bit about or go into a little bit more in a few minutes, but something that we've built or been talking about building quite a lot at Clio and kind of something that we found to be really engaging feature, I guess, for our users.

So yeah, a quick overview of like the agenda. Yeah, like just quick intro into Clio and what we're trying to achieve in our mission. A quick overview of like the spin to win idea, you know, where it came from, where it kind of exists in the product. And also, we've also got some designs from Trev, one of the awesome designers at Clio as well. So a big thanks to him for providing the designs. We're then kind of gonna get up and running with Expo. We've got like a repo with a kind of starting template in it. So I've posted a link to that in the Discord chat. But if anybody doesn't have access to that, just shout. There's a couple of getting started instructions in there as well. So feel free to kind of get started with that. But we'll also walk through them for a couple of minutes as well. Make sure everybody's kind of up to speed and ready to go. And then yeah, we've kind of broken it down, I guess, into three main steps. We've got the kind of dragging the wheel, adding momentum and some animation, and then some nice to have competitive tactics and other further improvements. And then a quick roundup and QA. So I think we're aiming to be like less than an hour, hopefully. We'll try and kind of get it wrapped up fairly quick. But if anybody has any questions or problems or anything like that, feel free to shout in the Discord or in the Zoom chat as well. Like, yeah, we can both kind of jump out and help anyone or yeah, happy to answer any questions along the way as well.

So yeah, I guess kind of getting started a little bit about Clio and our mission. So Clio is a money app that's got your back. With Clio, we're trying to define a kind of new category of personal finance managed apps, and one that just goes beyond saving and budgeting to actually changing how people feel about their money. So over the last kind of couple of years, we've built an AI that over 4 million people are using across the US, Canada and the United Kingdom to kind of get roasted about their spending to budget and save as well, help managing their bills, getting salary advances and also understanding and building their credit score. So this is all delivered in a kind of chat first way. We've got a kind of, I guess, yeah, like a chat bot screen, which is where we can kind of deliver you your insights. And you can also ask Clio about your money. And this is kind of all delivered in an engaging tone of voice. And I guess what we're ultimately trying to do is create that friend who's looking out for you and your money. It's someone who's kind of got your back and is also not afraid to tell you when you fucked up. So yeah, that's the kind of the overview of Clio. And I guess our general mission is that we're trying to fight for the world's financial health. And that's kind of, yeah, that's what we're striving to achieve. The spin to win idea kind of lines up with that quite nicely. Last quarter, Alan and I were both working in the savings squad. And our kind of, I guess, squad mission for the quarter was to help help users build a safety net for that rainy day. The problem we were kind of, I guess, facing was that users were coming into the products and they'd never saved before. They had no savings, like existing savings, and they had no safety net. You know, one bad day could kind of tip them over the edge. So their car breaks down and they don't have the money to fix it up. They could kind of, you know, not then be able to go into their, to drive to their work.

2. Building the Spin to Win Feature

Short description:

We wanted to help users start saving for the first time and build up a safety net. Gamified savings or prize-linked savings can incentivize users to save more. We came up with the idea of a spin to win, where users can spin a wheel and contribute to their savings. This engaging feature promotes regular savings and helps users save more. We'll use Expo to build this feature quickly. If you have any questions, feel free to ask in the chat. Let's get started with the build. First, we'll add rotation to the wheel as the user moves their finger.

They could kind of, you know, not then be able to go into their, to drive to their work. They lose their job, they spiral into debt. And this was kind of, you know, actual things that we were seeing, or problems we were seeing users face. So our challenge or our mission for the quarter was to help users start saving for the first time and build up this safety net so that they could, yeah, so that they could, I guess, kind of, yeah, if they hit that bad day, they could afford to kind of, yeah, to fix it themselves.

And yeah, one of the kind of things that we looked into alongside, like, the automatic savings and roundups that we'd already kind of built out was the idea of, like, gamified savings or prize-linked savings. And this was something, it's not a new idea, and I've actually linked a couple of, kind of, articles and papers around this. But the kind of, the general idea is that we could incentivize users to save more by gamifying it or kind of linking prizes to the action of saving. And this has actually been proved to kind of increase the amount of money that people are saving over a year by quite a substantial amount. So I guess there's a kind of win-win there, where we've kind of built a product that can incentivize users to save more and to build that safety net up more, whilst also kind of building an engaging and fun feature.

And yeah, like, we, the kind of, the idea, I guess, that we came up with was this idea of a spin to win. So in its kind of MVP form, like, we just had a, we had a kind of a screen that after you saved or anytime you manually deposited into your savings account, you could spin a wheel, you know, it would give you a random number and that would, that number clear would kind of, you know, also contribute to your savings. That was, that was the kind of, yeah, I guess our hypothesis was that this would be an engaging feature for users and also promote the idea of regular savings and ultimately help users save more and build up that safety net. So that's the general idea. Alan, I don't know if you've got anything you want to add about that. No, I think, I think that pretty much sums it up. The interesting thing, I guess, is like people are really into the idea of like paying, like giving away money potentially, if it means that they'll give a, get a big reward, like an idea, like one of the things that really demonstrates that is, I guess, if you think about the lottery tickets, like a lot of people will spend money on lottery tickets, but be less likely to put the money that they paid on the tickets just into a savings account. So yeah, it's, I think, we thought it was like a really cool way to try to get users to save. But yeah, that's awesome. Yeah, and yeah, I guess like the, this kind of GIF is what we're going to try and build over the next kind of 40 minutes or so. And yeah, as I mentioned before, like it's a bit of an MVP. So, you know, we were just trying to get this out and seeing if it was an engaging feature to start with. But yeah, let's get started with the build then. And yeah, as I mentioned before, like if anybody's got any questions as we're going through this, feel free to put them in the Discord or the Zoom chat. And yeah, we can answer to any of those. Cool. So getting started, we're going to use the Expo to kind of build this on top of. So we've built a, yeah, I guess kind of for anybody who's not used Expo before, it's a kind of a wrapper around React Native that kind of manages a lot of the dependencies and lets you get up and running really quick. So it's kind of a perfect use case for this kind of thing where we just want to demo a quick feature. We've got a repo, I've put the link in here and also in the Discord where you can kind of clone the, our kind of get getting started app. If you've never used Expo before, you can install the CLI using this script and then, yeah, clone the repo and install dependencies and run Expo start to kick it off. You should then, I think after Expo started, I think you can hit the I key if you're on a Mac and it will spin up an iOS simulator locally, or you can hit the W key and it will open up in the web page and you can develop it there. So yeah. Yeah, I'll copy the links in chat, sorry. So yeah, so the slides are in a Google Drive, but the starting template app is that GitHub link, which should take you to the place to get started. I'll give it a few minutes for people to kind of get up and running there. But yeah, if you kind of get this, if you get it started, this kind of should be the screen that you see. So we've got a really simple, yeah, React Native app running in Expo. We've added some starting, I guess, components to it. So we've got our title, we've got a little arrow and then the kind of the actual spinner, which is just an image at the moment. And we're going to use this as our starting template. So cool. Think we're good to keep on going? Yeah, if anybody's struggling to get that up and running, shout in the chat. And yeah, we can go back over any bits. But if not, I'll kind of start getting started. So the first bit we're going to want to do, so I guess kind of going back a little bit, this is what we're wanting, or we're going to want to be wanting to build by the end. The idea is that you can kind of click and or I guess tap and hold the wheel, the kind of the spinning wheel. And then you're going to want to move it with your thumb. And as you move that gesture around or down, we're going to want to rotate that wheel along. And I think, like, I guess we've kind of roughly broken it down into like three steps. So the first is just kind of adding a rotation to that image as you move your finger, which you can kind of, I guess, see at this stage of the game.

3. Setting up the Pan Responder

Short description:

We need to detect when a user drags the wheel and map that to its rotation. We'll use the pan responder library to achieve this. The pan responder library allows us to listen for gestures and hook into different actions that the user is doing. We'll set up the pan responder on the wheel component and connect it to the rotation of the wheel. The first callback we're adding to the config is the on move should set pan responder, which ensures that the component receives the callbacks. The next callback we're interested in is on pan responder move, respond to new, which is called when the user starts moving their thumb around the component. We can check the contents of the gesture state in this callback. Finally, we'll add the pan responder config to the image component to set the callbacks live and see the console.warn fired when we move the gesture.

The second is like, I guess, the kind of flick and the kind of the actual adding the velocity to that spinning. Moving that momentum back down to zero over time or animating that. And then the third is, I guess, what actually happens when you when it finishes. So kind of with those in mind. The first step we're going to kind of, I guess, tackle is the the we want to be able to detect when a user drags it. We're going to want to like map that to a rotation of the wheel. And then we should be good to go.

So, sorry, interruption. So, cool. Yeah, there's linked the documentation to the two kind of, I guess, React Native libraries that we're going to use. So the first is the pan responder. And the second is the kind of animated library. So these are both included in the core React Native libraries. We're going to use the pan responder to detect the gesture. And then we're going to use the animated document, sorry, the animated library to actually kind of map that gesture into a value, a starting value. So, wrong way. Cool. So to get started, I guess the first thing we want to do is be able to detect that gesture when a user starts moving their thumb around around that image. And as I mentioned before, we're going to use the pan responder library to do that.

The first thing we can do is kind of set up the pan responder. And Alan, I think you, like we were talking about this earlier, and you described pan handlers to me really well. So I don't know if you want to. Yeah, so I think the idea is you set a listener on a component. And so the idea is we're going to set that wheel in the middle to listen for gestures. So as a user touches the screen, that pan respond will emit events that we can listen to. And pan responder comes with a bunch of callback functions that we can set in the config here, as Ollie's going to do now, where we can tell and allows us to hook into loads of different actions that the user is doing and do things based on those actions. And so yeah, as Ollie said, we're going to hook into that like wheel in the middle and connected to the users or connected to the gestures that the user is making. And we can and that way we can connect it to the rotation of the actual component. As you can see. Yeah. Yeah, cool. So yeah, I think that that like made it click for me. Yeah, I guess the pan responder library is kind of ultimately, it's pulling together all of the different touches and gestures that a user is making into a single kind of set of callback functions that we can then kind of hook into. So the first one that we're calling, or we're kind of adding into the config here is the on move should set pan responder. And I think this is mainly just kind of making sure that the that the component that we attach the pan responder to actually receives the callbacks and that it doesn't bubble up or down depend like if there's other kind of components around it that are also looking for the callbacks. And then the next one that we're interested in is for when and when the movement actually starts. So on pan responder move, respond to new. So this is the kind of the callback that will be called when the user starts like moving their thumb around the component that we attach this this kind of handler to. So I guess the way we can check that is by kind of writing this this callback. So it takes two, it takes two arguments. The first is the kind of the actual events that's happening. And the second is the kind of I guess the gesture state. So the state of the of the current gesture. So just to kind of like check that this is this is working. We can we can check, I guess the contents of the gesture state here. So we've now got our so we've got our pan responder config. The next step is to actually add this config to one of the components to kind of to set the callbacks live to actually add the handler. And the way you can do that is just by spreading the path. So what this is doing now is saying that this image component has the kind of the pan handler callbacks attached to it. So this is the config that we set up and we should be starting to see the console.warn fired when we move the gesture within here.

4. Calculating Rotation with Gesture Handling

Short description:

We'll be caring about the dy property, which represents the distance from where the user started dragging to where they finished dragging. We want to translate the Y movement in the gesture to a rotation of the image using React Native's animated APIs. We'll use the animated value functionality within the animated library to map the distance into a degree rotation.

And if we do and start dragging, so we should see that we get like a load of warnings with the full contents of that gesture state. Cool. Any questions so far? Are we good?

I think it'd be good if we just warn the gesture state.dy so we can see like the... Yeah, yeah. Because yeah, so the dy is the property that we'll be caring about to start with. dy is the distance from where the user started dragging to where they finished dragging. Yeah. So yeah, so within this kind of gesture state that is passed into the callback, we get a load of information about the gesture. And as I mentioned, one of those is dy, which is, yeah, the distance from where the touch started to where it actually kind of, I guess, is moved to. There's other ones such as like, you know, the actual coordinate of the thumb, I guess, on the screen. But yeah, the one we're most interested here is actually the movement of the thumb. So we can console.log.dy. And this is going to give us the numbers as, or I guess like the number of pixels from where the touch started. And actually, I guess this is probably a good time to talk about what we're trying to achieve with the touch, the gesture handling. And I think, yeah, our kind of idea with how this should work is that we want to kind of translate a Y movement in the gesture to a rotation of the image. And we can do that like really nicely using React Native's animated APIs. But I guess the way we're going to want to be able to calculate that is kind of by looking at the distance from where the touch started to where the touch ended. And like, yeah, mapping this distance into a degree rotation. So with this code that we've added in so far, we've got kind of got this bit here, like I'm not sure I'm even going to be able to write this. But like this, this amount here is the dy. And like, assuming we start kind of here, I'm so sorry, this is such a terrible scribble. Yeah, it looks good. It's clearer. And yeah, we're then I guess the next step then. So we've got our kind of, we've got our pan responder, we've got this distance here, we want to now translate that into an animated value, or a rotation value. And in order to do that, we're going to use the animated value, kind of what's it called, like functionality within the animated library. And I guess effectively, what this is, is it's a kind of a stream of values made to be like super performant. And we can then use various functions or functionality around that to allow us to map between the input and output values that we give it. So in this case, if my editor ever wants to come back, if it doesn't, one sec, let me try to restart that. Alan, anything to add whilst we have the annotations? I think you're doing a great job of explaining. Yeah, I think one thing, the annotation is still on the screen. I don't know if you could... Well, I think that was actually it. Yeah. What was your other thing by the way? Was your editor frozen? I think I might have just been drawing on top of it. I don't think it was actually frozen. Nice. Cool. Well, we'll give that another go. But yeah, are there any questions around this stuff at the moment? Okay. Yeah, feel free to post any questions in the Discord or the Zoom and we can try to answer them on the way. Cool. Okay. Okay. Can you zoom in a tiny bit, please? Oh, yeah. Sorry. Yeah. Good. Thanks. Okay.

5. Turning Distance into Rotation

Short description:

We're almost there. We've got the distance from when the user starts their gesture to when they finish it. We'll turn that value into a rotation value on the spin wheel using the animated value or animated library. We'll create a new animated value and wrap it in a ref to ensure consistency.

We're almost there. Okay. So, yeah, as I mentioned before, we've got the distance now from when the user starts their gesture or starts the drag to when they, I guess, continue it and finish it. The next thing we want to do is actually turn that value into a rotation value on the spin wheel. And yeah, as I mentioned before, we're going to use the animated value or animated library, which includes a value stream, effectively. So, the way we do this is we use the animated... So, we create a new animated value and we're going to start it kind of at zero, I guess, zero movement because we want it to kind of, yeah, start from the start. And then the only other thing to remember about when using animated values in functional components is just that we want to wrap it in a ref so that it's always the same. So, we're going to use the animated value just that we want to wrap it in a ref so that it's always the same value between lenders.

6. Mapping Animation Values to Rotation

Short description:

The rotate value is our pipeline or pipe of animation values that we'll set as the user moves their thumb. We'll map these values into the rotation by manually adding it to the image component. React Native's animated library allows us to pass an animated value to the rotation property of the image. By converting the image into an animated image, we can link the rotate value to the rotation value on the image.

So, yeah, the rotate value now is, I guess, our kind of pipeline or our pipe of kind of animation values that we're going to set as the user moves their thumb. And then what we want to do is map those values into the rotation. So, the first thing we want to do is just set this value. And we're going to set that value when the user moves that thumb.

So, using the kind of this, the bit that we were outputting earlier in the console statement. So, at this point, when you, I mean, nothing's going to happen, but when you... When you, yeah, when you move your thumb over, tap and kind of drag over the wheel, we're going to be kind of pushing the Y, that change of Y value into the rotate value, like, yeah, pipe, I guess. But we're not doing anything with it. We're just setting it at the moment.

So, the next thing we want to do is actually add that rotation to the image. And the way, I guess, we can start to do that is, I guess, just manually do it. So, we can pass the actual rotation into the image component. And like, yeah, so we can pass React Native allows you to pass in this rotate property by the transform style prop. And you can, yeah, set this to a certain number of degrees, and you can kind of see that image rotating around as we increase that. So, what we're going to want to do is link this rotate value to the rotation value on that image. And we can do that really easily using the React Native's animated kind of library again. The first thing is that we actually have, or the library wraps a lot of the base components in React Native with, like, the animated versions of them. And what this allows you to do is to pass, rather than kind of, I guess, fixed or variable values in here, it actually allows you to pass a rotated, oh, sorry, an animated value straight in. So, that's the first step is just to convert this into an animated image.

7. Mapping Pixel Values to Rotation

Short description:

We want to map the number of pixels from the gesture to a number of degrees rotation using the animated interpolate function. By specifying the input range and output range, we can control the mapping. For example, when the user moves their thumb by one pixel, we want that to equate to one degree rotation. We can fine-tune this mapping to create a more realistic interaction. The interpolated value can be directly used to rotate the image, mapping the gesture to the rotation value. This step successfully maps the change in Y gesture to a rotate value on the image.

The second step is that we want to provide a mapping from the kind of pixel values that we're inputting into here. So, remember, this dy is the number of pixels from where a gesture started to where the gesture actually ended, or is currently at. We want to map that from, like, I guess, a vertical pixel to a number of degrees rotation. And the way we can do that is using the animated interpolate function.

So, what we do, and yeah, this is going to be kind of passed into the spinner as a rotation style. So, we can say that's going to be our rotate value, and we want to interpolate that. So, interpolate is a function that is, kind of, I guess, exists on the rotate value. No, it's not. It's this. It's animated. No, yes. What am I talking about? Yes, it is. Cool. We pass in the input range. So, the input range is the, I guess, the kind of the values that we're interested in interpolating between. And the output range is, again, the kind of, like, the output we want to see from the interpolation function.

And in this case, we can actually pass in a number, a kind of degrees value in a string, and the library will kind of understand that this means it's a rotation and actually kind of transform these two values. So, effectively, what this is saying is that when the user has moved their thumb by one, by zero pixels, we want that to equate to zero degrees rotation, which makes sense. If you just kind of put your thumb on there and don't move it, like, we don't want that spinner to move. We're now saying that if you move that by one pixel down, we want that to equate to one degree rotation. So, this doesn't actually have to be a one, you know, a kind of one-to-one mapping. We could use this value to actually kind of, I guess, fine-tune the interaction and make it so that, like, it feels like you're actually pulling that spinner down. But we can, you know, we can play around with this value later and work out that exact mapping. And it's also something I think that would be much more kind of, like, or much better to actually have in your hand and playing around on your phone to see how it feels. So, we'll leave it as, I guess, a one pixel equals one degree rotation mapping for now.

So, to actually use this interpolated value, we can pass this spinner rotation directly into the rotate kind of style like this. And what we should now see or be able to do is when you move that, when you make that gesture, we see that kind of mapping to a rotate value on the image. So, yeah, that is, I guess, the initial kind of step that we wanted to do. We've mapped a change in Y kind of gesture to a rotate value on the image. And yeah, it's kind of, I guess, feeling pretty good. Alan, anything missed? Anything? No, I think that sounds great. The one thing that I think is kind of interesting is that input range and output range that we specified, those aren't necessarily limits. Those are just specifying the, I guess, it's the line, the angle, the steepness of how fast we want the input to affect the output. But it doesn't mean that we'll only affect things that are less than one pixel or the DY that's less than one. So, it'll keep going. It's just, it's more defining a line. And as Ollie's saying, we could make that one pixel movement actually translate to a more than one degree, like a two degree thing. And that would just mean it would spin faster for a thing. And we can really play with that to make it more realistic. Yeah. Yeah, really good point. Yeah. Yeah. So, just the question in the Zoom is exactly on that. Yeah. So, this is, yeah, exactly as Alan mentioned, it's a kind of a ratio mapping. So, a value of like what we is effectively saying is that like a value of two here would be two degrees. And you can actually specify that if you wanted to kind of like for it not to be a linear mapping. You know, you could kind of like change that depending on what you needed from the exact interpolation. But yeah, for us, we just, we only need like that linear mapping, which is cool.

8. Handling Rotation and Resetting

Short description:

We can use the config to clamp the rotation between zero and one degrees. However, there are a few caveats to consider. Firstly, the current approach relies on vertical movement, so the rotation may be incorrect when moving up the left side. Secondly, if we start a second gesture, the wheel resets to zero. To address this, we can add a reset button and use the animated spring function to smoothly animate the rotation back to zero. These animations provide a visually appealing experience. Any other questions or anything else to add at the moment?

The other thing you can do is like you can actually use, you can use some of these, some of the config in here to actually like clamp between them. Yeah, it's the extrapolate thing. So, you know, you could clamp it if you wanted it just to be like anything between zero and one goes to zero and one degrees. That was to kind of like actually, yeah, go outside of this range. So, yeah. So, we're happy with that linear mapping. Cool. Okay. I guess the other thing to mention at this point is that there's a few caveats to this or this approach to start with that I think we're kind of, it'd be good to talk about, but also be like we're aware of and it's something that we can come back to.

So, the first is that we're relying on this DY movement on the, of the user's thumb, whereas like actually the gesture could be a circular one. And at the moment, if you kind of like map this round or track the gesture round, like past the horizontal, and then like going, start going back up, you'll actually see that like we're rotating the wrong way when you're going up the left hand side. And the reason for that is that we're just tracking the vertical movement from where you started. So, it makes sense that it starts rotating backwards when you're going back up to that first spot. So, that's the first thing. And I think there's kind of various ways, I guess, of solving that. And like, yeah, that's definitely something we can talk about in a in a bit or talk about a bit later.

The other thing is that at the moment, if we kind of drag and drop, and kind of finish there, what, and then if we drag and drop again, you'll notice that our wheel kind of starts again from zero. And the reason that is, is because we are setting this kind of value to back to kind of zero degrees, sorry, zero pixels from the start of the gesture. So, we're starting a second gesture, and we're resetting that rotate value back to zero, which is why it's jumping. So, one, I guess, quite nice way of solving that is that, well, there's a couple of ways to solve it. The kind of the first or the most kind of technical would be like, you know, rather than resetting it back to zero, like we use the off an offset to kind of like always make sure that we're moving things from kind of where it last was dropped. But actually, I guess, like thinking about the problem or like what we're trying to achieve here, like we're trying to do a spin to win wheel for the user to spin once and then kind of find out like a prize that they win or something like that. You know, there might not actually be a use case for spinning multiple times. So, this could just be something that we see in dev. But like, I guess, to kind of solve it for ourselves, like it might be quite nice just to have a bit of a reset or a way to reset this back to zero without it kind of jumping back. So, what we could do is just add a button, a reset button. Let's call it reset. And then on press, we just want to call a new reset function that we can write up here. And what all the reset is going to do is it wants to set the rotate value back to zero. So, now we should have that reset button here. So, when we kind of click and drag away and do our first gesture and hit the reset button, we can see it jumps back to zero. And this is, I guess, also a nice time to introduce some of the kind of React animation or React native animated kind of helper or animation helper functions. And they allow you to do various things or manipulate animated values in various ways to provide really nice kind of interactive or visual animations. And one of them is called a spring. So, we could use the spring. So, rather than just resetting the value to zero here, we could actually animate it back to zero in like, you know, a nice fluid way. So, we can do that using the animated spring function. So, what we do is we call animated.spring and we say it that, we tell the function that our rotate value is the one we want to spring and that we are wanting to spring it back to zero. So, just to kind of show you what that looks like before we talk it through, what that's going to do is when you click reset, rather than jumping back to zero, it's... Rather than jumping... Let's try that again. Rather than jumping back to zero, it will animate and spring back. So, what I guess underneath what's going on is this function is like we've set the value to a kind of fixed value here. The spring function is calculating kind of a, you know, based on an easing curve, the next value that it should put in and kind of updating this... Or go back to zero. The second argument to the config is just kind of making sure that we're always using the kind of native or, yeah, using the native driver, which is like the kind of the new performance thing with the animated library. Cool. So, we've got our reset button working and that's kind of, yeah, springing back to zero, which is just a little bit of a nice to have for us. Any other questions or anything else to add at the moment? Not for me. Okay, sick.

9. Adding Momentum to the Wheel

Short description:

We've detected when a user drags down on the wheel and mapped that drag to a rotation using the pan responder and React Native animated libraries. Now, we need to add momentum to the wheel to make it spin. We'll take the velocity of the gesture at the point of release and decay it down to zero over time. By hooking into the on pan responder release function, we can get the velocity of the gesture and use it to continue moving the wheel at that velocity, gradually slowing it down using a friction function. This mimics the real-world behavior of spinning a wheel and gradually coming to a stop. The velocity is measured in pixels per millisecond and can be used to determine the number of degrees of rotation per millisecond. We'll use the decay function from the animated library to achieve this, passing in the velocity as a config.

Okay. So, just, I guess, kind of going back to our, yeah, our plan a little bit. We've detected when a user drags down on the wheel. We've then mapped that drag to a rotation. And, yeah, the two kind of libraries we've used here are the pan responder, which is the gesture handling or, yeah, gesture handling callbacks and the React Native animated kind of set of functions for mapping values to kind of styles effectively within our native app.

Cool. So, I guess, yeah, the next bit in the next piece of the puzzle is to actually add momentum to this wheel. So, we've got it at the moment. We've got it so that you can click and drag and let go and it stops. When you're spinning a wheel, we want, you know, we're going to want to add some momentum in there. But obviously, if you do that at the moment, it's just going to stop as soon as you lift your finger off. So, obviously, that's not great. So, the next thing to do is we're going to want to add some momentum to this wheel to, yeah, to get it spinning. And I guess, like, much like we did with the spring function here, we also have a really nice helper method in the animated library that can help us out here. And effectively, what we're going to do is we're going to want to take the velocity of the gesture at the point of release. And we're going to want to decay that velocity down to zero over time. So, I guess in kind of, like, what's actually happening is, like, you're moving your thumb down the screen to you're tapping and dragging and moving your thumb. At the point of you releasing your thumb, we want to take the velocity that your thumb was moving. And we're going to want to continue moving the wheel at that velocity. But slowly, like, you know, using a friction function, slowly kind of push that velocity down to zero. So, you know, as if you were spinning the wheel, it was tick, tick, tick, tick, tick, and slowly getting slower and slower and slower and then kind of, you know, landing on the value that you have. So, trying to kind of, I guess, mimic, like, the real world, yeah, real world, what would happen in the real world, really.

So, yeah. I guess to start with that, we're going to hook into the on pan responder release function. So, this is the bit that we, yeah, as I just mentioned, like, we want to get the velocity of your movement when you release your thumb from the screen. So, on pan handler release. So, this is another callback. It takes the same arguments to, as the on pan handler move. And like we did before, we can just, like, log out the gesture state. And within gesture state is this VY. So, this is the velocity of the kind of the Y in the Y axis of that gesture at the point of release. So, if we do that now, click and drag and release, we can see we get a value here. And I think, yeah, as you kind of, if you then try kind of spinning it harder or faster and then releasing, we get a bigger number. And I think, Alan, you did, you kind of managed to find out what this number actually means. Yeah. So, that number is, so, at the point of release, it's the pixels per millisecond that the gesture was moving at. So, if you do it again. So, yeah, Oli was moving his mouse at 11 pixel or point 18, 1.9 milliseconds, sorry, pixels per millisecond. So, yeah. So, that's the kind of the part, that's the unit that we get back as this gesture state dot VY value that we can use going forward.

So, we've got, yeah. So, we've got this value, which is, yeah, pixels per millisecond. And that is then, like, I guess, also the value that, because we've got this one-to-one mapping at the moment, like, we can also say that's, like, you know, the number of degrees rotation per millisecond as well. So, yeah. The next thing we're then going to want to do is to start mapping or kind of using this velocity. We want to give this animated value that or continue increasing the value using that velocity, but decay it down to zero. And as I kind of, I guess, alluded to, we've got this decay function that's included in the animated library. And it works in much the same way as the spring one. So, we can pass in, as a first argument, the kind of the actual animated value that we want to decay. And the config, we pass in the actual velocity of our gesture.

10. Adding Velocity and Addressing Issues

Short description:

We've added velocity to the animation. When the user releases their thumb or finger from the gesture, we take the velocity they were moving at and continue that velocity in the rotation, slowly decaying it down to zero with a deceleration function. However, there are some obvious holes in the current implementation. When rotating up and round, the wheel starts going back down to zero. If the user drags it to a specific value and lets go, there is no velocity added. We need to address these issues and consider further improvements, such as a gesture area for dragging back up, a minimum velocity or randomness to prevent cheating, and introducing some randomness for granting money or entering users into a prize draw to make it as safe as possible.

So, this could be any velocity that we want. But in our case, we want to pass in the velocity of the gesture. So, that speed at which the kind of user releases their thumb. So, I'm going to, we're going to start that on release. Cool. So, what we should now see in a bit of magic is when you release that thumb, the wheel continues to spin and slowly decays the velocity down to zero using a kind of, you know, a friction function or, you know, some kind of deceleration. And I guess the way you can check that is if you kind of go really slow in the release, it kind of, you know, really quickly goes down to zero. If you give it a big old spin and spin it hard, it will actually kind of keep on spinning and slowly go down to zero. So, yeah, we've kind of, I guess, we've got a lot of our functionality there, which is really cool. And it's been pretty simple using just, you know, a combination of the Panresponder and the kind of animated helper functions. There's a few other bits and pieces that I guess would be really great to kind of to play around with. So, the first is actually like this deceleration function or this kind of the speed at which we decay back to the velocity of the rotation down to zero. Yeah, we can kind of play around with that a little bit and try and make it feel as kind of as lifelike as possible or like, you know, really up that anticipation of it going, of the speed going down to zero. So, in the config that we passed to the decay function, we can also pass a deceleration value. I think this is 0.997 by default. So, this should be the same. I don't actually know what 0.997 means. I guess it's just some value. But what we can play around is if we kind of like, yeah, if you change that value to be different, you'll see that like, yeah, with lower deceleration value, we kind of go to down to zero much quicker. Does that make sense? It stops faster. Faster, thank you. And then, yeah, if we kind of like increase this load, I think what we should see is that this wheel just like spins forever. So, that's probably a little bit in excessive. It's never going to stop. The bearings on that. Yeah. And actually, when I was playing around with this before, and I've really bugged it. Cool. When I was playing around with this before, the value I thought felt best was 0.9989. And there was absolutely nothing apart from trial and error to get there. But like, yeah, have a play around a few different values and shout if anybody finds a better one. But this seemed to do a really good job of like, I guess, making that kind of anticipation of it spinning kind of like last as long as possible whilst you're still like, what am I going to get kind of thing. So, if we give it a spin now, it kind of goes down and it still goes, goes, goes, goes and then finally stops on your value. So, I don't know, that felt like it kind of gave a good level of anticipation whilst you're spinning it. Yeah. I could watch that forever. Cool. So, I guess like, yeah, we've got our, yeah, as part of this, we've added our kind of velocity to the animation. So, when the user releases their thumb or their kind of finger from the gesture, we take the velocity that they were moving at and continue that kind of velocity in the rotation, but kind of slowly decay it down to zero with a deceleration function. So, from a functionality or kind of like, I guess, a kind of happy path point of view, like this is, you know, most of what we needed and what we wanted to build. But yeah, I guess, as we kind of mentioned a little bit before, there's some pretty obvious kind of holes in this at the moment. The first being that, yeah, if you kind of rotate up and round, like it starts going back down to zero, which is a bit, a bit brap. And then the other is, I guess, if we're going to start to kind of, I guess, play around with the idea of this being something that you could win money off or that you could kind of use to gain, like if you drag it round to that 500 and let go, we kind of, yeah, you have no velocity, so we don't add any velocity in. So, and yeah, we can trust users to always find a way to do that. So, I guess the first thing that we could want to try and do, actually, I think I've got a slide for this. Yeah, nice. So, these are like the kind of further improvements or ideas that we were kind of talking about doing. Yeah, we've got some kind of the gesture area where you're kind of dragging back up. We've got this idea of like a minimum velocity or randomness if you're kind of like trying to cheat that system. And also the idea that kind of like if we're going to kind of grant money off this or, you know, just kind of like enter users into a prize draw or whatever it might be, like, maybe we do want this to be a little bit random in order to kind of, yeah, just make it as safe as possible.

11. Enhancing Velocity and Effects in React Native

Short description:

To give the wheel some velocity, we can set a minimum velocity and generate a random value if the velocity is below the minimum. We can also explore adding confetti and haptic feedback to enhance the user experience. It would be interesting to hear your ideas on how to improve the feature or even extend it to something more exciting. We could also consider flashing individual items when the wheel lands on them and using an animated XY value to allow movement in both the X and Y axes. As for deciding which field the wheel eventually spins to, we haven't covered that yet, but we can start exploring ways to map the rotation value to the segment value. Any suggestions are welcome!

So, yeah, I guess how we could actually do that is quite simple for the random one anyway. So, I guess going back to the problem, the kind of problem is that you can drag and drop this and drop it on the 500 and you've got no velocity. So, maybe all we need to do is give a minimum velocity in here. And if we have anything less than the minimum, then we kind of generate a random value. So, what we can do is just create a velocity here. And then we're going to say, like, if gesture state, if the velocity is greater than, let's say, one, then we're happy with it. Otherwise, like, let's create a random or pull a random value from somewhere. And here I've just added a plus one just to give it, like, an initial kick of velocity, just that it kind of moves something similar. And then we can pass this directly into that config. So, if we now reset this, so what we should see is we spin it as normal and we're all good. But if we reset that down to zero, if I now drag and drop that and just let it go, we get that kind of velocity kind of given for us. And we've added a, you know, we've added a random function in here. So, if you did it again, and we shouldn't, you know, we shouldn't always get the same value. So, we should be able to get something that's different to that 50. So, yeah. So, that kind of, I guess, solves one thing. The other thing is, like, if we wanted to keep this nice and clean, we could have a kind of, like, min velocity. Into there. And, yeah, that just gives us a bit of kind of control over the, yeah, of the kind of, of the gesture, I guess. Alan, any other thoughts on the other bits? I mean, there's that, there's some, just some ideas. React Native has, like, a native confetti library that you could stick in. There's a screenshot at the start of the presentation with confetti in it. And haptics, haptic feedback. It would be kind of cool if, if you've ever seen, like, one of those Wheel of Fortune kind of things where there's actually, like, little bits in between each quadrant, or not quadrant, but section that holds it, and it kind of ticks between, as it slows down, it ticks between. And so, we could, we could do that. So, yeah, I mean, it'd be really interesting to see what kind of ideas any of you have, like, how we could improve this, or, or it would be so cool if you pulled it down and, like, rebuilt it and then extended it to something that you thought was cool. I think that would be really cool, yeah. Yeah, for sure. Yeah, like, this is very much, like, yeah, first, first implementation. So, there's kind of, yeah, any other ideas to make, ideas to make it awesome would be sweet. I know, like, one of the other things we talked about doing is, I guess, using, like, a kind of image here and rotating it around is a bit of a cheating way of doing it. But, you know, what if we could flash individual items when we landed on it, and kind of, you know, actually build this up as its own component that we were rotating, rather than an image, and, you know, then we could kind of, like, flash the segment that we land on and have that, like, emit the confetti, or, yeah, something like that would be quite cool. Yeah, Paul's comment about taking to the DX is, yeah, definitely a good shout. Animated, like, we could use the animated value, rather than it just being a kind of a single, yeah, a single kind of value, we could use the XY, kind of, helper to actually, XY, kind of, helper to actually allow us to move things in the Y and X axes at the same time. And that way we could, yeah, we could use the X value, too, and have that rotation, that X value map with the, yeah, with the kind of movement along the Y axis, as well. But, yeah, I think there might be easier ways to solve the problem with, about, like, kind of moving your thumb around it. For example, like, we just kind of, like, detect when you move your thumb, like, further left than the kind of the middle point, and then start, like, taking, yeah, negating the value, which is, again, a bit of a cheat, but... Will you still cover how to decide which field we eventually spin to? So, that's a really good question. We haven't, kind of, gotten that far yet. It's definitely something, like, I think we could probably try and start, yeah, putting it together. I think the way that, I guess, we can, kind of, think about how to do that is that, at the moment, this value, yeah, we've mapped this, we've kept it quite easy for ourselves because these values are mapped from one pixel or one, yeah, one unit in the value, in the animated value equals one degrees of rotation. And if we, kind of, yeah, say that we've got, like, 10 segments here, each segment is going to be 36 degrees of value, or 36, kind of, pixels in the value. So, what we can do is this start function gives you a callback on finish. So, let's just check what this value is. So, what we should see now is if we let that spin out, we should then see, kind of, the finish value here. Cool. And what we want to do then is actually say, like, we want to know the outcome or the current value at the time of finish. And we then want to be able to, I guess, kind of, divide it by 10 to give us the, yeah, the, kind of, segment. Is that right? Divide it by 10? Yeah. Here we go.

12. Adding Listener and Extensions

Short description:

Yeah, one bit is that we don't have access to the raw value from the animated value. We can set up a listener for this value and add it to the state. Then, in the finish function, we can calculate the segment the user's falling into based on the value. We could also add extensions like firing confetti and using haptic feedback to enhance the user experience. It would be great to hear any thoughts or ideas from everyone.

Yeah, okay, try it. So, one bit is that we don't have the actual, with this animated value, we can't actually, kind of, get access to the raw value from this. So, what we'll need to do is actually set up a listener for this value and, kind of, add it to the state. So, let's just, kind of, like, put this together quite quick. So, what I'm going to do is add a listener to the rotate value. And we're going to set the value when that's called. In our effect, we can just return a cleanup as well. Okay. Yeah, this is, I'm just, kind of, putting this together to show how it could be done. But what we should now have is, in this state, we have our, kind of, value. And what we can then do is, in this finish function, we can, kind of, just double check what our value is. So, if we spin that around, we now have, that's not what, yeah. So, what we will have at this point is the value that we finish at in this, or what we should have is the value that we finish at in this callback. And then we can, yeah, as I mentioned, use that to calculate that starts in. So, we're starting in the middle of the segment. We'll be, kind of, like, minus 5 and plus 5, sorry, 6, 6, 2, 2. We'll be minus 18 and plus 18 from the start will be our first segment. So, yeah, we could, kind of, calculate the offsets from that and, kind of, work out what that value, what segment the user's falling into based on, like, the modulus of that, if that makes sense. Andre, does that make sense for the, kind of, deciding which has been spun to? Awesome. And I'm not exactly sure why this isn't working at the moment. I'm sure there's some stupid thing going on. But, yeah, that's roughly how it would work. Cool. Any other questions? Any other thoughts on, like, on, yeah, I guess, extensions that we could do here or, like, little nice bits that happen as well? Like, feel free to fire them anywhere. But, yeah, as Adam mentioned, like, yeah, there's some nice little libraries such as the confetti one. So, yeah, what we could do is, yeah, we could use this, kind of, this library to fire some confetti when, yeah, at this point, when we finish that decaying, when that velocity's back to zero, we could fire some confetti. The haptics is a really nice idea as well. So, I think one of the things we found is that haptics add, like, you know, kind of another dimension to the, to how an app feels. And obviously, in that real world, when you're spinning that spinner, you kind of get those clicks and you can feel it. And that's a big part of the process. And in much the same way, like, as we kind of could calculate the segment that the, kind of, spinner lands on, we could also calculate every time that spinner goes over a segment, we could fire a piece of haptic feedback, for example, and that, you know, that would be a really nice extension in there as well. But yeah, if we don't have any other questions or anything like that, I feel like one thing we haven't done is adding, adding in any contact information for us, because I think it would be great to, yeah, hear any thoughts on how, how everyone got on or, yeah, any other ideas around what we could be building or, yeah, just, like, nice bits to have. Yeah. Alan, any other final bits? No, I think you covered everything perfectly well. Awesome. Sweet. Well, yeah, thanks, everybody. I think we've got about an hour, so yeah, thank you so much for everybody who turned up. I hope that was, like, I guess, interesting or enjoyable and okay to follow, especially if you've never worked with React Native before. And yeah, like, hopefully hear from you all in the future. That'd be great. All right.

Watch more workshops on topic

React Summit 2022React Summit 2022
117 min
Detox 101: How to write stable end-to-end tests for your React Native application
Compared to unit testing, end-to-end testing aims to interact with your application just like a real user. And as we all know it can be pretty challenging. Especially when we talk about Mobile applications.
Tests rely on many conditions and are considered to be slow and flaky. On the other hand - end-to-end tests can give the greatest confidence that your app is working. And if done right - can become an amazing tool for boosting developer velocity.
Detox is a gray-box end-to-end testing framework for mobile apps. Developed by Wix to solve the problem of slowness and flakiness and used by React Native itself as its E2E testing tool.
Join me on this workshop to learn how to make your mobile end-to-end tests with Detox rock.
Prerequisites- iOS/Android: MacOS Catalina or newer- Android only: Linux- Install before the workshop
React Advanced Conference 2022React Advanced Conference 2022
81 min
Introducing FlashList: Let's build a performant React Native list all together
In this workshop you’ll learn why we created FlashList at Shopify and how you can use it in your code today. We will show you how to take a list that is not performant in FlatList and make it performant using FlashList with minimum effort. We will use tools like Flipper, our own benchmarking code, and teach you how the FlashList API can cover more complex use cases and still keep a top-notch performance.You will know:- Quick presentation about what FlashList, why we built, etc.- Migrating from FlatList to FlashList- Teaching how to write a performant list- Utilizing the tools provided by FlashList library (mainly the useBenchmark hook)- Using the Flipper plugins (flame graph, our lists profiler, UI & JS FPS profiler, etc.)- Optimizing performance of FlashList by using more advanced props like `getType`- 5-6 sample tasks where we’ll uncover and fix issues together- Q&A with Shopify team
React Advanced Conference 2023React Advanced Conference 2023
159 min
Effective Detox Testing
So you’ve gotten Detox set up to test your React Native application. Good work! But you aren’t done yet: there are still a lot of questions you need to answer. How many tests do you write? When and where do you run them? How do you ensure there is test data available? What do you do about parts of your app that use mobile APIs that are difficult to automate? You could sink a lot of effort into these things—is the payoff worth it?
In this three-hour workshop we’ll address these questions by discussing how to integrate Detox into your development workflow. You’ll walk away with the skills and information you need to make Detox testing a natural and productive part of day-to-day development.
Table of contents:
- Deciding what to test with Detox vs React Native Testing Library vs manual testing- Setting up a fake API layer for testing- Getting Detox running on CI on GitHub Actions for free- Deciding how much of your app to test with Detox: a sliding scale- Fitting Detox into you local development workflow
- Familiarity with building applications with React Native- Basic experience with Detox- Machine setup: a working React Native CLI development environment including either Xcode or Android Studio
React Summit 2023React Summit 2023
88 min
Deploying React Native Apps in the Cloud
Deploying React Native apps manually on a local machine can be complex. The differences between Android and iOS require developers to use specific tools and processes for each platform, including hardware requirements for iOS. Manual deployments also make it difficult to manage signing credentials, environment configurations, track releases, and to collaborate as a team.
Appflow is the cloud mobile DevOps platform built by Ionic. Using a service like Appflow to build React Native apps not only provides access to powerful computing resources, it can simplify the deployment process by providing a centralized environment for managing and distributing your app to multiple platforms. This can save time and resources, enable collaboration, as well as improve the overall reliability and scalability of an app.
In this workshop, you’ll deploy a React Native application for delivery to Android and iOS test devices using Appflow. You’ll also learn the steps for publishing to Google Play and Apple App Stores. No previous experience with deploying native applications is required, and you’ll come away with a deeper understanding of the mobile deployment process and best practices for how to use a cloud mobile DevOps platform to ship quickly at scale.
React Advanced Conference 2022React Advanced Conference 2022
131 min
Introduction to React Native Testing Library
Are you satisfied with your test suites? If you said no, you’re not alone—most developers aren’t. And testing in React Native is harder than on most platforms. How can you write JavaScript tests when the JS and native code are so intertwined? And what in the world are you supposed to do about that persistent act() warning? Faced with these challenges, some teams are never able to make any progress testing their React Native app, and others end up with tests that don’t seem to help and only take extra time to maintain.
But it doesn’t have to be this way. React Native Testing Library (RNTL) is a great library for component testing, and with the right mental model you can use it to implement tests that are low-cost and high-value. In this three-hour workshop you’ll learn the tools, techniques, and principles you need to implement tests that will help you ship your React Native app with confidence. You’ll walk away with a clear vision for the goal of your component tests and with techniques that will help you address any obstacle that gets in the way of that will know:- The different kinds React Native tests, and where component tests fit in- A mental model for thinking about the inputs and outputs of the components you test- Options for selecting text, image, and native code elements to verify and interact with them- The value of mocks and why they shouldn’t be avoided- The challenges with asynchrony in RNTL tests and how to handle them- Options for handling native functions and components in your JavaScript tests
Prerequisites:- Familiarity with building applications with React Native- Basic experience writing automated tests with Jest or another unit testing framework- You do not need any experience with React Native Testing Library- Machine setup: Node 16.x or 18.x, Yarn, be able to successfully create and run a new Expo app following the instructions on
Vue.js London Live 2021Vue.js London Live 2021
89 min
Building for Web and Native with Ionic & Vue
When building an app, there are many options choices developers need to make. Is it a web app? Does need to be a native app? What should I use for UI? In this workshop will look at how to make use of Ionic for building your app and how to deploy it to not only the web, but native as well.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

React Advanced Conference 2023React Advanced Conference 2023
29 min
Raising the Bar: Our Journey Making React Native a Preferred Choice
At Microsoft, we're committed to providing our teams with the best tools and technologies to build high-quality mobile applications. React Native has long been a preferred choice for its high performance and great user experience, but getting stakeholders on board can be a challenge. In this talk, we will share our journey of making React Native a preferred choice for stakeholders who prioritize ease of integration and developer experience. We'll discuss the specific strategies we used to achieve our goal and the results we achieved.
React Finland 2021React Finland 2021
27 min
Opensource Documentation—Tales from React and React Native
Documentation is often your community's first point of contact with your project and their daily companion at work. So why is documentation the last thing that gets done, and how can we do it better? This talk shares how important documentation is for React and React Native and how you can invest in or contribute to making your favourite project's docs to build a thriving community
React Day Berlin 2023React Day Berlin 2023
29 min
Bringing React Server Components to React Native
React Server Components are new topic in community, bunch of frameworks are implementing them, people are discussing around this topic. But what if we could use React Server Components in React Native? And bring all optimisation features that RSC allows to mobile apps? In this talk I would present what we are able to do with RSC in React Native!
React Advanced Conference 2021React Advanced Conference 2021
21 min
Building Cross-Platform Component Libraries for Web and Native with React
Building products for multiple platforms such as web and mobile often requires separate code-based despite most of the components being identical in look and feel. Is there a way where we could use shared React component library on different platforms and save time? In this presentation I'll demonstrate one way to build truly cross-platform component library with a unique approach of using React & React Native in combination.