Implicitly animated widget from scratch (The Boring Flutter Development Show, Ep. 62)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[MUSIC PLAYING] TIYA CHOWDHURY: Welcome back to "The Boring Show." I'm Tiya, and this is my co-host, Craig. CRAIG LABENZ: And we are here today to kind of demystify implicitly animated widgets. We were talking before about what we wanted to make. And one thing that popped into our heads was the idea-- everyone kind of knows the animated container, the animated position. There's a ton of them, whatever all the other ones are. And they're pretty neat, because you just change your value from one frame to the next, probably via setState or whatnot. And the widget kind of evolves. It linearly interpolates from the old value that you passed it to the new value. And we thought, how on Earth do those work? So we're going to build one. And at the end, we'll appreciate how cool the animated container is. And we'll never build another one again. We'll use the animated container. But sometimes, actually, all kidding aside, you may find a thing that you want to animate in one of your widgets, and you'd like to really encapsulate it. And this pattern can be pretty nice. So any other thoughts, Tiya? TIYA CHOWDHURY: No. I'm interested because I haven't done much animation. So this will be quite cool. CRAIG LABENZ: All right. Well, let's get our fingers dirty. If our keyboards are going to get our fingers dirty, then we have other problems. All right. So we're in a fresh Flutter create, and I'm going to do the old initial get rid of the comments. So grab everything and get rid of them. And then we'll allow VS Code to reformat for us. OK. You didn't get it. TIYA CHOWDHURY: No. CRAIG LABENZ: We've de-- TIYA CHOWDHURY: [LAUGHS] But I am following you. CRAIG LABENZ: The [INAUDIBLE]---- wow. Really? Maybe refresh, because that is super-busted. Anyway, so to start, let's just draw a simple widget, and then worry about implicitly animating it later. So we have-- TIYA CHOWDHURY: In a stateless-- stateful widget, right? CRAIG LABENZ: Right. Great question. I am unaware of any way to make an implicitly animated widget without having it be a stateful widget. Because it's going to have to be able to know the difference between its old value and its new value. It's going to have to know-- it's going to have to have an animation controller. It's going to have to do all those things. So yeah, it's going to have to be a stateful widget. And it looks like you are now synced up again. TIYA CHOWDHURY: Yes, I am synced. CRAIG LABENZ: OK. So yeah, we're just in the fresh Flutter create. So we're pretty much ready to delete all the things. We do want the scaffold, so I guess we can-- let's just put a scaffold here. How about that? Or I mean, no. TIYA CHOWDHURY: Are you going to put-- OK. CRAIG LABENZ: --a widget? No, we'll put a scaffold. And then we'll add our own widget to it. So this is body, right? And should we call it-- we called the project implicit widget, which is the incomplete name of what we're trying to do. What should we call it? Implicit-- Widget? TIYA CHOWDHURY: Yeah. CRAIG LABENZ: All right. TIYA CHOWDHURY: Yeah. Do you want me to clean up? CRAIG LABENZ: Sure. TIYA CHOWDHURY: I'll clean up. I've cleaned up. CRAIG LABENZ: Oh, but now I didn't get that. Whoa, it's weird. Look. I got it on the sidebar, but not in the main bar. Oh, I wonder if it's because I also had unsaved changes. So I'm going to save, and it may come back. TIYA CHOWDHURY: OK. CRAIG LABENZ: Well, this is just working poorly-- [LAUGHTER] --unfortunately. Nice. Well, I'll delete it again. And are you seeing the [INAUDIBLE]?? TIYA CHOWDHURY: Should I refresh? No, I don't see anything. Should I refresh again? CRAIG LABENZ: Yeah. Wow. This is really quite poor. TIYA CHOWDHURY: Oh, no. CRAIG LABENZ: We'll figure it out. OK. So we're going to make a new stateful widget. Stateful, stateful-- there it is. And it's called ImplicitWidget. All right? Oh, are we-- pubspec. I'm surely on the new stuff. So this should be Dart at least 17. I'm actually just going to set this back to 17 for now. That's all I'm willing to commit to. There we go. And this means we can use super parameters, which is very exciting. So this will be just super.key, and we can get rid of all this. How did I do that? TIYA CHOWDHURY: That's a lot cleaner. CRAIG LABENZ: Right? TIYA CHOWDHURY: Yeah. CRAIG LABENZ: That's what the Dart folks thought. That's why they made it. I'm not going to worry about this const lint, because we're about to bust that completely wide open. Next, the things that we want to-- oh, let's maybe center this. And then we'll build as soon as we decide what we want to implicitly animate. So the animated container is probably the most common implicitly animated widget out there. Why don't we just make the lowest-budget animated container of all time? TIYA CHOWDHURY: Container, yep. [LAUGHS] CRAIG LABENZ: All right. So ultimately-- oh, this already returns a container. Brilliant. What properties do we want to animate on our container? TIYA CHOWDHURY: Probably the color. CRAIG LABENZ: That was coming to mind for me as well. TIYA CHOWDHURY: OK. CRAIG LABENZ: So we'll say final Color color. And what if we did the name of the color? TIYA CHOWDHURY: OK. So the text? CRAIG LABENZ: Yeah, the text. We could have a text widget. And one thing that is kind of fun-- it's very common to use animation controllers for the kind of expected things where your mind always goes-- color, border radius, elevation, whatever else. But you can animate anything. You can animate strings from one value to the next. And I think that would be fun. So let's have another parameter that is not text, but a string. And it's a color name. And then here we'll say required this.color and required this.colorName. So we haven't done anything with our-- oh, let's give this some size, I guess, so we can see it. So let's say size-- that's not even close to it-- height 200, width 200. And then its child will be probably another Center widget with a Text widget showing our color name. TIYA CHOWDHURY: Will it respond to something, like a user? CRAIG LABENZ: Oh, yeah. We are going to have to have a way to switch. What? String color-- oh, it's widget.color and widget.colorName. widget.colorName. And then the container will have a background color, which is just that color. And that's also widget.color. OK. What is this? How did we already do five things wrong? All right. We do owe it these new parameters. So just to show ourselves that we've written something that renders, what color do we want to start with? TIYA CHOWDHURY: Blue. CRAIG LABENZ: A classic. An oldie, but a goodie. And then colorName will be Blue. And again, OK, fine, we'll just say const. So let's build this. And we're on macOS. That's good. That's what I always like to use. Start debugging. OK. So while this spins up, we're going to need-- you mentioned a way to tell the app that we're changing states. TIYA CHOWDHURY: Yep. Or would like to. CRAIG LABENZ: How do you want to do that? TIYA CHOWDHURY: So typically, you'd want to tap something, maybe. CRAIG LABENZ: OK. So a gesture detector? TIYA CHOWDHURY: OK. CRAIG LABENZ: Around the widget itself? TIYA CHOWDHURY: OK, makes sense. CRAIG LABENZ: So I think we should put it up here. Yeah. This gesture detector is going to take a function. It makes me suspect-- oh, how timely. But there it is. It makes me suspect that this-- I don't know if this is going to be able to stay stateless forever. But for now, we'll say GestureDetector NU. Detector. TIYA CHOWDHURY: Oh, I see why it can't be, because you'll need to know what to pass it if it's changed. CRAIG LABENZ: Right. TIYA CHOWDHURY: Right? CRAIG LABENZ: Yeah. TIYA CHOWDHURY: OK. CRAIG LABENZ: So onTap is going to do something. And then this is maybe-- can you not be const-ified, because your constitution does not allow for this? So const. OK. So this seems good. We're going to need to-- so the whole point of an implicitly animated widget is that-- and by the way, is it working for you right now? TIYA CHOWDHURY: It isn't. CRAIG LABENZ: It isn't? So for you to drive, you'd need to stand here. TIYA CHOWDHURY: Yes. CRAIG LABENZ: What a travesty. TIYA CHOWDHURY: So you are driving. [LAUGHTER] CRAIG LABENZ: The plan was to pass it back and forth. But you'll be brainstorming with me. TIYA CHOWDHURY: Right. CRAIG LABENZ: So the whole point of an implicitly animated widget is that you pass a new value and it animates to the new value. So we're going to need to pass new things here, right? So I think we can-- let's convert this into a stateful widget. Use that handy-dandy-- TIYA CHOWDHURY: That is very, very nice. CRAIG LABENZ: Oh, do y'all not have that? TIYA CHOWDHURY: Well, we do. But you also know how to type it all out. CRAIG LABENZ: Oh. Well. So now we're going to have a-- basically, what I'm imagining for this demo is that we kind of have a couple states that we toggle between when we use this gesture detector. And then it will maybe move an index. So we could have final List of Colors. That will be colors. And that will equal-- we already said Colors.blue is where we start. And then let's just say Colors dot-- what's not blue? TIYA CHOWDHURY: Red! CRAIG LABENZ: Quick, name another color. TIYA CHOWDHURY: Red. CRAIG LABENZ: Red, OK. Whoo! So after that, then we have our list of strings, which is going to be the color names. And so this will be-- oh, we should give it fancy marketing names, like Azure Sky. And then for red, it will be-- what's a good, like-- TIYA CHOWDHURY: Red is usually-- CRAIG LABENZ: What's the name of your lipstick? What's the name of that color? TIYA CHOWDHURY: This is Icon. CRAIG LABENZ: Icon Red. Great. And then we need to know our-- yeah, I didn't mean to save. So now we need to know our index in these lists. So this could be just int index equals 0. And now in our app, we pass colors.index and colorNames.index. And none of this is const-ifiable. TIYA CHOWDHURY: Because it now changes. CRAIG LABENZ: Because it changes. And then if we just do this part, then we should at least be able to toggle it back and forth, and it will snap from value to value. Right? So we can, in here, call setState. And that takes a closure. And in this closure, we will first flip the index. So index equals-- if the index equals 0, then the new value is 1; otherwise, 0. TIYA CHOWDHURY: Yeah. CRAIG LABENZ: Does that check out? TIYA CHOWDHURY: Index-- CRAIG LABENZ: It doesn't think it does. Oh, no. I wrote it totally wrong. TIYA CHOWDHURY: Yeah, I think you-- yeah. CRAIG LABENZ: Really, it just couldn't have been more wrong. So if the index equals 1, then we go to 0; otherwise, 1. OK. TIYA CHOWDHURY: Now it's good. CRAIG LABENZ: That was really far off. TIYA CHOWDHURY: That's fine. CRAIG LABENZ: Samson. TIYA CHOWDHURY: We got there in the end. CRAIG LABENZ: I was way off. And now we can just-- oh, that's actually it. Because we didn't have a single variable for color and color name anymore. So we're actually done. So let's save this. And it didn't love that we changed it to a stateful widget, so I am expecting it to do this. And now-- oh, it didn't like something. What we did? [INAUDIBLE] MyApp. Huh? What's going on? MyApp is not a subtype of StatelessWidget in type cast. I'm starting over. I have no faith in the thing. Do you know why that happened? TIYA CHOWDHURY: I was going to just scroll down your code, but I can't. I was going to see if you've done anything [INAUDIBLE],, just converted it. But there was nothing crazy. CRAIG LABENZ: --crazy. TIYA CHOWDHURY: Yeah. CRAIG LABENZ: Yeah. Whenever you change a stateless widget to a stateful widget, or vice versa-- I think it's probably not common to go in the other direction-- it gets upset for a minute. But then you do a full restart, and then it's happy. And it wasn't happy. You want to do the honors? You want to click it? TIYA CHOWDHURY: [LAUGHTER] CRAIG LABENZ: All right. TIYA CHOWDHURY: Wow. CRAIG LABENZ: We did it. TIYA CHOWDHURY: But that's not very animated, is it. CRAIG LABENZ: Not very animated. Very snappy. TIYA CHOWDHURY: Yeah. CRAIG LABENZ: So it's time. And you mentioned that you've not done a ton with animation. TIYA CHOWDHURY: No, no. CRAIG LABENZ: Have you done anything with your own animation controller? TIYA CHOWDHURY: No. CRAIG LABENZ: All right. TIYA CHOWDHURY: I've played around with it, but nothing beyond just-- CRAIG LABENZ: Well, you can be my spotter and my Googler, because we're going to need to look some stuff up. TIYA CHOWDHURY: OK. CRAIG LABENZ: So down here in our implicit widget, we have a couple of things that we need to do. First, we need an animation controller. So in our State class, we will create an AnimationController, and we'll call it controller. And then in our initState, we can first initialize, controller equals AnimationController. And it needs some things it doesn't have yet-- duration, and access to the clock, the real-world clock provided by Flutter. And its way to get that is by saying with SingleTicker-- that's the one. And that now makes our whole State class know how to keep time. So we can say vsync is this. And then we need a duration. How long should our animation take? TIYA CHOWDHURY: 2 seconds? CRAIG LABENZ: OK. const Duration, seconds 2. Now, instead of having me just type the whole time, do you want to keyboard back and forth? TIYA CHOWDHURY: Yeah, let's do that. CRAIG LABENZ: All right. So we're in the middle of everything right now. But you can have a turn at the wheel. TIYA CHOWDHURY: OK. Awesome. All right. So do we need to initialize anything else here? CRAIG LABENZ: Well, actually, the first thing-- why doesn't it like our controller? TIYA CHOWDHURY: --doesn't like this. Because we need to put that in. CRAIG LABENZ: Nice. Right, right, right, right. TIYA CHOWDHURY: OK. CRAIG LABENZ: OK, so we have an animation controller. And now, the next thing that we need-- this widget needs to know when its current value is different than the last value. And there is just such a lifecycle hook in the life of a stateful widget. What is it, didWidgetUpdate? Something like that? Let's see if that gives us any kind of autocomplete if you start typing that. TIYA CHOWDHURY: It's just-- CRAIG LABENZ: Yeah. Try just "did" to start. didWidgetUpdate? TIYA CHOWDHURY: Did you make this up? Oh. CRAIG LABENZ: Now, one thing I would expect is, if we have the right name, it should be telling us we need to override it. Oh, see, now it may be telling us-- yeah, we're overriding something that has [INAUDIBLE].. TIYA CHOWDHURY: Yeah. CRAIG LABENZ: That's all right. Oh, didUpdateWidget, probably. TIYA CHOWDHURY: didWidget-- oh. CRAIG LABENZ: didUpdateWidget. TIYA CHOWDHURY: OK. CRAIG LABENZ: "Did widget update?" is a question. [LAUGHS] TIYA CHOWDHURY: didUpdateWidget. CRAIG LABENZ: Yeah. Now what's it mad about? Oh, it must call super. OK. Oh, you have the very unfortunate situation of using someone else's keyboard shortcuts. TIYA CHOWDHURY: This is going to be tough. CRAIG LABENZ: Nobody-- that is tough. OK, so the parameter that this is passed is the type of our widget. So that is a-- TIYA CHOWDHURY: Inherited-- oh, sorry. ImplicitWidget? CRAIG LABENZ: Yes, an ImplicitWidget. TIYA CHOWDHURY: OK. CRAIG LABENZ: So you can grab that. And then that's called oldWidget, as we see. TIYA CHOWDHURY: OK. CRAIG LABENZ: Right. Awesome. OK. Now, in here is where we detect any differences, and if so, kind of push over some starting domino which will animate the transition. TIYA CHOWDHURY: OK. CRAIG LABENZ: So the values that we want to check, I think, are color and colorName. TIYA CHOWDHURY: --and text. OK. Oh, right, the name. CRAIG LABENZ: Oh, yeah, what was it? colorName? TIYA CHOWDHURY: No, you are right. It's colorName. So if oldWidget.colorName doesn't equal to-- then the widget? CRAIG LABENZ: Widget, yeah. TIYA CHOWDHURY: OK. If I spot it correctly. Oh. Your Down key, it's not where my Down key is. OK, sorry. CRAIG LABENZ: You really are coding on hard mode right now-- different keyboard shortcuts, different keyboard layout. It's impressive you're typing anything at all. [LAUGHTER] TIYA CHOWDHURY: OK. So both of them? Do we check for both of them? CRAIG LABENZ: Oh, that's a good question. So I think we do want to trigger off either one. TIYA CHOWDHURY: Yep. CRAIG LABENZ: Yeah, let's-- I was wondering, do we want to check for them in the same line? TIYA CHOWDHURY: Or in a separate line? CRAIG LABENZ: Yeah, or in the same "if" statement. Sorry. TIYA CHOWDHURY: Mm-hmm. CRAIG LABENZ: Because if we do check them in the same "if" statement, then once we get inside, we wouldn't know, necessarily, which one changed. TIYA CHOWDHURY: Yes. CRAIG LABENZ: So we'd have to be committed to-- TIYA CHOWDHURY: If one changes, we will be changing the other one. CRAIG LABENZ: Yeah. And we might be interpolating the same value to itself. Yeah. Let's keep going. TIYA CHOWDHURY: Just colorName? CRAIG LABENZ: Oh, no, I think-- yeah, let's put it all in one line. This might present an edge case later, but we'll find out. Nice. TIYA CHOWDHURY: OK. CRAIG LABENZ: So-- TIYA CHOWDHURY: If that happens-- CRAIG LABENZ: If that happens, then we need to push over some domino. We need to start something. TIYA CHOWDHURY: Make some magic happen. CRAIG LABENZ: So we can [INAUDIBLE] right in here, or new method. TIYA CHOWDHURY: New method probably makes sense. OK. So let's call it animateWidget. CRAIG LABENZ: Sure. TIYA CHOWDHURY: Yeah? Not that. CRAIG LABENZ: That was an unhelpful-- TIYA CHOWDHURY: That was not helpful. CRAIG LABENZ: I call this auto-incorrect, where you type the right thing, and it's like, what if I screw it up for you? TIYA CHOWDHURY: [LAUGHS] OK. CRAIG LABENZ: OK. Yeah, nice. So in here, we're finally ready to start the party. [LAUGHTER] So we need a-- we have our controller. And now we need a tween, right? And the tween class is just called Tween. So let's make a new variable. I guess final tween equals. Yeah. Capital T, Tween, is the class. And then I think it has a type. You want to Command-click on the Tween? Unless you know. TIYA CHOWDHURY: I don't, so-- CRAIG LABENZ: Go to Definition, or Command-click any of those. Yeah. OK. So double goes here. TIYA CHOWDHURY: OK. CRAIG LABENZ: Lowercase d. And nice. Now, let's see what the constructor on this is. Because it's a class. So now we can open up the constructor. Oh, just beginning and end. And they are probably T. You want to scroll down a little bit? Let's see. Yeah, T. OK, nice. So the convention here is to say begin 0, end 1. You could have any values, but this makes the math have no unnecessary complication to it. TIYA CHOWDHURY: Unrelated to our duration, then. CRAIG LABENZ: Correct. So what's going to happen is this will animate-- this will basically move a value-- it will start at 0. It will take 2 seconds, as specified by our duration. And it will march its way on up to the end value of 1. TIYA CHOWDHURY: 1. OK. CRAIG LABENZ: And trying to remember. We might just need to Google this. The next thing that we write here, I can literally never remember in my entire life. TIYA CHOWDHURY: OK, do you want me to Google it? Shall I do it on my machine? CRAIG LABENZ: Sure. Yeah, sure. I can also potentially Google, so they can see the results. TIYA CHOWDHURY: OK, fine. CRAIG LABENZ: So we need-- this is from months ago. We need to look up Flutter animation. Let's see. Tween, animation. Animations tutorial. That seems promising. TIYA CHOWDHURY: Oh, yes. CRAIG LABENZ: So searching here for Tween. Tween.animate, OK. So we got this far. That was pretty good. Oh, we skipped a step, though. Oh, IntTween? We don't want that. Huh? TIYA CHOWDHURY: Is this telling what type of animation? CRAIG LABENZ: CurvedAnimation. Creates a curve value, which it looks like it gets passed here. Sorry, what was the last thing you said? TIYA CHOWDHURY: Is that telling it what type of animation it should be doing? CRAIG LABENZ: Yeah. TIYA CHOWDHURY: Is that what that line is? CRAIG LABENZ: Oh, I bet IntTween is just a tween with type int. Probably. That's what I'm going to tell myself. So I think if we copy this and come back here-- and then, do you want to keep driving? TIYA CHOWDHURY: Yeah. CRAIG LABENZ: OK. I guess you could have just Googled it, then. We didn't even need to pass it back. TIYA CHOWDHURY: That's OK. CRAIG LABENZ: So we said IntTween, but we already made our tween. So I think line 88, yeah, that's a little no good. But we need to call this animate method. TIYA CHOWDHURY: So can we just call that on there? CRAIG LABENZ: Yeah, I think so. TIYA CHOWDHURY: OK. CRAIG LABENZ: And then the curve variable is what was passed in. TIYA CHOWDHURY: Ah, so we want to go above that. CRAIG LABENZ: Yeah, sure. Yeah. Yeah, nice. OK. All right. Now we need a listener. There's two more things we need to do. And on one of them, I always spend a significant amount of time wondering why my animation doesn't start. So we need to add a listener so that as the animation moves, we can basically call setState incrementally. And then we need to start the controller. And that's what I always forget. TIYA CHOWDHURY: So add a listener to-- CRAIG LABENZ: Yeah, tween.addListener. Yeah. Nice, nice. And now, so have you added a listener? Have you done any of this before? TIYA CHOWDHURY: No. CRAIG LABENZ: No? OK. So the way the kind of raw animation controller stuff works is, we said before that this was going to march a double value that it keeps track of, from our starting value of 0 to our ending value of 1. It's going to take 2 seconds to get there. And then 60-odd times per second, potentially faster on higher refresh-rate screens, it's going to call this method. So at every step of the way, we're not going to know how much time has passed. That's not our job. That was the vsync. We just know some amount of time has passed. And critically, I forget if it's cur-- it's probably tween.value will be our progress on the path from 0 to 1. So we're going to call setState here and update-- why don't we just start with the color? And we'll do the color name in a minute. TIYA CHOWDHURY: So based on the tween value, we'll-- CRAIG LABENZ: Yeah. TIYA CHOWDHURY: OK. CRAIG LABENZ: So are you familiar with color.lerp and all that? TIYA CHOWDHURY: A little bit. CRAIG LABENZ: OK. TIYA CHOWDHURY: Yes. CRAIG LABENZ: So-- what are you writing here? TIYA CHOWDHURY: Well, I figured-- would we use tween value to determine what color, or would we do it based on-- CRAIG LABENZ: Yeah, yeah, the tween value. Yeah. TIYA CHOWDHURY: OK. CRAIG LABENZ: So what's your thought on the "if" statement? TIYA CHOWDHURY: So between 0 and-- so if it's moving from 0 and 1, so first half, a color, and then the second half, a color? CRAIG LABENZ: Oh, I see, I see, I see. TIYA CHOWDHURY: Is that how it would work? CRAIG LABENZ: Well, I think we'll have to do that for the string name, because strings don't have a lerp function. TIYA CHOWDHURY: Right. CRAIG LABENZ: But yeah, for the color-- TIYA CHOWDHURY: Is it simpler? CRAIG LABENZ: Yeah. Yeah, I think so. So we'll just set our color value. So color equals. TIYA CHOWDHURY: OK. CRAIG LABENZ: Oh, and then we need a variable for that. Yeah, we can't set anything to widget. So we'll need a variable for this. TIYA CHOWDHURY: OK. CRAIG LABENZ: Nice. TIYA CHOWDHURY: And do we set it? CRAIG LABENZ: Yeah. The initial-- oh. Yeah. TIYA CHOWDHURY: We didn't pass anything in. CRAIG LABENZ: But widget.color. TIYA CHOWDHURY: OK. CRAIG LABENZ: That will be the first one, naturally. TIYA CHOWDHURY: Right. CRAIG LABENZ: And this, of course, gets only run once. So that won't be run again as the value changes. TIYA CHOWDHURY: OK. CRAIG LABENZ: And maybe, does that need to be late? Yeah, I think-- TIYA CHOWDHURY: Ah, thank you. CRAIG LABENZ: It was your genius from the last time. TIYA CHOWDHURY: OK. CRAIG LABENZ: All right. So we saved our initial color. And now we're ready to move from that color to the target every frame. So what we are setting this to is Color-- maybe it's Colors-- Color.lerp? Oh, there it is. TIYA CHOWDHURY: Singular, yeah. So is it starting-- ending color. CRAIG LABENZ: And percentage of the way. So our starting color is color. Except I can already see how this is going to be problematic, because we keep overwriting color. We'll think about that in a moment. widget.color, that seems right. Yeah. TIYA CHOWDHURY: It's old and then new. CRAIG LABENZ: Yes. TIYA CHOWDHURY: Yeah. OK. CRAIG LABENZ: And then this is tween.value, I believe. Dang. TIYA CHOWDHURY: If the squigglies go away, then you're right. CRAIG LABENZ: And they didn't. TIYA CHOWDHURY: [LAUGHS] They didn't. CRAIG LABENZ: So, oh, right. color.lerp-- I don't know why lerp returns a nullable color, but we're pretty sure it will be a real color, so yeah. TIYA CHOWDHURY: OK. CRAIG LABENZ: Nice. OK. Now, we already said-- well, first of all, do we think this is going to work at all? Oh, no, because of the second thing. TIYA CHOWDHURY: Go on. Go on. [LAUGHS] CRAIG LABENZ: We have to start the controller. TIYA CHOWDHURY: Right, OK. So the forward. CRAIG LABENZ: Yeah, yeah. TIYA CHOWDHURY: I do it outside the listener. CRAIG LABENZ: Yes. TIYA CHOWDHURY: OK. CRAIG LABENZ: So here, yeah, it's controller.forward. TIYA CHOWDHURY: Yeah. CRAIG LABENZ: And then yeah, no "from." We don't care about that. OK. This looks good. You ready? TIYA CHOWDHURY: Yeah. Do you have hot reload on this? CRAIG LABENZ: Command-S. It must be a different button for you? TIYA CHOWDHURY: Yes, Shift-R. CRAIG LABENZ: Shift-R? TIYA CHOWDHURY: Yeah, for reload. CRAIG LABENZ: Oh, because you go from the command line. TIYA CHOWDHURY: Yes. CRAIG LABENZ: Gotcha. All right. So yeah, let's switch back to the UI. TIYA CHOWDHURY: No. [INAUDIBLE] CRAIG LABENZ: So I would do three up, grab, and click it. Oh, good-- controller has not been initialized. We may have typed for a long time without running anything. TIYA CHOWDHURY: We have the controller there. CRAIG LABENZ: Yeah, we did. TIYA CHOWDHURY: Should I just reboot it? CRAIG LABENZ: Yeah, hot restart. Yeah, the green circle. That's the equivalent of your Shift-R. TIYA CHOWDHURY: OK. CRAIG LABENZ: Uh-oh, still wrong. What did we do? It's really quite the stack trace. No, no. It was right. It's committed to us not having initialized that. TIYA CHOWDHURY: OK. CRAIG LABENZ: So I guess it's on line 28, I think. Oh, gesture detector? TIYA CHOWDHURY: 28 is here. CRAIG LABENZ: What is it talking about? Oh, wait. And then implicit widget, main 1. Animated widget-- oh, I guess it's on 86. TIYA CHOWDHURY: Yeah. CRAIG LABENZ: Controller. I really thought we did that in initState. TIYA CHOWDHURY: Completely perfect code. 86. So this line? CRAIG LABENZ: Yeah. So wait, will you scroll up? TIYA CHOWDHURY: Mm-hmm. CRAIG LABENZ: What, what, what? Really looks-- initialize. How? Could we put a print statement in the init? TIYA CHOWDHURY: OK. CRAIG LABENZ: Let's just see-- OK. And then what do you think about putting another one after the super call? I mean, the super call can't be getting-- TIYA CHOWDHURY: Oh, here, with init? CRAIG LABENZ: I was thinking maybe like between 67 and 68, to see if somehow the super call is leading to something else happening. Nice. All right. Save. We did save. Very good. No? Wait a minute. TIYA CHOWDHURY: Does it need to be rebuilt? CRAIG LABENZ: This time it didn't error. TIYA CHOWDHURY: It didn't error. Yeah, OK. We're good. CRAIG LABENZ: Nice. Never in doubt. [LAUGHS] TIYA CHOWDHURY: We did write perfect code. OK. CRAIG LABENZ: All right, so it's still very snappy. Oh, but we knew there was the starting color thing. So if we go to our animateWidget method, I think line 94 is like eating its own tail. Right? Because every frame through, we say animate from color to the target color at a certain percentage. But that color variable doesn't keep holding on to our initial color. In the beginning, it's blue. And then we click it, and widget.color becomes red. And so we start animating from blue to red. Except we overwrite the place that's storing blue. So then soon we start animating from purple to red. And then we start animating from almost red to red. But really, we were only supposed to be not that far along in the animation yet. So we need to save the initial color, which I think we can just do in that method. If we go back into animateWidget, at the top, why don't we just say starting color equals color? TIYA CHOWDHURY: OK. CRAIG LABENZ: Do we need it up here? That's an interesting question. TIYA CHOWDHURY: Or maybe we don't need it. At the top of this one? CRAIG LABENZ: Yeah, maybe there. I think it might be good here. Yeah, nice. TIYA CHOWDHURY: startColour? CRAIG LABENZ: Sure. TIYA CHOWDHURY: OK. CRAIG LABENZ: But boy, do we spell that word differently. TIYA CHOWDHURY: I'm sorry. Oh, yeah. I'll re-spell it. CRAIG LABENZ: OK. TIYA CHOWDHURY: Sorry. CRAIG LABENZ: All right. So now we put that in line 94, right in the first parameter to lerp. Does that make sense? TIYA CHOWDHURY: Yep. CRAIG LABENZ: OK. So we'll see if it works. [LAUGHS] TIYA CHOWDHURY: It was [INAUDIBLE].. CRAIG LABENZ: So it should be good. TIYA CHOWDHURY: OK. CRAIG LABENZ: And now it's a three-finger up. TIYA CHOWDHURY: A three-finger up. OK. CRAIG LABENZ: Yeah. And-- oh, lordy. Not even a little bit right. TIYA CHOWDHURY: No. CRAIG LABENZ: Ay. We need to put some print statements in somewhere, I guess in that listener. What do you think? TIYA CHOWDHURY: In here? CRAIG LABENZ: Yeah. TIYA CHOWDHURY: OK. Inside the setState? CRAIG LABENZ: Yeah. Oh, either, I guess. Let's just maybe print tween.value and see it work-- see it go from 0 to 1. Oh, wait. Wait, wait, wait. Can you scroll down into the build method? Yeah, look. We use widget.color and widget.colorName, and we made a local variable for that. And it was just color. TIYA CHOWDHURY: So we should just-- CRAIG LABENZ: And we haven't done it yet for colorName. TIYA CHOWDHURY: But that's really OK. CRAIG LABENZ: Yeah. OK. TIYA CHOWDHURY: Is that the magic? Should we see it? CRAIG LABENZ: I think this is going to really improve things. [LAUGHTER] Hey! TIYA CHOWDHURY: OK. CRAIG LABENZ: Let's go. TIYA CHOWDHURY: Hey. CRAIG LABENZ: Let's go. TIYA CHOWDHURY: [LAUGHS] CRAIG LABENZ: All right. Now, what happens if you click it again? TIYA CHOWDHURY: I clicked it too fast, and then it didn't do anything. CRAIG LABENZ: Uh-oh. Oh, it's not working at all. So the controller needs some love. TIYA CHOWDHURY: Oh, is it because we're not resetting it? CRAIG LABENZ: Yes. TIYA CHOWDHURY: OK. CRAIG LABENZ: Yep. So on line 98, I think we can just make that a little smarter-- like you said, reset it first. You're totally right. TIYA CHOWDHURY: Reset it before-- CRAIG LABENZ: Yeah, so controller.reset. And then you probably have to cascade both of those, because they each return null by default. TIYA CHOWDHURY: Right. CRAIG LABENZ: All right. Let's see how that works. OK, so give it a click. TIYA CHOWDHURY: Do you want to do it? I think I'm taking all the-- CRAIG LABENZ: [GASPS] OK. TIYA CHOWDHURY: [LAUGHS] Go ahead. CRAIG LABENZ: I feel so honored to run the code that you just laboriously wrote. Great. And now does it go backwards? Click again. Oh, man. Now-- TIYA CHOWDHURY: Nice. CRAIG LABENZ: Because-- I think because we save the starting color here, what's nice about using your own animation controllers-- and animated widgets do this nicely as well-- but when you're doing this yourself, you can kind of set it so that if you only get halfway through the animation and something yanks you back, it should behave correctly. And I think this will do it. So let's try to click, and then click halfway through. So click, and then click again. And we're back to blue. TIYA CHOWDHURY: Yeah. OK. CRAIG LABENZ: Yeah! All right. So now we are ready to animate the string. TIYA CHOWDHURY: Right. CRAIG LABENZ: Let's think about this. How could we animate the string? What might we do? TIYA CHOWDHURY: You could make the letters appear. Based on the tween value, you can make certain letters appear and disappear, maybe. CRAIG LABENZ: Yeah. That's kind of where my brain was going as well, almost like a cursor is deleting the old name and then typing out the new name. TIYA CHOWDHURY: Yeah. CRAIG LABENZ: That would be kind of cool. TIYA CHOWDHURY: Mm-hmm. CRAIG LABENZ: So do you want to keep driving, or what would you like? TIYA CHOWDHURY: You can drive. CRAIG LABENZ: OK. TIYA CHOWDHURY: I feel like I can talk at you whilst you're driving. CRAIG LABENZ: OK, great. TIYA CHOWDHURY: Do you take the tween value and then divide it by the number of letters? How would we know when to remove a letter? CRAIG LABENZ: Right. TIYA CHOWDHURY: And that could be different-- CRAIG LABENZ: We want something like that, for sure. TIYA CHOWDHURY: Something like that. CRAIG LABENZ: One change that we need to make is kind of following this pattern for color name. So we can scroll up, and this will be colorName, which is a string. Name. And then we'll save the initial value. We have to do that. I guess we'll just do this-- Name. Yeah, yeah. TIYA CHOWDHURY: We know to ignore those ones. CRAIG LABENZ: Wow. I really thought that would fix it, and it just doesn't. Huh. Odd. It's been a long day. This may be obvious to the viewer at home. And if so, I apologize. [LAUGHTER] But we're now ready to think about-- where the hell are we? I mean, heck. We're here. This is the one. Well, I made scrolling look hard. TIYA CHOWDHURY: It's fine. CRAIG LABENZ: OK, so it does the thing. And the name didn't update, because we're not making that smarter. So, hmm-hmm-hmm. So maybe we spend half of the time deleting the first value, and the second half of the time typing the second value. TIYA CHOWDHURY: OK. CRAIG LABENZ: Seem reasonable? TIYA CHOWDHURY: Yeah. CRAIG LABENZ: And this was the "if" statement you were writing. TIYA CHOWDHURY: Right. Yeah. So it's actually between 0 and 0.5. CRAIG LABENZ: Yes. Yes. TIYA CHOWDHURY: OK. CRAIG LABENZ: So if tween.value is less than 0.5, then we'll do something; otherwise, we'll do something else. TIYA CHOWDHURY: Yeah. CRAIG LABENZ: So in here, we are deleting the current name, so deleting the old/current-- depending on how you look at it-- name. Now, like you said, we kind of need to figure out how long to spend on each letter. So is this like an integer division situation? What do we want? TIYA CHOWDHURY: This is a double, or at least a double, right? Or a float? I don't know. How granular does it go? CRAIG LABENZ: Oh, quite. TIYA CHOWDHURY: OK. CRAIG LABENZ: But we could potentially just say, with millisecond granularity, we've got 500 milliseconds. So we could divide the-- what is it? Oh, we'll need to save the starting string, too, won't we? Final startName, or colorName, equals colorName. TIYA CHOWDHURY: (WHISPERING) Capital C. CRAIG LABENZ: Ooh. Nice. So now we need to figure out how many milliseconds per thing. So we have 500. I have no idea how to do integer division. Do you remember the syntax for that? It's like this or something? TIYA CHOWDHURY: Yeah, yeah. CRAIG LABENZ: That's it? TIYA CHOWDHURY: Well, not that. CRAIG LABENZ: Oh. TIYA CHOWDHURY: Just slash. CRAIG LABENZ: Oh, this does integer division by default? TIYA CHOWDHURY: Yeah, I feel like it does. CRAIG LABENZ: I don't-- TIYA CHOWDHURY: Now you're making me doubt myself. Do you want me to look it up? CRAIG LABENZ: I just learned how to program. TIYA CHOWDHURY: Oh, don't say that. CRAIG LABENZ: So 500 divided by the startColor dot-- oh, could we make a lerp method for strings? Is that crazy talk? TIYA CHOWDHURY: I feel like you're going to try it anyways if I said [INAUDIBLE].. [LAUGHTER] CRAIG LABENZ: Maybe we spitball it here. And then if it is coherent, then we'll wrap it up in an extension method. That would be sweet. TIYA CHOWDHURY: OK. CRAIG LABENZ: So 500 divided by the length of startColorName.length. And this tells us how many milliseconds per letter. Right? TIYA CHOWDHURY: Yeah. CRAIG LABENZ: So final milliseconds per letter that we're deleting. And then we'll figure out how many of those have passed. So this would be tween.value divided by milliseconds per letter. There's probably so many better ways to do this. This is final number deleted letters. And so now we can setState to say-- I'm laughing because I just have no idea if this is going to work. colorName will equal the startColorName.substring. And we are at 0, and then this is the number that we deleted. So it's the length minus the number deleted. Right? Does that compute? TIYA CHOWDHURY: Yeah, I think so. And then minus 1. CRAIG LABENZ: Dot length minus-- no. What am I typing? Yeah, dot length minus-- oh. TIYA CHOWDHURY: Minus 1, because we have an index, not length. CRAIG LABENZ: numDeletedLetters. And we need another minus 1? TIYA CHOWDHURY: Yeah. CRAIG LABENZ: You are so many steps ahead of me, it's not even funny. Hey, what's wrong with this? Oh, numDeletedLetters is probably a double. Yeah. So how do you do that? toInt? Excellent. Excellent, Smithers. So if this works, it will just incrementally delete "Azure Sky," or whatever we said. Are you ready? TIYA CHOWDHURY: But only one name, right? CRAIG LABENZ: Right. And it won't type "Icon Red" yet. TIYA CHOWDHURY: OK. Fine. CRAIG LABENZ: Here we go. [GASPS] TIYA CHOWDHURY: It removed one letter. CRAIG LABENZ: We got one letter. TIYA CHOWDHURY: OK. CRAIG LABENZ: Great. [LAUGHTER] I was so excited. I thought it was going to work. TIYA CHOWDHURY: But we got one letter. That's pretty good. CRAIG LABENZ: What a tease. OK. What happened here? So the length, so let's say if it was-- TIYA CHOWDHURY: Does it need to be in a loop or something? CRAIG LABENZ: Well, we're in the loop, because this whole thing is in the loop, right? TIYA CHOWDHURY: OK, right. OK. CRAIG LABENZ: So let's just-- TIYA CHOWDHURY: It's just removing one, and then stopping. CRAIG LABENZ: Print milliseconds per letter. So let's do like this, and then number deleted letters. And do these numbers even make sense? So restart. Come here. Azure Sky. Click. What? So numDeletedLetters-- oh, it's getting really small. So numDeletedLetters, this isn't close to right. Do we just need to divide in the other way? Milliseconds per letter. No. Why didn't this work? tween.value. Oh, we didn't multiply it by 500. This is really going to help, I theorize. TIYA CHOWDHURY: When the number's this small, yes. CRAIG LABENZ: Yeah, right. So redo it. I don't know if we needed to do that. Click. Oh, oh, oh. Oh, it stopped. TIYA CHOWDHURY: Oh, it stopped. CRAIG LABENZ: Why? Yeah, it did conclude at the end that it only wanted to get rid of four letters. I wonder if we have a rounding error that's adding up. But no, that would be a lot. So our milliseconds per letter was 55. How long is "Azure Sky"? 5 for Azure, 4 for Sky and the space, so 9. So what's 500 divided by 9? Of course, it can math correctly. So why did-- TIYA CHOWDHURY: It just stops at 4. CRAIG LABENZ: Where even is the code? Yeah. TIYA CHOWDHURY: Yeah. CRAIG LABENZ: So what's going on here? tween.value times 500, because this is our-- is times 500 right? tween.value-- well, if it was too low, then it would have-- oh, it's times 1,000. We need all of the milliseconds. TIYA CHOWDHURY: --it is halfway. Because, yeah, it is only going halfway. CRAIG LABENZ: We need all of the milliseconds. Great. I love it. OK, very good. And come back. And now-- [CLAPPING] TIYA CHOWDHURY: Well done. CRAIG LABENZ: Let's go! TIYA CHOWDHURY: That is very good. Very, very good. CRAIG LABENZ: And so now it's an exercise of how much can we flip this logically, or the back 9, as they call it? Retyping the new, now-current name. So these parameters-- oh, this does change, because this is now widget.colorName. This is the target name. TIYA CHOWDHURY: Yeah. OK. CRAIG LABENZ: So widget.colorName.length. And then, so this should be the same. But it's not deleted letters anymore. It's now typed letters. So let's say numTypedLetters. TIYA CHOWDHURY: Yeah. CRAIG LABENZ: And now our substring-- TIYA CHOWDHURY: It's going from the other-- so you'll probably swap those? CRAIG LABENZ: Well, we're going to still type from the beginning of the string. TIYA CHOWDHURY: Oh. OK, yes. I take it back. CRAIG LABENZ: So startColorName also-- this isn't it. Oh, we're starting from-- I have literally no idea what to write in this line. TIYA CHOWDHURY: So you were deleting things from right to left, and now you're adding things. CRAIG LABENZ: Yeah. TIYA CHOWDHURY: So we're going from 0, and then-- CRAIG LABENZ: So we want this to just work its way. Oh, it's just numTypedLetters. I'm going to feel really silly. And do we need a minus 1 this time? TIYA CHOWDHURY: Do we always need the minus 1, because of the-- CRAIG LABENZ: Don't know. TIYA CHOWDHURY: You could try it, and then-- CRAIG LABENZ: toInt, minus 1. Why don't we use clamp? TIYA CHOWDHURY: OK. CRAIG LABENZ: Clamp at 0 and widget.colorName.length. TIYA CHOWDHURY: There you go. CRAIG LABENZ: Yeah. Then we just don't have to care about it at all, unless we don't get the last letter. TIYA CHOWDHURY: I like that. I like that. OK. CRAIG LABENZ: Because then we would-- but I don't think that will happen. All right. If you were a betting woman, what would you bet? TIYA CHOWDHURY: It's going to work perfectly. That's exclusive, right? So it won't include the last-- CRAIG LABENZ: These are great questions. You know the right questions to ask. Quick delete. Oh, very wrong. Not close. So startColorName-- first of all, that isn't what we want. Oh, I think I see what the problem is here. Huh? Oh, yeah. We've got to get rid of the length. So we're going to need a minus 500 somewhere. I don't know where. So tween.value-- TIYA CHOWDHURY: Why are we minusing 500? CRAIG LABENZ: Because the tween.value starts at 500 milliseconds. But for us, that's 0% of the way through the second half. TIYA CHOWDHURY: OK. CRAIG LABENZ: Right? TIYA CHOWDHURY: Yeah. CRAIG LABENZ: So we need to figure out how to capture that somewhere. And I think it may be by subtracting 500, which would be like doing this. TIYA CHOWDHURY: OK. CRAIG LABENZ: Who knows? Hmm? Nope. It-- TIYA CHOWDHURY: Halfway again. CRAIG LABENZ: Oh, interesting. Yeah. All right. Let's use our noggins and figure out what's wrong. So right away, it just dropped in four letters. So numTypedLetters, the first time through-- sorry. Do you want to drive? TIYA CHOWDHURY: No, no, no, no, no. CRAIG LABENZ: OK. So numTypedLetters, the first time through, immediately resolved to 4. TIYA CHOWDHURY: Halfway. CRAIG LABENZ: So why did that happen? Let's do this. Oh, I was real smart, and I got rid of those prints. No, I didn't. It's right here. OK, so come with me. Oh, we're already printing. Great. So let's do it again, and then we won't have the other prints. That will be better. So you clear, and now print. Whoa. It started right away. TIYA CHOWDHURY: Yeah. CRAIG LABENZ: That was odd. TIYA CHOWDHURY: It started with 5, right? CRAIG LABENZ: I think it was because this closure was already bound. So we are going to have to redo things. So our update in this closure-- that's not a thing that can hot-reload, which is quite the foot gun. TIYA CHOWDHURY: Yep. CRAIG LABENZ: OK. So it deletes, and yes, it starts right there. So let's look at this first print statement. TIYA CHOWDHURY: It starts at 4. CRAIG LABENZ: Yes. Why is this happening? So numTypedLetters. We said tween.value, which at that point is going to basically be 0.5, right? TIYA CHOWDHURY: Right. CRAIG LABENZ: Like 0.50000001. And then-- that's not the number of milliseconds. TIYA CHOWDHURY: And you changed that 500 to 1,000. CRAIG LABENZ: Yeah, and that science experiment failed. That was terrible. Well, you know what's interesting? It started right at the end before. And then when I cut it in half, it started halfway through. TIYA CHOWDHURY: Halfway through. CRAIG LABENZ: But why would we not need to multiply this time? If it was such that this would work, why would this be the case? Is this possibly the case? So the tween value will be about 0.5. TIYA CHOWDHURY: 0.5 to 1, it travels. CRAIG LABENZ: And we'll divide by milliseconds per letter. So 0.5 over 62 is a very big number. So this is just totally wrong. So what number do we need to put here? I feel like we've bitten off a riddle. TIYA CHOWDHURY: Yeah, and we're so close. CRAIG LABENZ: The first value that we want it to produce is 0. So we want 0.5 times some value. I think we still want that times 1,000. TIYA CHOWDHURY: Yeah, I don't think that we should remove that. CRAIG LABENZ: We shouldn't get rid of it. Yeah, yeah, yeah. So times 1,000. TIYA CHOWDHURY: What happens when we do that? CRAIG LABENZ: I think it started right at the end. TIYA CHOWDHURY: OK. CRAIG LABENZ: Oh, right. There's some 50% we need to chop off somewhere. And we just haven't figured out where to get it. So that's where we still are. So this will delete "Azure Sky" and then start right at the end, because we didn't account for the fact that 50-- oh, wait. Do we just subtract 0.5 from the tween before we multiply by 1,000? Because we just said we wanted 50% of the way through to count as 0%. TIYA CHOWDHURY: To count as 0%, yeah. CRAIG LABENZ: Through this second animation. But then we still want 100% of the way through the animation to count as 100% of the way. TIYA CHOWDHURY: Yes. CRAIG LABENZ: So we kind of say-- what on Earth do we say? So tween.value, maybe minus 0.5, because that much we-- TIYA CHOWDHURY: --have already traveled? CRAIG LABENZ: Yeah, that much doesn't count. So let's think about how this would work, then. Eventually, it's going to get to 1. So we'll say 1 minus 0.5 is 0.5, times 1,000 milliseconds per letter. I feel like it's only going to type half the word. TIYA CHOWDHURY: Let's see? CRAIG LABENZ: Let's find out. Refresh. Rerun. Re-cry. TIYA CHOWDHURY: No. CRAIG LABENZ: What? I literally don't even know. TIYA CHOWDHURY: Don't cry. You can't cry. Well done. CRAIG LABENZ: It worked? TIYA CHOWDHURY: Yes. CRAIG LABENZ: How? TIYA CHOWDHURY: Well, let's have a look. CRAIG LABENZ: Yeah, so at the end value-- TIYA CHOWDHURY: That was your minus 0.5. Is that what you were gunning for? We needed to put it somewhere, to work out that we were already gone-- CRAIG LABENZ: It's because we have 500 here. TIYA CHOWDHURY: Right. OK. CRAIG LABENZ: If we had 1,000 here, then it would have only typed half. TIYA CHOWDHURY: OK. CRAIG LABENZ: We did it. It just clicked for me. Did it click for you yet? TIYA CHOWDHURY: Not really. CRAIG LABENZ: OK. TIYA CHOWDHURY: OK. CRAIG LABENZ: So because the milliseconds per letter is only judged against 500 milliseconds, that means we only need to climb all the way to 500 milliseconds to complete. TIYA CHOWDHURY: And not to 1,000. CRAIG LABENZ: And not to 1,000. TIYA CHOWDHURY: Right, OK. CRAIG LABENZ: And now it worked. TIYA CHOWDHURY: OK. CRAIG LABENZ: And folks, that's how you linearly interpolate a [? stress. ?] Easy-peasy. TIYA CHOWDHURY: Yeah. CRAIG LABENZ: I think we need to watch it again. Because oh man, that's a juicy animation. And what's kind of fun-- TIYA CHOWDHURY: That is smooth. That is very smooth. CRAIG LABENZ: --is the curve is involved here, right? Curved, easeOut. We can see it started typing faster, and then slowed down. TIYA CHOWDHURY: But you can change that, as well. CRAIG LABENZ: Yeah. What's a really nutty curve? Oh, there are some that dip below 0 and kind of ascend above 1. TIYA CHOWDHURY: OK. CRAIG LABENZ: And that would not make sense for strings. So we can't use those. I want a dynamic one, though. How about easeInOutQuart? TIYA CHOWDHURY: Yeah. CRAIG LABENZ: This should be a really slow finish, or some such. [HUMS] So slow, and then it zips around, and then it finishes, like yeah. So the curve is also taken into account. TIYA CHOWDHURY: We could pass that in and make it very custom. CRAIG LABENZ: Oh, right. Should we? TIYA CHOWDHURY: We could. CRAIG LABENZ: OK. Do you want to drive for that? TIYA CHOWDHURY: Sure. CRAIG LABENZ: All right. TIYA CHOWDHURY: OK. So going to go straight back up to the top. CRAIG LABENZ: Yeah, I think. Yeah. TIYA CHOWDHURY: And pass it in to here. CRAIG LABENZ: Yeah, that makes sense. TIYA CHOWDHURY: Should we make it required? CRAIG LABENZ: I feel like we shouldn't. We should have linear maybe be the default. TIYA CHOWDHURY: OK. Maybe we should-- CRAIG LABENZ: Yeah, Curve. Yeah, nice. So just this.curve. I don't know why I'm saying it as if you don't know. TIYA CHOWDHURY: That's OK. CRAIG LABENZ: But we will need to give it the default. TIYA CHOWDHURY: Yeah. OK, so do we set it here? CRAIG LABENZ: In the constructor. TIYA CHOWDHURY: OK, in the constructor. OK, right. Curves? CRAIG LABENZ: Yeah. Just like Color, it's in the plural there. And then linear. Yeah, nice. All right. Now, the only other thing we have to change is we use widget.curve. TIYA CHOWDHURY: Right. OK. CRAIG LABENZ: Which is down in the something. TIYA CHOWDHURY: Where are we setting-- CRAIG LABENZ: We just passed it. Line 90-something. 2. TIYA CHOWDHURY: Here. CRAIG LABENZ: Yep. TIYA CHOWDHURY: Right. CRAIG LABENZ: widget.curve. Whoo! OK. So you run it again, and we should see a linear curve. It should just not do anything interesting. Amazing. We did it. Ooh, click it halfway through, and let's see the-- because we did the color. Oh, no. TIYA CHOWDHURY: That does not look good. OK. CRAIG LABENZ: We have [INAUDIBLE],, right? Yeah, let's see. Where did we get-- let's look at the stack trace, see where we pass something. Oh, probably in our substring. Oh. There's probably a fair amount of juggling to take care of in that, which isn't a thing that I want to do. [LAUGHTER] Unless you want to. TIYA CHOWDHURY: I feel like, yeah, we shouldn't do that. CRAIG LABENZ: But we've demonstrated the concept of this. And now, this was highly academic and fairly contrived, because if you wanted to do this, you wouldn't do this. You would use-- do you remember what it's called? TIYA CHOWDHURY: I want to say inherited widget. CRAIG LABENZ: Or implicit something. TIYA CHOWDHURY: Sorry, implicit. Ah, let me-- CRAIG LABENZ: Passwords are so hard. TIYA CHOWDHURY: Yeah. Third time. CRAIG LABENZ: Impossible. But yeah, there is a class that you can subclass. It's also what all of the animated container, position, et cetera-- they subclass this. TIYA CHOWDHURY: Yes. Implicitly animated widget class. CRAIG LABENZ: There it is. TIYA CHOWDHURY: Yeah. CRAIG LABENZ: So that's actually what you would use if you needed to do this. But I always feel like being at peace with what is going on in those widgets is pretty helpful. TIYA CHOWDHURY: Yeah. CRAIG LABENZ: And also, you could always peek into that widget, and you will very likely see an implementation far smarter than what we just stapled together. TIYA CHOWDHURY: It's the best way to understand how something works. CRAIG LABENZ: Right. TIYA CHOWDHURY: Yeah, do it yourself. CRAIG LABENZ: Well, Tiya, any closing thoughts? TIYA CHOWDHURY: Try it yourself, definitely. I think that I've learned loads. Thank you. CRAIG LABENZ: Amazing. Yeah, well thank you for co-piloting nicely and braving a foreign keyboard, one of my greatest fears in life. But folks, this-- wait. You read us in. Do you want to read us out? TIYA CHOWDHURY: Thank you very much for joining us on "The Boring Show." [MUSIC PLAYING]
Info
Channel: Flutter
Views: 11,870
Rating: undefined out of 5
Keywords: Implicitly animated widget from scratch, Implicitly animated widget, animated widget, animated widgets, flutter tutorial, how to use flutter, intro to flutter, dartpad, introduction to flutter, dart, dart pad, google search, google code, the boring flutter development show, boring flutter show, flutter development, flutter developer, flutter developers, flutter, google developers, google, flutter latest, latest from flutter, flutter updates, Craig Labenz, Tiya
Id: HtgsoZieoeM
Channel Id: undefined
Length: 59min 17sec (3557 seconds)
Published: Wed Aug 24 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.