0 1 00:00:01,350 --> 00:00:07,070 In this lesson, we'll get the grips with UISliders and get them working inside our app. 1 2 00:00:07,260 --> 00:00:14,140 So you should have cloned the starting project and have the project open inside Xcode. 2 3 00:00:14,250 --> 00:00:18,060 Now, first, let's take a look around the starting project. 3 4 00:00:18,060 --> 00:00:25,470 So notice that we've got our Models, View, and Controller folders already created for you. And in our Views 4 5 00:00:25,470 --> 00:00:25,890 folder, 5 6 00:00:25,890 --> 00:00:32,280 we've got our Main.storyboard that has all our designs. But in this case, we've actually got two screens 6 7 00:00:32,340 --> 00:00:37,920 or two view controllers, compared to previously where we've limited ourselves to building single-screen 7 8 00:00:37,920 --> 00:00:39,630 applications. 8 9 00:00:39,630 --> 00:00:44,580 So in this case, we're going to have one screen which is for the calculator where the user toggles their 9 10 00:00:44,580 --> 00:00:49,470 height and weight, and then presses the calculate button. And then, that will take them to the next screen 10 11 00:00:49,740 --> 00:00:52,970 where it shows them their result and some advice. 11 12 00:00:53,100 --> 00:00:57,830 Now, notice that in the calculator view, we've added some UISliders. 12 13 00:00:57,900 --> 00:01:02,850 And if you need to find them they're in exactly the same place that you won't find everything which 13 14 00:01:02,850 --> 00:01:04,980 is, of course, in our object's library. 14 15 00:01:04,980 --> 00:01:11,930 And here we've got a Slider. So it displays a horizontal bar and it represents a range of values. 15 16 00:01:12,150 --> 00:01:16,810 We can define the maximum and the minimum values in the Attribute Inspector 16 17 00:01:16,830 --> 00:01:19,170 once we have the Slider selected. 17 18 00:01:19,170 --> 00:01:26,820 So for my height, which is in meters, I've got the minimum to be 0 meters which, hopefully, nobody is. 18 19 00:01:27,110 --> 00:01:33,190 And I've got the maximum at 3 meters. now, the weight I've set to be zero and 200. 19 20 00:01:33,210 --> 00:01:36,480 So you can feel free to adjust these as you see fit. 20 21 00:01:36,480 --> 00:01:39,420 But I think these will work fine for most people. 21 22 00:01:39,420 --> 00:01:47,670 Notice how we've got these labels here inside a Stack View, and these labels should update to equal the 22 23 00:01:47,670 --> 00:01:51,030 value of the thumb in the Slider track. 23 24 00:01:51,030 --> 00:01:55,030 So I've set the starting value to be 1.5. 24 25 00:01:55,050 --> 00:02:01,170 Now, you can also set it to be at the beginning if you wanted it to be at zero which is the minimum value, 25 26 00:02:01,560 --> 00:02:05,970 but I quite like starting it out in the middle it, looks quite neat. 26 27 00:02:05,970 --> 00:02:11,080 Notice there's also a warning up here that says, "View Controller" is unreachable. 27 28 00:02:11,220 --> 00:02:16,020 And when we click on it, it tells us which one it's referring to which is, of course, this Result View 28 29 00:02:16,020 --> 00:02:16,950 Controller. 29 30 00:02:16,950 --> 00:02:21,810 But don't worry about this warning for now, we're going to fix it when we learn about multi-screen apps 30 31 00:02:22,140 --> 00:02:24,980 and how to navigate to this second screen. 31 32 00:02:25,020 --> 00:02:27,560 For now, we can just safely ignore it. 32 33 00:02:27,990 --> 00:02:32,580 But what we can't ignore right now is our Sliders don't yet work. 33 34 00:02:33,300 --> 00:02:36,210 Now, the behavior that we're after is something like this. 34 35 00:02:36,240 --> 00:02:44,320 We should be able to move the slider along the track and see the Height label here on the right updates. 35 36 00:02:44,910 --> 00:02:52,320 So every time I move the slider, then the associated labels should change its values according to where 36 37 00:02:52,320 --> 00:02:58,410 I am on the slider from the minimum of 10 to the maximum of 200, and the height goes from zero all the 37 38 00:02:58,410 --> 00:03:00,150 way up to three. 38 39 00:03:00,210 --> 00:03:05,760 Now, the height has two decimal places of accuracy, whereas the weight is rounded to the nearest whole 39 40 00:03:05,760 --> 00:03:06,210 number. 40 41 00:03:06,570 --> 00:03:08,080 So that's the objective. 41 42 00:03:08,100 --> 00:03:11,090 That's the behavior we're aiming for by the end of this lesson. 42 43 00:03:11,430 --> 00:03:14,380 But let's break it down into a series of steps. 43 44 00:03:14,430 --> 00:03:17,510 The first step will be printing the value of the slider 44 45 00:03:17,650 --> 00:03:19,860 when we move it along the track. 45 46 00:03:19,860 --> 00:03:21,240 So here's a challenge for you. 46 47 00:03:21,270 --> 00:03:27,990 Can you link up the height slider with an IBAction called height slider changed, and the weight slider 47 48 00:03:28,020 --> 00:03:33,960 with an IBAction called weight slider changed, and then figure out how you can print out the value 48 49 00:03:33,960 --> 00:03:34,940 of each slider 49 50 00:03:35,070 --> 00:03:39,960 when they do in fact get changed. I'll give you a few seconds the pause the video before I show you the 50 51 00:03:39,960 --> 00:03:43,620 solution. 51 52 00:03:43,770 --> 00:03:44,190 All right. 52 53 00:03:44,220 --> 00:03:45,950 So how did you do? 53 54 00:03:46,000 --> 00:03:47,470 Did you give that a go? 54 55 00:03:47,470 --> 00:03:52,600 Well, the first thing that we need to do is, of course, link up some IBActions, right? 55 56 00:03:52,600 --> 00:03:57,280 This is a component that can take user interactions just like the button. 56 57 00:03:57,340 --> 00:03:58,240 How do we do that? 57 58 00:03:58,270 --> 00:04:05,750 We, of course, pull up our assistant view, and then we can start linking up our design with our code. 58 59 00:04:05,920 --> 00:04:12,370 And I'm going to select this horizontal slider which you can see is the height slider and I'm going 59 60 00:04:12,370 --> 00:04:20,920 to control, drag over here, and I'm going to call that action the heightSliderChanged. 60 61 00:04:20,920 --> 00:04:30,430 And notice how the event type that triggers this IBAction is when the value of my slider changes. 61 62 00:04:30,490 --> 00:04:35,830 And to be more accurate and to make life easier for me down the line, I'm going to change the data type to 62 63 00:04:35,830 --> 00:04:39,160 be a more precise data type, rather than any data type. 63 64 00:04:39,340 --> 00:04:44,320 It's going to be a UISlider that's going to be linked to this action. 64 65 00:04:44,410 --> 00:04:50,170 So that's my height slider done and now I'm going to do the same with my weight slider. 65 66 00:04:50,200 --> 00:04:58,990 So this one's going to be called weightSliderChanged. And, again, change the type to UISlider, hit Connect. 66 67 00:04:58,990 --> 00:05:07,150 So now I've got my two IBActions down. Now, the next step is how do I change my code so that whenever 67 68 00:05:07,210 --> 00:05:16,000 this IBAction gets triggered, I can print out the value of my slider where I am on this slider track? 68 69 00:05:17,680 --> 00:05:24,820 So we know that when we select these UISliders in the interface builder, and when we look in the Attribute 69 70 00:05:24,820 --> 00:05:30,310 Inspector, the value property is the one that we actually want, 70 71 00:05:30,310 --> 00:05:30,610 right? 71 72 00:05:30,610 --> 00:05:32,850 Like right now, it's set to 1.5, 72 73 00:05:32,980 --> 00:05:39,850 but I could set it to 1.7, or I could set it to zero, and that moves the little circle along 73 74 00:05:39,850 --> 00:05:40,930 the track. 74 75 00:05:40,930 --> 00:05:48,730 Now, if we go and check in our IBAction, notice how we've got a sender which has a data type of 75 76 00:05:48,730 --> 00:05:49,510 UISlider. 76 77 00:05:50,890 --> 00:05:58,240 So if we tap into the sender which is, of course, that slider, and we wlrite a dot, you can also just scroll 77 78 00:05:58,240 --> 00:06:03,490 through this list and see if there's any properties that you think might be what you want. 78 79 00:06:03,730 --> 00:06:08,770 And we can see that there's actually a property that matches the one we saw in the Attribute Inspector. 79 80 00:06:09,190 --> 00:06:14,520 The value and the explanation is that this will be equal to the slider's current value. 80 81 00:06:14,530 --> 00:06:17,830 Well, that sounds pretty much like exactly what we need. 81 82 00:06:18,010 --> 00:06:24,160 So now all we need is to wrap it inside a print statement, and then copy it over to the weightSlider 82 83 00:06:24,160 --> 00:06:30,610 as well. And you've now got the functionality that we described, 83 84 00:06:30,850 --> 00:06:36,280 so that completes the first two steps. We've linked our Sliders to our View Controller and we've successfully 84 85 00:06:36,280 --> 00:06:39,540 access the value of each Slider. 85 86 00:06:39,610 --> 00:06:45,520 The next thing to notice is that when these values get printed, well, they actually have quite a lot of 86 87 00:06:45,520 --> 00:06:47,100 decimal places. 87 88 00:06:47,140 --> 00:06:53,090 That's a high level of precision. But we don't really need it to be so precise. 88 89 00:06:53,110 --> 00:06:54,490 Here's another challenge for you. 89 90 00:06:54,610 --> 00:07:03,170 Can you figure out how to round the height slider value down to only two decimal places? 90 91 00:07:03,340 --> 00:07:11,010 So we move the high slider, the goal is to only have two decimal places being printed, rather than four 91 92 00:07:11,010 --> 00:07:11,630 or five. 92 93 00:07:12,490 --> 00:07:15,670 So pause the video and see if you can complete this challenge. 93 94 00:07:18,330 --> 00:07:20,210 So there's quite a few ways of doing this. 94 95 00:07:20,220 --> 00:07:28,200 But if I did a just cursory search of how to round a number to two decimal places using Swift, then one 95 96 00:07:28,200 --> 00:07:33,650 of the solutions that you might come across is to use the String formatting. 96 97 00:07:33,840 --> 00:07:39,660 So we pass in the number that we want to be rounded and then we specify the number of decimal places 97 98 00:07:39,660 --> 00:07:47,260 we want by using this "%." and the 2f refers to two decimal places after the floating point, 98 99 00:07:47,460 --> 00:07:52,900 or you could have one 1f for one decimal place, 0f for zero decimal places. 99 100 00:07:52,920 --> 00:08:00,720 So let's try this. In our heightSlider, we already know that we can get access to the sender.value 100 101 00:08:01,320 --> 00:08:05,240 which is going to be quite precise, so it has a lot of decimal places. 101 102 00:08:05,430 --> 00:08:11,040 And this is going to be the thing that we want to round. And if we apply the code that we found here 102 103 00:08:11,070 --> 00:08:15,840 where we write String, and then we type format just like we saw. 103 104 00:08:15,850 --> 00:08:25,320 Well, this particular method is going to return a String initialized by using a given format string as 104 105 00:08:25,350 --> 00:08:30,440 a template into which the remaining argument values are substituted. 105 106 00:08:30,450 --> 00:08:34,980 That sounds pretty confusing but, essentially, all it takes are two inputs: 106 107 00:08:34,980 --> 00:08:38,630 the format string and the thing that you want to format. 107 108 00:08:38,970 --> 00:08:44,770 In this case, the thing that we want to format is, of course, sender.value, so we'll put that in here. 108 109 00:08:45,060 --> 00:08:54,120 And the format string as we saw before, we just had to put "%.2f" just as we have in the 109 110 00:08:54,120 --> 00:09:02,180 code snippet here. And then finally, we're going to go ahead and print this entire string. 110 111 00:09:02,300 --> 00:09:09,320 And now if we run our app, you'll see that functionality I described earlier on, 111 112 00:09:09,350 --> 00:09:12,350 so two decimal places. 112 113 00:09:12,350 --> 00:09:15,200 The next thing to do is our weight slider. 113 114 00:09:15,320 --> 00:09:18,180 We want it to be a whole number. 114 115 00:09:18,320 --> 00:09:23,320 So when we move the weight slider, we don't want to see any decimal places. 115 116 00:09:23,390 --> 00:09:25,960 And so I'm, again, going to leave this as a challenge to you. 116 117 00:09:25,970 --> 00:09:28,810 There's actually multiple ways of doing the same thing. 117 118 00:09:28,940 --> 00:09:35,190 But pause the video and see if you can achieve this effect. 118 119 00:09:35,510 --> 00:09:35,820 All right. 119 120 00:09:35,850 --> 00:09:41,940 So in this case, we could have done what we did before which is where we simply do string format the 120 121 00:09:42,000 --> 00:09:47,980 sender.value, and instead of two decimal places or "2f," we put "0f." 121 122 00:09:48,240 --> 00:09:53,410 And now when we run our app, you can see that we have no decimal places. 122 123 00:09:53,490 --> 00:10:00,480 Now, the alternative way of doing this is we could have also converted our sender.value, which if 123 124 00:10:00,480 --> 00:10:07,110 you check is actually a floating point number, we could actually just convert it into an integer by writing 124 125 00:10:07,130 --> 00:10:12,640 "int," and then having a set of parenthese,s and inside we write sender.value. 125 126 00:10:12,640 --> 00:10:20,600 Now, when I do that, you'll see that I get the same effect again with numbers with no decimal places. 126 127 00:10:20,620 --> 00:10:27,010 So now that we've got our height to two decimal places, I'll wait to no decimal places. 127 128 00:10:27,100 --> 00:10:35,260 We're ready to move on and get the user to be able to see these values. Firstly, we're going to add some 128 129 00:10:35,320 --> 00:10:41,140 IBOutlets. The place that we want to display these values are, of course, this label and this label 129 130 00:10:41,140 --> 00:10:46,540 right here, because the user can't see the debug area, so we need to be able to put these values onto 130 131 00:10:46,540 --> 00:10:49,220 the screen. At the top of my file, 131 132 00:10:49,240 --> 00:10:58,000 I'm going to go ahead and control drag my hype label here and I'm just gonna call it heightLabel and, also, 132 133 00:10:58,030 --> 00:11:04,410 I'm going to create a link from this label right here which I'm going to call 133 134 00:11:04,420 --> 00:11:05,830 weightLabel. 134 135 00:11:05,830 --> 00:11:09,520 Now, I've got my two labels connected. 135 136 00:11:09,520 --> 00:11:11,350 Let's quickly format our code. 136 137 00:11:11,800 --> 00:11:16,310 Well how do I get these numbers into these labels? 137 138 00:11:16,750 --> 00:11:22,120 And I'd like to pose this as a challenge to you. Upon successfully completing the challenge, 138 139 00:11:22,150 --> 00:11:29,530 you should be able to move the slider and see these labels move with you from the maximum to the minimum 139 140 00:11:29,800 --> 00:11:31,780 reflecting the value of the slider. 140 141 00:11:32,260 --> 00:11:34,990 Pause the video and see if you can figure out how to do this 141 142 00:11:38,900 --> 00:11:46,190 Previously, we were already able to print these values to the desired accuracy into the debug console. 142 143 00:11:46,190 --> 00:11:52,340 We now need to get them into these heightLabels and weightLabels. So let's delete the print statement 143 144 00:11:52,610 --> 00:11:56,540 and we're left with the value that we want to put into the heightLabel. 144 145 00:11:56,540 --> 00:12:02,830 So now all we need to do is tap into our heightLabel and then get hold of its 145 146 00:12:02,870 --> 00:12:09,950 text property, and set it equal to the string that we formatted based on the sender.value. 146 147 00:12:09,950 --> 00:12:16,550 Now, if you used this method that I showed earlier where we converted the sender.value into an integer, 147 148 00:12:16,550 --> 00:12:22,290 well it might be a little bit harder to put it into the weightLabel because when we write weightLabel.text 148 149 00:12:22,430 --> 00:12:25,610 equal to Int(sender.value) 149 150 00:12:26,000 --> 00:12:31,910 well, there's gonna be a type mismatch because the right-hand slide is an integer data type, whereas this 150 151 00:12:31,910 --> 00:12:34,920 text property needs a string data type. 151 152 00:12:35,000 --> 00:12:36,380 So how can we fix this? 152 153 00:12:36,380 --> 00:12:44,930 Well, one way is to wrap the integer inside a string. So we first convert this into a whole number and 153 154 00:12:44,930 --> 00:12:46,880 then we convert it into a string. 154 155 00:12:46,880 --> 00:12:52,700 But to be honest, that's quite roundabout, so we might as well just use the same method that we have above 155 156 00:12:53,060 --> 00:12:59,990 which is where we use the format, and then we have "%.0f" for zero decimal places, and then we 156 157 00:12:59,990 --> 00:13:02,720 put in our sender.value. 157 158 00:13:02,720 --> 00:13:11,750 So now if we run our app, you'll see that these labels move when I move the slider. But notice how previously, 158 159 00:13:11,780 --> 00:13:14,900 we had some units in there. But now we move them, 159 160 00:13:14,900 --> 00:13:16,480 the units are gone. 160 161 00:13:16,580 --> 00:13:23,300 Pause the video and see if you can change the code so that when we move the slider, the units stay as 161 162 00:13:23,300 --> 00:13:23,750 they are. 162 163 00:13:23,750 --> 00:13:28,270 So meters for the height and kilograms for the weight. 163 164 00:13:28,280 --> 00:13:30,950 So pause the video and try to do this. 164 165 00:13:33,530 --> 00:13:33,880 All right. 165 166 00:13:33,890 --> 00:13:37,810 So before we start formatting, this line is already getting pretty long. 166 167 00:13:37,820 --> 00:13:42,620 So let's go ahead and set this equal to a separate constant. 167 168 00:13:43,010 --> 00:13:50,600 So I'm going to write "let height" equal this, and then in my heightLabel, I'm gonna set the text property 168 169 00:13:50,630 --> 00:13:53,510 to be equal to an interpolated string. 169 170 00:13:53,660 --> 00:14:01,700 So I'm going to insert the value of my height in here, and then I'm going to tag on the meters unit, and 170 171 00:14:01,760 --> 00:14:05,930 I'm going to do the same with my weight, "let weight" equal that. 171 172 00:14:06,050 --> 00:14:17,660 And then my weightLabel.text is gonna be equal to the weight inserted into my string and then with 172 173 00:14:17,660 --> 00:14:20,720 my kilograms added on at the end. 173 174 00:14:20,750 --> 00:14:28,510 Now, we have this behavior that we want. In the next lesson, we'll use our slider values to calculate the 174 175 00:14:28,510 --> 00:14:35,710 BMI. But to do that, we need to be able to get hold of the slider values outside IBActions. For all 175 176 00:14:35,710 --> 00:14:38,050 of that and more, I'll see you on the next lesson.