Timeline Animation8:31 with Craig Dennis
Let's make our timer tick down and learn a bit about how custom animations in JavaFX work!
[MUSIC] 0:00 Our time tracking app isn't very good if we don't change the big block of 0:04 time, right? 0:08 So, there are a couple of ways that we can tackle the problem 0:10 of making our clock start ticking. 0:13 I think the one that makes the most sense, is to use timeline animation. 0:15 Have you ever seen one of those flip books where there's a still picture on one page. 0:20 Maybe a stick figure going, and then on the next page he's like, and 0:24 then almost the same one on each different pages. 0:28 And then it goes kinda go like this. 0:31 And if you take the corner and flip the pages, it makes it seem like it's moving. 0:33 This is animation in a nutshell, and those are some sweet moves too, huh? 0:37 JavaFX provides different powerful types of animation, and 0:42 I've linked to some fun examples in the teacher's notes. 0:46 So what we are going to do is make a pretty boring flip book. 0:49 On each page, we're going to have the remaining time and 0:53 every second we'll flip the page. 0:56 So, we'll start with 25. 0:58 Wait a second. 1:00 Flip the page, and it will say 24:59 seconds, etc. 1:01 JavaFX provides a pretty straightforward way to accomplish this task. 1:06 So let's go learn all about the timeline. 1:11 All right, so the first thing that we need to do is create a timeline object. 1:14 Let's add a private field to store it. 1:19 So we'll put it up here and say, private TimeLine, and 1:21 we'll call it mTimeLine. 1:25 Now, every time that we prepare an attempt to run, we'll just make a new timeline. 1:32 So let's do that. 1:37 So in here, in this prepareAttempt method that we have going on, 1:38 let's just make a new timeline. 1:43 nTimeLine = new TimeLine. 1:45 So we wanna set the cycle count. 1:51 And the cycle count is essentially, 1:53 in our flip book analogy, how many pages are available. 1:55 So, we wanna have a page for every single second that we're gonna display, right? 1:58 So let's set it to the total seconds that are required. 2:04 So we'll say mTimeline.setCycleCount. 2:06 And we're gonna set it to the total seconds that we're going to perform right? 2:10 So that says run that, that many times, 2:14 whatever 60 times 25 is. 2:18 Run that times, cycle that many times through. 2:22 Now next, what we need to set up is what happens on each page flip. 2:26 Now these are known as keyframes, and you can have multiple keyframes. 2:30 But ours is really only going to do one thing. 2:33 So, keyframes is a property that returns a list on our timeline. 2:36 So let's add one. 2:41 So we'll say mTimeLine. 2:42 We'll get the property, we'll say getKeyFrames. 2:45 And we can just create a new one in line here. 2:48 Could create this outside, but this is the standard way of doing it. 2:52 I wanted to show you this. 2:54 It looks a little over the top at first if you just see this written. 2:55 So I just wanted to show this to you so you could grab it. 2:59 So getKeyFrames, and we are going to do a new KeyFrame. 3:02 Creating a brand new one here. 3:08 And it takes two parameters, first it needs to know the duration. 3:09 How does this run for, it's thinking. 3:12 So you say Duration, and ours is going to run for exactly 1 second, right? 3:14 You want to flip the page, let it go. 3:19 Flip the page, wait a second, flip the page, right? 3:22 So, 1 second, and then you can pass in a lambda. 3:25 Okay, so we're going to do a lambda. 3:30 And again, 3:32 check the teacher's notes if you're not sure what the syntax of that is. 3:33 And I'll import both of those things, okay. 3:38 So in our lambda here, this is what is gonna run every one of these KeyFrames. 3:42 So what we wanna do is we wanna take the current attempt, and 3:47 we wanna make it take a remaining second down, right? 3:52 We wanna tick the timer. 3:55 So why don't we make a method called that? 3:57 Let's call a method called tick. 4:00 Of course, it doesn't know what that is so we will click it. 4:03 And let's go create the method tick. 4:06 All right, so, what does that do? 4:09 Well, we want to decrement the RemainingSeconds. 4:12 Okay, do you remember how that is? 4:15 You go RemainingSeconds--. 4:17 Okay, so that will take the existing time minus one. 4:19 So, if we come back here, it should be working now. 4:24 We'll see what that error is here in a second. 4:30 And now what we wanna do is, each time we wanna set the timer text, 4:33 remember that's that property that's automatically bound. 4:37 We wanna set that to the RemainingSeconds. 4:39 Let's see what this says. 4:48 Oh, I forgot the word add, .add. 4:51 We wanna call getKeyFrames and then we wanna add. 4:55 So see it was so confusing even I typed it wrong. 4:58 Let's read that again. 5:01 We get all the KeyFrames that are currently existing cuz it's a list. 5:02 And we add to it, and we create a brand new KeyFrame. 5:05 And the brand new KeyFrame says, how long does it run for? 5:08 And what does it do? 5:12 And then because the cycle count says how many times it does it, 5:14 basically we've just created our book. 5:17 So now since we want to have multiple events be able to start and 5:20 stop the timers, right, we have the play and the pause and the restart. 5:23 Let's make a couple of methods right on the controller that explain 5:27 what it's doing. 5:30 How about, I dunno, playTimer. 5:31 So we'll say public void playTimer. 5:34 And it will know about the timeline, and so it will say mTimeLine. 5:41 And there's a method on there called play, just as you'd imagine. 5:44 And let's do one called pauseTimer, 5:47 cuz multiple people might wanna call that as well. 5:50 So say mTimeline.pause(). 5:54 Cool, maybe we'll need more later in there, maybe we'll do other things. 5:59 But for now, that will expose the method that kicks off the timeline. 6:02 So one place I know for sure that wants to do that, and 6:06 should be pretty clear, is the restart button, right? 6:09 So let's go over to our FXML file. 6:12 And in the Restart button, on this button here, let's go ahead and 6:15 give that an action. 6:19 So we'll say, onAction= handleRestart. 6:20 And of course, that doesn't exist because we just made that up, so 6:28 let's go ahead and say Create method. 6:32 Awesome. 6:36 All right, so when it restarts, what does it need to do? 6:39 Well first we need to set up what attempt type it is. 6:42 And no matter what, if you're doing a restart, it should go back, I believe, 6:44 to focus time. 6:47 So we should say, I'm ready to focus again. 6:48 So if you click restart, 6:52 we'll prepareAttempt, and 6:55 we'll do AttemptKind.FOCUS, okay? 7:00 And then, we'll just start automatically playing the timer, right? 7:06 You don't need to set it and then have it sitting there waiting for us. 7:08 We'll just automatically play the timer, it'll just start. 7:11 Let's try that, let's see what happens. 7:15 Okay, so let's click our Restart button. 7:19 There it goes. 7:23 Look at it clicking away. 7:24 Awesome. 7:26 So if I click it again, there it goes. 7:28 Seems a little jumpy, that's strange. 7:31 Oh, it's really jumpy. 7:34 Oh, I wonder if it's clicking off multiple timelines. 7:36 That's something we have to be careful of right. 7:39 Cuz we told it to run this thing into the future, and 7:41 it is running the thing in the future. 7:43 Yikes, why don't we put a to-do in the code to fix that. 7:45 Let's put that right right here we better say, 7:50 And I'm gonna put my initials so 7:57 anybody coming to look at this knows that, 8:01 This is creating multiple timelines. 8:05 We need to fix this! 8:10 Yikes! 8:14 We got our clock ticking, and our app is starting to work like we dreamed. 8:16 One thing we need to think about is what happens when the animation is over. 8:20 I think there was a user story about that wasn't there? 8:23 Let's go start that story right after this quick exercise. 8:27
You need to sign up for Treehouse in order to download course files.Sign up