Flutter Europe: Animations in Flutter done right

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

I really enjoyed this talk in Warsaw by Emily Fortuna and Andrew Fitz Gibbon, on flutter animations. Flutter enables some great animations, for transitions of for animated UI elements and this talk gave some really great practical pointers on the best ways to approach the various use cases. It was also a good primer on the best maths to use for the various effects.

👍︎︎ 7 👤︎︎ u/AndyGas 📅︎︎ Mar 30 2020 🗫︎ replies
Captions
[MUSIC PLAYING] EMILY FORTUNA: All right. I think we're at 1:30. [NON-ENGLISH]. And welcome to Innovations. Welcome to Innovations Done Incorrectly. ANDREW FITZ GIBBON: Incorrectly. Emily, I already know how to do animation incorrectly. I want to learn how to do them correctly. EMILY FORTUNA: Well, you're giving this talk, so. ANDREW FITZ GIBBON: Right. OK. So welcome to Animations Done Right. I'm Fitz. EMILY FORTUNA: I'm Emily. We are both developer advocates on the Flutter team at Google. ANDREW FITZ GIBBON: Yes. So one of the challenges with trying to figure out how to do animations right is there's a lot of options. So I want to do an animation. Do I choose a rotation transition? Do I choose a scale transition? Do I to choose an animated container? What do I choose? I don't know. EMILY FORTUNA: So we are going to be walking through two different parts of our talk. The first part is if you know exactly what sort of animation you want to create and you're just not sure how to implement it using all of those different widgets, how do you choose? The second part is walking through the thought process of creating animations and adding them to your app so that you can know how to-- adding some animations can really elevate the level of professionalism of your app and how thinking of where to add them can really clarify that process. ANDREW FITZ GIBBON: So once you know what the animation should look like, you're on a team with a designer, and you know exactly what you want, what are the next steps? EMILY FORTUNA: Well, we have a couple of questions to work your way through that. So the first question is, is the animation you're envisioning more like a drawing? If the answer is yes, then we recommend you not create your animation purely in Flutter. ANDREW FITZ GIBBON: Are you saying I can't do a dancing penguin in rows, and columns, and boxes? EMILY FORTUNA: That is not, in fact, what I'm saying. I actually can create it. And I have seen people do that. But your life will be much more pleasant if you use tools that help or that are right for the job. And tools that are right for the job for a more drawing-based thing are more drawing based tools, things like things Rive, things like Loddy. So if that's the case, then use a plugin. But if you have an animation that is using more Flutter core layout concepts, things like rows and columns or text styles, or like Flutter parameters, then a pure Flutter code-based animation is what we'll be talking about, such as this example that we saw on [? Marcine ?] yesterday. ANDREW FITZ GIBBON: OK. So when you're doing the pure Flutter kind of animations, there's two different kinds of animations that we're looking at, the implicit animations and our explicit animations. So what's the difference? Well, our explicit animations are the things that we give it a controller and we can tell it when to go. We can tell it how to go. We can tell it how long to go. We control what happens when it happens, everything. On the other side, the implicit animations we are not controlling it as much. We are giving it an end value. And it just kind of takes care of everything. And that's our implicit animations. And this is on our range of easy to hard on creating our own animations. EMILY FORTUNA: It's implicit because when it starts and the process of getting there is defined just by setting that end value rather than that controller saying it's time to start. ANDREW FITZ GIBBON: So we have more questions though, because just knowing implicit versus explicit is kind of a hard decision. And so we want to figure out how to make that decision. So first off, EMILY FORTUNA: You should ask yourself, does my animation repeat forever? Is it going for the length of your app running or is it repeating while a certain condition is true? If the answer is yes, then you want to use an explicit animation. The second question you can ask yourself, is my animation discontinuous? What I mean by that is if you look at that middle animated circle here, you see the circle is growing from small to large and then small to large. It never goes small, large, large, small. So the value of circle size is discontinuous. It's jumping from that big size back down to the small size again. And so if that's the case, then again explicit animation is what you would need. And then the last question to ask yourself is, are there multiple widgets that I'm animating together? So on the far right, you can see there's a bunch of squares that are kind of animating in and out in tandem. And that is done by using an animation controller that can orchestrate how each of those squares goes in at different points. So again, if you have multiple widgets that are all connected, explicit animation is for you. But if you answered no to all those questions, then you can use an implicit animation. ANDREW FITZ GIBBON: All right. So now we've decided whether we're using implicit versus explicit. Next question we want to ask is, is there a built-in widget for what you want to do? And often the answer is yes. Choose a property of a widget that you want to animate, and there's likely a built-in for it. So whether you're rotating it, whether changing the size, or changing your color and opacity, all of these things already exist. And they're nice and easy to use for the most part. And so the general idea there is try the easiest and the simplest thing first. We don't want to preemptively make our lives difficult by making a custom painter that is animating every single pixel on every single frame. That's going to be a bit hard. So try to do the simplest thing first. EMILY FORTUNA: So we've got this sort of difficulty scale here with the implicit on the far end because there's fewer things to manage. You don't have to manage that controller object, which is separate. You have to control constructing it and disposing it. And then you have Tween animation builder as the next step followed by the explicit animations and so on. ANDREW FITZ GIBBON: OK. So we've walked through a bunch of theory, a bunch of questions. What's the next step for actually trying to do this? EMILY FORTUNA: Right. So let us do some coding, and apply these questions, and see how it works. So now we're moving into the second part of our talk of also like I have an app and I want to make it look nicer. But I'm just not really sure how. And we're going to show by adding only animations, not adding/changing a layout or anything like that. You can make it look a lot nicer. ANDREW FITZ GIBBON: And we're using the basis of this app as one of the apps from "The Boring Show." And this is a very professionally done app written mostly by a puppet. EMILY FORTUNA: Not professionally. ANDREW FITZ GIBBON: It's really an in progress app though. And there's some rough edges. And it also doesn't have really any animations in it already. So we thought it would be a good candidate for adding some life to it. EMILY FORTUNA: So if you are not familiar with "The Boring Show," DashCast is a podcasting app. And as Fitz mentioned, it's in the relatively early stages, because right now you can only listen to one podcast. But again, we're showing how animations can take a pretty basic looking app and make it look nicer. ANDREW FITZ GIBBON: OK. So let's start looking through the app first. Here on the right, we have an initial version of the app running. And you can see it's our basic list view with a bunch of list tiles. And in fact, our list tile is there with the text for our title and our subtitle, et cetera. EMILY FORTUNA: And before we go in, I just want to check with everyone. Is our font size large enough? Shall we up it? It's good. OK. ANDREW FITZ GIBBON: OK. Great. You'll notice a couple things throughout here. We're using our provider for various things related to state management in this app. In particular, we're using it for the episode status, and the playback status, and a couple other things. We'll see those come up again. FORTUNA: Yeah. Provider provides all the information of the podcast itself and whether we've downloaded it and someone. ANDREW FITZ GIBBON: Yep, and speaking of downloads, we can click on a button, and we get a nice snack bar at the bottom telling us we're downloading. We can click on an episode, go into it. We can play it. EMILY FORTUNA: And just again, emphasizing, this is an app that is a work in progress. ANDREW FITZ GIBBON: Yes. EMILY FORTUNA: Pretty basic. ANDREW FITZ GIBBON: And so even the basic things like the play button going just straight from a play to a pause and then straight from pause to a play and back, like, that's all it's doing. EMILY FORTUNA: It is playing the audio. We turned the audio down. ANDREW FITZ GIBBON: Yes. OK, so let's start on this list page. It's kind of-- it's just what it is. EMILY FORTUNA: Right. ANDREW FITZ GIBBON: What should we do first? EMILY FORTUNA: So right now when you download, the download button goes away because you have downloaded it, but it would be nice to know the download progress. And so you could do something like adding a progress bar. I had the idea of adding-- first of all, once this app becomes more fully featured, we want to-- you'll have multiple podcasts, and you'll have multiple images related with each podcast. So we could put an image next to each list tile to tell you which podcast it's from. And when it is downloading, we could start with it semitransparent before it's downloaded. And once it's downloaded, you can make it hopefully opaque. So we could have it update showing your image fading into view. And this is a imprecise way of showing download status, but the user doesn't need to know the exact percentage of your download. You just need to see that it is progressing. ANDREW FITZ GIBBON: So we've kind of given us a little bit of a starting point here already to work from. So we can see we've already added the image there as the background to the download button. And in fact, we've already implemented the opacity there. Again, this is done with one of our-- well, actually, let's get to the questions first. EMILY FORTUNA: Well-- and OK. Yes, so in terms of asking our questions for how we should implement this. First up, is it a drawing? ANDREW FITZ GIBBON: No, it's just changing that opacity layer on something. Not a drawing. EMILY FORTUNA: All right. Second up is does it repeat or is it discontinuous? ANDREW FITZ GIBBON: No, it just kind of goes from zero to fully opaque, and then it's done. EMILY FORTUNA: Great. So we're in implicit animation territory. And then the last question, "Is there a built in for it?" ANDREW FITZ GIBBON: Yes, yes, there is a built in for it, and that is simply animated opacity. EMILY FORTUNA: And that is why we've already coded this up because we want to get to the interesting stuff where there aren't built ins. We'll live code that part. ANDREW FITZ GIBBON: Yes. EMILY FORTUNA: But first the code for this. ANDREW FITZ GIBBON: First the code for animator opacity. You can see here that within this build method for the image, the leading image of our podcast, we just have the animated opacity taking the child, which is the thing that it's changing the opacity of. EMILY FORTUNA: If you attended Philip's performance talk yesterday, you may recall about how you don't want to rebuild all parts of your sub-tree if it's not changing. And in this case, the only thing that's changing is that opacity overlay. The child, which is the image is consistent the whole way through. So that's why we had that child down below. And that part stays. This is only built once, and then the opacity gets built as we get download progress. ANDREW FITZ GIBBON: Yep. And so we're basing the opacity on the download progress. And so we're doing a little bit of math to make sure that we start at something that's kind of there. EMILY FORTUNA: Like how do we get that download process? ANDREW FITZ GIBBON: Ah, yes. Well, that's coming from our provider. EMILY FORTUNA: Which is here you can see we're consuming the episode which gives us updates on the percent downloaded. ANDREW FITZ GIBBON: Right. And so you could look at this and say, well, every time the episode downloads, status is updated. Since we're using Provider, this builder is gonna be called. And we could just set the animated-- the opacity based on that. So why aren't we? EMILY FORTUNA: Well, we're using a little bit of extra mass which you can scroll down to show. Just because we're starting with the image slightly visible so we have a default opacity of 50% and then we just make it so that when you're not at 85% capacity, it doesn't show that it's 100%. And so I want to just review-- do a quick review. Animate opacity is a implicit animation. Implicit animations usually are in the form AnimatedFoo, where "Foo" is the property that you are animating. In this case, we're animating opacity. ANDREW FITZ GIBBON: Yep. And so animated opacity is doing something for us nicely here as part of the consumer builder which is giving us a smooth transition between different opacity levels. And so we could just set the opacity straight, but then it'd be potentially disjointed. EMILY FORTUNA: Yeah, since we don't know the granularity that consumer is giving us updates on downloads, if we just use a pure opacity, it could be quick jumps in the opacity as Fitz said. All, right so we've got that. Let us now-- one other thing we can add for animations is we're looking at the user actions. We want to go to the next page or to the page of the episode. ANDREW FITZ GIBBON: Yes there's a hugely underrated widget that we could use here, referencing last night-- EMILY FORTUNA: Some might say the most underrated. ANDREW FITZ GIBBON: The most, yes. And so we have this transition here, and for every single episode, it's about the same transition, right? It's just that default page transition. And so we could override the entire thing, right? EMILY FORTUNA: Yeah, so there if you use Page Wrap Builder, you can overwrite it and create a very custom in page animation. Another really easy way is to add a hero. Because here, we've got an image on the side here and the same podcast image on the full page. So all you've got to do is wrap that child in a hero. You specify a tag to uniquely identify that image to connect it to the image on the new page, so Flutter knows what you're intimating. And then you set it on the other page as well. And then you're good to go. So now the user has an indication, as they are transitioning to the new page, of the actual podcast, the particular episode that they're going to be listening to. So it's nice to just give another visual indication of what they're doing. ANDREW FITZ GIBBON: Yes. And speaking of visual indications, I feel like we're not quite done with this page yet, because when I was watching that opacity come up for the download, I feel like I missed it. I was doing other things and trying to pay attention to what we were saying, and I missed the download. EMILY FORTUNA: So yeah, so really, when a download is complete is what you're most interested in. And I had the idea of having a little more of a indication on, for each episode, once you've downloaded it, when it's complete. And the visual indication would be making each list tile jump up just a little bit. Not anything huge, but just a little bounce. ANDREW FITZ GIBBON: Yeah, just a little jump up. EMILY FORTUNA: So asking our questions. First of all, is it a drawing? No. ANDREW FITZ GIBBON: No. EMILY FORTUNA: Does it repeat or go on forever? ANDREW FITZ GIBBON: No, it kind of just ends once the animation is done. EMILY FORTUNA: Right. So we're still in implicit animation world. And then, lastly, is there a built-in for a wiggle jump animation? ANDREW FITZ GIBBON: Elevated wiggle or something like that? Yeah, no, I don't think there's a built-in for that. EMILY FORTUNA: So that puts us in the realm of TweenAnimationBuilder. This is for when you have an implicit animation, but you do not have a built-in animation widget for the jump. So let's code that up. ANDREW FITZ GIBBON: OK. So again, we've kind of started a-- given us, ourselves, a starting point here. And we want to take that entire list tile, and that's what we want to have bounce a little bit. And we're going to wrap it in our custom widget, which we're calling AlertWiggle, in this case, just to give us a little wiggle alert when things finish. So we'll wrap that, and we'll go over to Alert Wiggle. Now, so far, Alert Wiggle is just a stateless widget. We have our consumer there, again, provider everywhere. But it's just returning the child. So-- EMILY FORTUNA: Right, so it's currently just returning that list tile. So we're not doing any animations at all. And before we code this up, let's think a little bit about what we are coding. So what we need to make this animation is we want both positive and negative values-- so to move our widget up a little bit, to move it down a little bit. And we want a continuous function to get us that value so we're not randomly jumping from new location to new location. Now, what mathematical function might satisfy those two qualities? AUDIENCE: [INAUDIBLE] EMILY FORTUNA: Sine wave! I heard it. So if you're like me and need a little refresher on trigonometry, a sine wave is a function that goes from negative 1 to 1, and it starts at 0, goes positive, goes negative. And the rate at which, or the distance between when that up and down movement starts repeating itself is 2pi. We'll get to more details as we go. So we're going to use a sine wave to calculate our offset for how much we should go up and how much we should go down. And it has the nice added property of an easing up at that top and easing up and down. So it's not just purely linear to the position we want, giving it a little bit of a more natural feel. So back to the code. ANDREW FITZ GIBBON: All right, so we've got this nice to-do here that's telling us what to do. And we're just going to start with wrapping that child in a tween animation builder. So there's a couple things happening here. We've got our duration, which is our duration. Then-- EMILY FORTUNA: Yes, so we want-- we're having our duration short because, again, we don't want to annoy the user. It's just a small visual indication. And then, [? between ?] is we're saying, what are the values that we want to animate between? I currently have this between 0 and 1, although I mentioned this whole 2pi thing, so we're probably going to change that in a minute. And then we've got the builder, which is where the animation action happens. Currently, we're just returning a child again, so we're just returning that list tile. So instead, what we want to use is we want to translate that widget up a little bit and then move it back down. So we have that transform widget, and what we're doing to calculate that offset is we're just using sine. So we get this value from [INAUDIBLE] animation builder, currently between 0 and 1. And we calculate an offset. And as you may recall, its sized between negative 1 and 1. So we're also multiplying it by 2, just so the wiggle is a little bit bigger, a little bit more obvious. OK, so we've set this, but we're not making this animation happen in response to when the download is complete. That's when we want the animation to happen. So to do that, we have this consumer again to check our download status. And we're checking how much is downloaded. And when the download is complete, we set that n value to the period of sine. Now, we're not using n value. So let's set n value to that end in the tween. So as you can see, at the class initialization-- scroll up just a little bit-- you see n value is initialized at zero. And then, when the download is complete, we set it to 2pi. So we do that wiggle. So let's see that in action. ANDREW FITZ GIBBON: All right, hit the Download button, and then wait for it to finish. And then-- I did save, didn't I? AUDIENCE: [INAUDIBLE] EMILY FORTUNA: Oh, yeah. Main looks like there's got a change. You didn't save main. Thank you. There it goes. So do we see it? Do we see the wiggle? ANDREW FITZ GIBBON: It did a little bit. There it is. EMILY FORTUNA: OK, so-- ANDREW FITZ GIBBON: OK. So it's really subtle, though. I had a vision of it kind of bouncing up. And to do that, we might want to add a shadow. So I'm thinking of what kind of-- there's actually a widget built in that gives you a nice drop shadow, and that's the material widget. EMILY FORTUNA: So let's go back to our TweenAnimationBuilder. And inside that child, we're checking-- the material has this notion of elevation. And so we're saying, when our value is animating, when it's not the start or end value, we give it an elevation of three arbitrarily. All right, so now let's see that. And we should see-- oh, there it went. ANDREW FITZ GIBBON: There they all went. I guess they're all finished downloading. So we get our nice little elevation wiggle. There it goes. EMILY FORTUNA: There it is. Cool, so now we've got a small little visual indication on there. I feel like we've done pretty much everything we can do based on user actions on this page. ANDREW FITZ GIBBON: Correct. EMILY FORTUNA: So let's move to the individual podcast page. ANDREW FITZ GIBBON: Right. So let's look at one of these. There's not a ton going on here, but there's one animation we've already implemented for us. And I mentioned that Play/Pause earlier. Now, this one's pretty simple. I hit Play, and it does a nice little animation over to the Pause button, and I hit Pause, and it comes back. Very nice. So let's look at what's going on there. I go into our player code. And here, we have our player buttons with our Rewind, our Play, and our Fast Forward. And here, we're just using an animated icon. So as Emily mentioned earlier, our implicit widgets are nicely named AnimatedFoo, where Foo is the thing you're animating. AnimatedIcon is an exception to this. And it's an exception because you can see here, as the progress parameter, we're passing an animation controller. This is one of our indications that this is going to be an explicit animation. And so we're doing this for the animated icon because it gives us this nice ability to just tell it to go forward and then tell to go backwards in order to go from Play to Pause and Pause to Play and back again. So you can see that in the onPressed, where we're listening for the Play status and reversing or forwarding as appropriate. OK, so-- EMILY FORTUNA: So now it's playing. ANDREW FITZ GIBBON: Yes. EMILY FORTUNA: But it'd be nice if we had some more visual indication that it is playing, because if we don't have the sound on very much, we don't know if it's actually doing anything. ANDREW FITZ GIBBON: Right. And for some episodes, they're really long. And so the progress bar is moving, but it's moving very slowly. And I have no idea if it's actually playing. EMILY FORTUNA: So we thought it might be good to make an animation kind of like audio, something suggesting sound movement, recording sound waves. ANDREW FITZ GIBBON: Yep, exactly. EMILY FORTUNA: And just want to take a step back for a second. One thing I forgot to mention is I'm finding sine everywhere in animations. You have all of these animations are using sine. This is from the Flutter Spinkit package. And a lot of these are using it with explicit animations to control how the offset of when different animations coordinate together. But yeah, sine is a good place to start with the animations. ANDREW FITZ GIBBON: And in fact, we went searching through the internet for inspiration. And it's the internet, so there's many things inspiration on there. And sure enough, our friend the sine wave came back again. So it really is everywhere. And so I was looking at this play page, and there's that little gap of space in between the description and the image. And so I thought it would be nice to add a little indication of something playing with a little sine wave animating to the right as the play is happening. So what do we need? A couple things. We need to be able to draw a sine wave, and we need to be able to wiggle it to the right while it's playing. So we ask our questions. EMILY FORTUNA: Is it a drawing? ANDREW FITZ GIBBON: Is it a drawing? No, it's just a sine wave. EMILY FORTUNA: Does it repeat forever? ANDREW FITZ GIBBON: Yeah, actually, while the podcast is playing, it does repeat. EMILY FORTUNA: Yeah, so while a certain condition is true, we are repeating forever. And that puts us in the realm of explicit animations. So lastly, do we have a built-in for making a sine wave animation? ANDREW FITZ GIBBON: So like the wiggle to the right sine wave animation? No, we don't. So there's nothing built in. We need to create our own. And that puts us squarely into our custom explicit animations, with either AnimatedWidget or AnimatedBuilder. And we'll briefly note that the difference between these two is that with AnimatedWidget, it's a nice thing to use if you have your animation mostly self-contained. And it can just be a drop-in for some widget that you want to be animated. On the other side, with AnimatedBuilder, if you're a little bit more tied to things around it, then you probably want to use AnimatedBuilder. OK, now I'm going to take a brief detour into what are explicit animations. So I mentioned the animated icon is a little bit of an exception on our naming scheme, and that's because of this animation controller. So when we look at the documentation, the animation controller is really just an animation object, right? So what is that? So an animation is really just a progression of images that slightly change on each one, right? So it's just little minuscule changes on every single frame. And when we play them back fast enough, we get a nice little movie. So we have this animation object. The animation object is an abstract object that has three things. It has a status, so whether we're running, whether we're dismissed, whether we're going backwards, whether it's completed, et cetera. We have our value-- so our current state on that 0 to 2pi range, for example. And then a set of listeners that we can notify when that value changes. So the animation controller is really just an implementation of that where we add some control. OK, so what is it actually doing? Well, we get that control. We can tell it when to start or when to end. And once the animation controller receives that, it will update the status-- because, again, that's one of our three things in the animation. And then we wait for a new frame. And we also call that a tick. We'll come back to that later. Once we receive a new frame, we update the value, which is a function of our duration, our lower and upper bound, how long it's been since the last frame, et cetera. And then we notify all of our listeners, and we update our status again if we need to-- for example, if we were asked to stop or we reached the final value. OK, so that's our brief detour into what are explicit animations, what brought us here. We just need to have an animation that starts and stops on demand and moves our wave slightly to the right. OK, I'm going to drop into the code. Let's take a look at what that-- how we actually implement that. So if we scroll to the top of this, we have our episode image here, which is that top little thing there. And here, you can see the other side of that Hero widget that we implemented earlier, where it really is just that one line. We're saying that this image has the same tag as the one from the ListView, and it nicely does the transition for us. We also have this animated opacity making another return. This is what lets us nicely fade in or nicely fade out when the play is going. And we're tying that to the play status. So like the other one where we were tying to the download status, here we're just saying, if we're playing, make it opaque. If we're not, then it's transparent. EMILY FORTUNA: All right, but I'm not seeing anything yet when I hit play. ANDREW FITZ GIBBON: Yeah, so there's nothing really happening yet, so let's drop into this Wave thing. So right now, Wave is just a stateful widget. There's not a ton going on there. We take the size and we move on. Within the actual state object, we have our controller, where we create it in init state and we dispose of it in dispose. And here, when we initialize that animation controller, we set our duration to whatever it needs to be. And since we're using our sine wave again, this is where our 2pi comes back. By default, the upper bound is just one, and to give you like a nice percentage of the animation complete, we're overriding that to 2pi. Then there's this VSync parameter. So you notice we're passing this, and we've done something special with the state object, which is to pass it or mix in a single ticker provider state mix-in. All right, I had to practice saying that really fast because it's a bit of a mouthful. But all it's doing is saying that this object is waiting for new frames to come in. EMILY FORTUNA: So it is when this particular widget is visual, it is listening for new frames. And we're connecting those two by passing it in to our controller. ANDREW FITZ GIBBON: So remember, the controller, one of the things it's doing is waiting for new frames. By passing this in, that's what allows it to do that. OK, so let's check out our build method here. This is why it's not doing anything. We're just returning an empty container. EMILY FORTUNA: Boring. ANDREW FITZ GIBBON: So let's fix that. While Emily's typing our code, we can see that we're consuming the play status again. So we can know when to start the animation versus not. And again, this is one of the helpful things about the controller, is that we can just tell it to repeat forever, and it will just repeat forever. OK, so we've added our animation builder here, and we've given it the controller. Really, another way to think about the controller is that it is a thing that emits values. So we need something to pick up those values, and the animation builder is one of those things. OK. EMILY FORTUNA: So inside our child, we have this blue gradient, which is literally just a rectangle that is a gradient and is blue. And then we are clipping it to make it look like a different shape-- (WHISPERING) like a sine wave. ANDREW FITZ GIBBON: (WHISPERING) Oh, my gosh. EMILY FORTUNA: And how do we do it? Let's look in Wave Clipper. ANDREW FITZ GIBBON: Yes. So Wave Clipper is a custom Clipper. And the critical thing about it is it returns a path. And so ClipPath is going to constrain the visible area of whatever it is to whatever path we give it. You can see at the bottom, the last three lines are creating that bottom three edges of our box. EMILY FORTUNA: And the top one is very, very tiny sine wave, if you look very closely. ANDREW FITZ GIBBON: Yes, you have to. I can't even see it from here. You have to go real, real close to look at it. And what we're doing there is, path does not give us a Create Sine Wave function. So we are manually setting all of the individual points for the sine wave along the top and adding it as a polygon along that edge. EMILY FORTUNA: So let's look at that sine wave. ANDREW FITZ GIBBON: Yeah. EMILY FORTUNA: All we're doing is we're getting the width of our screen here, and for each point along the width, we calculate sine. And then we make a point and stick it in. So as I mentioned, sine is negative 1 to 1. It's pretty small. We can make it taller by adding, by multiplying that value-- so add amplitude. ANDREW FITZ GIBBON: OK, so that's a little bit better, but I'm sure it's probably hard to see still for most people, probably even in the back of the room. I'm sure it's bigger up there, but I can't-- I can barely see it here. EMILY FORTUNA: Yeah, it's really skinny. So we want to make it wider. And to determine what to do here, we're going to consult our math books again. ANDREW FITZ GIBBON: We're going to put our math professor hats on now. EMILY FORTUNA: So here's the [INAUDIBLE] taller. What we want to do is, we found that if you add a coefficient to x that is less than 1, you make your sine wave wider. And if you multiply it by a number larger than 1, you make it narrower, the period shorter. So in our cases, we want to make it wider. We're going to add something. Let's divide by 4. ANDREW FITZ GIBBON: All right, OK so that's a little bit bitter. It's starting to look a little like a sine wave, but the top got cut off. What else can we do with our sine wave to fix that? EMILY FORTUNA: Yeah, so again, if you just add a constant to whatever value you're getting, you can shift that sine wave up or down. So we will just add a constant to that sum, conveniently named y offset. ANDREW FITZ GIBBON: All right, so that moved it down. So we'll note here that computer pixel math is a little bit different, and 0 0-- EMILY FORTUNA: A little different from math math. ANDREW FITZ GIBBON: What? EMILY FORTUNA: Math math coordinates are. ANDREW FITZ GIBBON: Yes, to think-- computer math different than math math! And top left is going to be our 0, 0, and then bottom right is going to be our positive x, y. And so moving up in this case is actually moving down. EMILY FORTUNA: All right, so we've got a sine wave, but it's not moving. ANDREW FITZ GIBBON: No, it's not moving. But I recall from when we did our tween animation builder, we called sine wave with our animation controller value. EMILY FORTUNA: Yeah, so we pass in the animation controller value to our clipper, but we're not doing anything with it. So first thing you might think to do is just stick it in here. ANDREW FITZ GIBBON: OK, so it's moving. It's definitely changing. It's animating now. EMILY FORTUNA: So this looks pretty similar to that wiggle animation, probably. And then, if you think about it, you're like, OK, well, what I'm doing is, for the entire width of the screen, I am just calculating the exact same value. I'm not taking advantage of the fact that sine can be different at different points. So again, let's consult our math books for a minute. So if you add a factor to before calculating sine, you can shift the sine wave left or right. So here, we've added pi. We've shifted it to the right a pi distance. And if you subtract, we're moving it slightly to the left. So what we want to do is-- value is changing for each frame, and we want to shift the sine wave a slightly different amount at each point. And that will give us the illusion of the sine wave moving. So we're going to add that to what we had originally. So we've got x/4 plus value. ANDREW FITZ GIBBON: OK, so we're moving nicely to the left now. EMILY FORTUNA: And then, yeah, if we wanted to go to the right, we just shift the sign. ANDREW FITZ GIBBON: Awesome. OK, so if you recall from our original inspiration, it was kind of sound wave-y, right? EMILY FORTUNA: Yeah, this is way too perfect to look like speech. ANDREW FITZ GIBBON: Right, and speech is not perfect. So let's-- EMILY FORTUNA: [INAUDIBLE] random. ANDREW FITZ GIBBON: Right. EMILY FORTUNA: Semi-random. ANDREW FITZ GIBBON: Semi-random. So let's create something semi-random. EMILY FORTUNA: So let's throw out that whole sine thing. ANDREW FITZ GIBBON: Yeah, just throw it all out. And so the first thing we do is we set our baseline for where all those points on that polygon are. So let's reset those to something random so we have some place to start from. EMILY FORTUNA: Oops, not that. ANDREW FITZ GIBBON: And what we're going to do is, for each point along the top edge of that container, we're going to set it to some random number between 0 and approximately 80% of the height of that container. EMILY FORTUNA: All right, so we're just setting this with random values within a certain range. Cool, so now we'd say-- I haven't hit Save yet, but we've got a random initialized set of values. But we're not going to do anything with those. How do we update them? ANDREW FITZ GIBBON: Right. So if we look back at our ClipPath function, we're still making a sine wave. Instead of making a sine wave, let's take those random points and modulate them a little randomly so that things move a little nicely like a sound wave. So what we're doing here is, again, going for each point along the top edge of that container and getting a new random value, but within a certain range so that we don't get random noise. Let's get, actually, just a little bit of a wiggle. EMILY FORTUNA: Yeah, so we take-- we have these random points, and we're shifting them just a small amount so it's not complete chaos. I'm going to do-- and there you have it. We've got our points-- ANDREW FITZ GIBBON: Nice little sine wave. EMILY FORTUNA: --bouncing up and down. [APPLAUSE] And just to prove that you don't want random noise, I'll just show you what that would look like if I just take this NextDouble. I'll multiply it by the height, size of height. Aargh. ANDREW FITZ GIBBON: That's why we control how much it moves by. That noise is a little-- I don't feel calm by that podcast playing. But this one I feel OK with. EMILY FORTUNA: All right, great. So we've added a collection of animations. Let's review. So we talked a little bit about the set of questions you need to ask yourself to determine how to code up the animation that you are envisioning, whether you're working with a designer or you just know what you want. And then we talked about the process of taking an app, and you're like, I want to make it look nice, but how? So to review, the questions. Is your animation like a drawing? If yes, probably use a plug-in. In fact, there's a talk just, I think, this afternoon about using Rive. Determining whether-- so if you're determining you want to use Flutter properly to code it up, then yeah, the next step is, should I use implicit or explicit? And there's three questions. Does my animation repeat forever? Is it discontinuous, or are there multiple widgets that are all animating that I need to coordinate together? And then, the last question is, should I write my own, or is there a widget for it? And obviously, don't reinvent the wheel if you don't have to. And at the bottom, we've got our little difficulty scale of all your animation options. And then, for our app, we added these five animations. ANDREW FITZ GIBBON: Yeah, and so, truly, our inspiration for this was looking through what actions the user is going to take as part of our app and gently adding in animations to them. So we added some download progress and a nice little animated opacity. We added some Heroes. We added an indication of done, et cetera. And they're all related almost exactly to what users are going to do and want. And so that's really our guidance for how to come up with these ideas for animations. First, look at what your users are doing. Second, emulate the physical world when possible to make it feel like it's coming up, it's coming down. You tap on something, it reacts. You have that sound wave to indicate that sound is playing. And usually, generally, subtle and short is good. So if you remember from our alert wiggle that it lasted just for a half a second or so, and then it was done. It was out of the way. We could have very nicely made everything go wild and crazy and jump up and down across the whole screen, but we kept a subtle, and that was much nicer. Finally-- EMILY FORTUNA: Go ahead. ANDREW FITZ GIBBON: --sine wave is everywhere. EMILY FORTUNA: It's a good place to start. So in summary, thank you all for your attention. If you would like to check out the code, you can scan that QR code. Hopefully it's large enough. Or, that is the same website that the QR code takes you to. ANDREW FITZ GIBBON: Right. EMILY FORTUNA: And we'll happily answer questions, probably after, because I know we don't have a lot of time left. So thank you all. [APPLAUSE] [MUSIC PLAYING]
Info
Channel: Flutter
Views: 40,354
Rating: undefined out of 5
Keywords: Flutter animations, animation widgets, widgets for animation, animations in Flutter, make animations in Flutter, how to make a Flutter animation, animate your app, tweenanimationbuilder, coding an animation, animations done right, Flutter, developer advocate, Emily Fortuna, Andrew Fitz Gibbon, GDS: Yes;
Id: wnARLByOtKA
Channel Id: undefined
Length: 42min 4sec (2524 seconds)
Published: Mon Mar 30 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.