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


- 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


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, yeah, something that we found to be a 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 competities, 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 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. We can both kind of jump out and help anyone or happy to answer any questions along the way as well. So cool. 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 got 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 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 there to drive to their work. They lose their job. They're spiraling today. 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 the 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 fix it themselves. And yeah, one of the kind of things that we looked into alongside the automatic savings and roundups that we'd already kind of built out was the idea of gamified savings or prize-linked savings. And this was something, it's not a new idea. And I've actually linked a couple of articles and papers around this. But 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 fun. 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 you to save more and build up that safety net. So that's a 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 get a big reward, like an idea. Like one of the things that really demonstrates that is, I guess, if you think about 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, 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, we were just trying to get this out and seeing if it was an engaging feature to start with. But yeah, let's, 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, we can answer to any of those. Cool. So getting started, we're going to use the expo or 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 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 demo a quick 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 kind of get getting started app. If you've never used read expo before, you can install the CLI using this script. And then yeah, clone the repo and install dependencies and run expo start to to kick it off. You should then I think with after expo started, I think you can hit the I key if you're on a Mac and it will spin up a an iOS simulator locally. Or you can hit the W key and it will open up in the web in the web page. And you can develop it there. So yeah. Yeah, I'll copy the links in chat. Sorry. So yeah, so this the slides are 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 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 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 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 this is what we 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 I guess tap and hold the wheel, the kind of the spinning wheel. And then you're going to we're going to want to move it with your 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 to that image as you move your finger, which you can kind of, I guess, see at this stage of the game. 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 though we want to be able to detect when a user drag. 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, I'm sorry. So cool. Yeah, there's links 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, that image. And as I mentioned before, we're going to use the pan responder in the library to do that. So 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 it's 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 connect it to the gestures that the user is making. And that way we can connect it to the rotation of the actual component, as you'll see. Yeah. Yeah, cool. So yeah, I think that like made it click for me as well. 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 component that we attach the pan responder to actually receives the callbacks and it doesn't bubble up or down, depending 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 the movement actually starts. So on pan responder move, 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 kind of handler to. So I guess the way we can check that is by kind of writing this callback. So it takes two arguments. The first is the kind of the actual event 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. 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. We should be starting to see the console.warn fired when we move the gesture within here. 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 want the gesture state and dot 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 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 kind of movement of the of the thumb. So we can console.log that dy. And this is going to give us the numbers as, oh, I guess, like the number of pixels from where the touch started. And actually, I guess this is like probably a good time to talk about what we're trying to achieve with the 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 Natives 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 a we've got kind of got this bit here, like, I'm not sure I'm even going to be able to write this. 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. It looks good. It's clear. 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 our questions? I think you're doing a great job of explaining. Yeah, I think one thing, the annotation is still on the screen. I think that was actually it. 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? 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. Yeah, good. Thanks. Okay, 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 to drag to when they kind of, I guess, kind of, or 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. 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 like wrap it in a ref so that it's always the same value between lenders. 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 out putting earlier in the console statement. So at this point, when you I mean, everything's going to happen. But when you when you Yeah, when you move your thumb over, tap and drag over the wheel, we're going to be kind of pushing the why that changes why 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 is actually add that rotation to the image. And the way I guess we can we can start to do that is, I guess just 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 the this rotate property by the transform style prop. And you can set this to a certain number of degrees. And you can kind of see that image rotating around as we increase that. So we, what we 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 natives animated kind of library again. The first thing is that we actually have 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 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, that's the first step is just to convert this into an animated 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 this dy is the number of pixels from where gesture started to where the gesture actually ended, or is currently at, we want to map that from like, I guess, a pixel, 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, again, this is going to be kind of passed into the spinner as a rotation style. So 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, I guess exists on the rotate value. No, it's not. It's this is animated. Yes, one was open up. 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 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 spin it to move without 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, that is, I guess, the initial, the initial kind of step that we wanted to do. We've mapped a Y, 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, that I think is kind of interesting is that input range and output range that we specify, those aren't necessarily limits. Those are just specifying the, it's, I guess it's the line, the angle, the steepness of how fast we want the input to affect the output. And, but it doesn't mean that we'll only affect things that are less than one pixel or the D Y that's less than one. So it'll keep going. It's just, it's more defining and aligning. 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 per 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, this is yeah, exactly as Alan mentioned, it's a kind of a ratio mapping. So a value of like what we are 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 yet what you needed from the exact interpolation. But yeah, for us we just, we only need like that linear mapping, which is cool. The other thing you can do is like, you can actually use, you can, you can use some of these, some of the config in here to actually like clamp between them. Yeah. So you could clamp it if you wanted it just to be like anything between zero one goes to zero 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 D Y 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 around or track the gesture round, like past the horizontal and then like go and 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, that first spot. So that's, that's the first thing. And I think there's, there's kind of various ways, I guess, of solving that. And like, yeah, that's definitely something that 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, 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, 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, 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 can do is just as 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, 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 retinated 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 value to zero here, we could actually animate it back to zero in 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 updating this value for us 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 using the native driver, which is like the kind of new performance thing with the animator library. Cool. So we've got our reset button working and that's kind of, yes, bringing 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? Okay, so just I guess kind of going back to 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 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 spinning a wheel, we want, you know, we're going to want to add some momentum in there. 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 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 your 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, 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, right? 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 of your movement when you release your thumb from the screen. So on 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 V y. 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, clicking 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 was moving his mouse at 11 pixel or 80 point 18 1.9 milliseconds, but sorry, pixels per millisecond. So yeah, so that's the kind of the part that that's the unit that we get back as a as this gesture straight dot V y 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 the next thing we're then going to want to do is is to start mapping or come using this velocity, we want to give this animated value that will 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 is 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 of kind of of our gesture. 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 gonna, 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 and 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 keep on spinning and slowly go down to zero. So yeah, we've kind of, I guess we've, we've, we've got a lot of our functionality there, which is really cool. And it's been pretty simple using just, yeah, a combination of the pan responder 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 kind of 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, 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. It stops 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. Shit, it's never going to stop. The bearing's on that. Yeah. And actually, when I was playing around with this before, and I've really bugged it. 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 if 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 velocity to the animation. So when the user releases their thumb or their 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, this is 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, 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 around 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 a 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. 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 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. And yeah, we could, if we want to keep this nice and clean, you can have a kind of like min velocity. And yeah, that just gives us gives us a bit of control over the, yeah, of the kind 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'd 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'd 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, for sure. Yeah, like this is very much like, yeah, first, first implementation. So those 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 can kind of like flash the segment that we land on and have that 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 allow us to do things in the in the Y and X axis 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 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, 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, 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. 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 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 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 up in this, or what we should have is the value that we finish it up in this callback. And then we can, yeah, as I mentioned, use that to calculate the number of segments that starts in. So we're starting in the middle of the segment, we'll be kind of like minus five and plus five, sorry, 36, 32. We'll be minus 18 and plus 18 from the start will be our first segment. So yeah, we can 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. Andrei, 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 worked. Cool. Any other questions? Any other thoughts on like, on, yeah, I guess extensions that we could do here or like a lot of nice bits that happen as well, like feel free to fire them anywhere. But yeah, as I mentioned, like, yeah, there's some nice little libraries such as the confetti one. So, you know, 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 when that velocity is 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, a kind of another dimension to the 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 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 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 any contact information for us, because I think it would be great to hear any thoughts on how everyone got on or, yeah, any other ideas around what we could be building or yeah, just like, nice bits to help. Yeah. Alan, any other final bits? I think you covered everything perfectly well. Awesome. Sweet. Well, yeah. Thanks, everybody. I think we've got a while. 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. Bye.
60 min
10 Jun, 2021

Watch more workshops on topic

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