0 1 00:00:00,590 --> 00:00:01,070 Hey, guys. 1 2 00:00:01,130 --> 00:00:05,230 Welcome to another lesson on SwiftUI. In this module, 2 3 00:00:05,270 --> 00:00:10,400 We're going to be creating the Dicee app. And in the process, we're going to look at how you can create 3 4 00:00:10,400 --> 00:00:14,280 an app with functionality using SwiftUI. 4 5 00:00:14,300 --> 00:00:20,420 In addition, we're going to get more practice creating layouts using SwiftUI, as well as by working with 5 6 00:00:20,420 --> 00:00:25,640 spaces and padding, as well as creating Subviews with properties that can change. 6 7 00:00:26,540 --> 00:00:33,170 But the most important takeaway from these lessons are going to be how to use SwiftUI to manage the 7 8 00:00:33,170 --> 00:00:34,430 state of the app. 8 9 00:00:35,740 --> 00:00:42,670 In this lesson, we're going to be building out an app that not only has an appearance but it also has 9 10 00:00:42,670 --> 00:00:43,980 functionality. 10 11 00:00:44,020 --> 00:00:49,690 So in this case, the user is actually able to interact with a button on the screen which will be able 11 12 00:00:49,690 --> 00:00:54,010 to change the dice faces in this dice shaker app. 12 13 00:00:54,280 --> 00:00:58,410 Let's get started by creating a brand-new project. 13 14 00:00:58,690 --> 00:01:06,910 And I'm, again, going to choose an iOS Single View App and I'm going to call it Dicer-SwiftUI. 14 15 00:01:06,940 --> 00:01:12,970 Again, make sure that you've got SwiftUI selected as the user interface, and then go ahead and hit Next. 15 16 00:01:14,740 --> 00:01:22,490 Now, save it wherever you like, and then click Create. So the first thing I want you to do is to go ahead 16 17 00:01:22,550 --> 00:01:25,830 and add some image assets to your project. 17 18 00:01:25,910 --> 00:01:33,440 So if you head over to the course resources page, you can find that the Dicee Assets for download under 18 19 00:01:33,500 --> 00:01:37,630 the SwiftUI Module, and then go ahead and download those assets. 19 20 00:01:39,590 --> 00:01:46,580 Once you've got the assets downloaded, unzip the compressed file, and you should find a folder called 20 21 00:01:46,580 --> 00:01:48,770 a Dicee Image Assets. 21 22 00:01:48,770 --> 00:01:54,890 Now, inside here are a bunch of app icons as well as other images that we're going to be using in the 22 23 00:01:54,890 --> 00:01:55,910 app. 23 24 00:01:55,910 --> 00:02:00,770 So I want you to head back over to Xcode in your Assets.xcassets, 24 25 00:02:00,800 --> 00:02:05,450 select the AppIcon placeholder, and click the minus button to delete it. 25 26 00:02:06,080 --> 00:02:11,810 Now, we're going to select all of these app icon sets and image sets, and then just drag it into this 26 27 00:02:11,900 --> 00:02:13,130 section here. 27 28 00:02:13,310 --> 00:02:17,980 And that should add all of the images that we need for this project. 28 29 00:02:17,990 --> 00:02:24,730 So, now we can head back to our ContentView and collapse our left-hand pane. 29 30 00:02:25,010 --> 00:02:29,830 So let's set up the user interface first. In this dice app, 30 31 00:02:29,870 --> 00:02:34,730 I want to give it a background image instead of a background color. 31 32 00:02:34,730 --> 00:02:40,360 So we're going to be using the image set that's called Background that's already in the Assets folder. 32 33 00:02:40,790 --> 00:02:47,120 But go ahead and set up a ZStack with a background image setup. 33 34 00:02:47,300 --> 00:02:51,310 Try and replicate the look that you see here on the right. 34 35 00:02:51,320 --> 00:02:55,060 Pause the video and see if you can complete this challenge. 35 36 00:02:58,540 --> 00:02:58,870 All right. 36 37 00:02:58,900 --> 00:03:06,580 So we can grab a ZStack from our Object library and it's going to be under the first tab, and then I'm 37 38 00:03:06,580 --> 00:03:13,960 just going to drag it into my code. And inside the ZStack, instead of a piece of text, I want to have 38 39 00:03:14,350 --> 00:03:15,410 an image. 39 40 00:03:15,520 --> 00:03:21,480 So I'm going to drag this image view into the stack. And the name of my image, 40 41 00:03:21,500 --> 00:03:25,730 we can just quickly check, it's called background. 41 42 00:03:25,850 --> 00:03:33,040 So let's go back to ContenView and let's change the image name to the string background. 42 43 00:03:33,040 --> 00:03:36,520 So, now once our updates load, 43 44 00:03:39,250 --> 00:03:44,250 you should see that our image background has been placed onto our screen. 44 45 00:03:44,350 --> 00:03:51,190 But the problem is that it's placed in its original aspect ratio which is kind of a square sort of 45 46 00:03:51,190 --> 00:03:52,640 one to one aspect ratio. 46 47 00:03:53,380 --> 00:03:59,140 So in this case, what we need is to make our image resizable. 47 48 00:03:59,260 --> 00:04:04,900 So let's add the resizable modifier, so they can actually change its size. 48 49 00:04:08,620 --> 00:04:15,400 And in addition to making every sizable which makes it take up as much space as it's allowed to, 49 50 00:04:15,490 --> 00:04:19,800 then we're also going to add the ignoring the safe areas, 50 51 00:04:19,840 --> 00:04:22,690 so that was called edgesIgnoringSafeArea. 51 52 00:04:22,840 --> 00:04:27,100 So let's add that as well and make sure that all is applied. 52 53 00:04:27,100 --> 00:04:34,780 So it goes to all four corners ignoring all of the safe areas. And that's the solution to the challenge. 53 54 00:04:34,780 --> 00:04:37,690 Now, let's add the remaining images. 54 55 00:04:37,690 --> 00:04:41,560 So on top of the ZStack, I'm going to create another image view. 55 56 00:04:42,130 --> 00:04:50,310 And in this case, the image view is going to hold the Dicee logo image that came with the assets. 56 57 00:04:50,380 --> 00:04:59,190 So I'm going to create another image and the image was simply called diceeLogo. And there it is. 57 58 00:04:59,190 --> 00:05:03,690 So, now the next objects are not going to go in the Z-axis. 58 59 00:05:03,690 --> 00:05:06,500 It's not going to be on top of the dice logo. 59 60 00:05:06,540 --> 00:05:10,710 In fact, what I need is everything in a vertical stack. 60 61 00:05:11,160 --> 00:05:19,090 So I'm going to hold down my command key and I'm going to drop this diceeLogo into a VStack. 61 62 00:05:19,110 --> 00:05:25,620 Now, in addition to the diceeLogo, I also want to put some of these dice images onto the screen. So I'm 62 63 00:05:25,620 --> 00:05:32,010 going to try and take this dice one image and place it just below my other image. 63 64 00:05:32,010 --> 00:05:34,990 Again, it's going to be using an image component. 64 65 00:05:35,100 --> 00:05:38,040 And in this case, the name was called a dice1. 65 66 00:05:38,640 --> 00:05:47,290 So, now in my preview updates, you should be able to see the logo and the dice face. 66 67 00:05:47,350 --> 00:05:54,340 Now, I'm going to go ahead and resize my dice face. So I'm going to do the same thing as I had up here, 67 68 00:05:54,760 --> 00:06:01,960 so I can either write .resizable. But, of course, following these SwiftUI conventions, it should be 68 69 00:06:02,320 --> 00:06:05,890 lower down so that we can stack each of them together. 69 70 00:06:05,950 --> 00:06:09,960 I'm going to get rid of some of these extra spaces now. 70 71 00:06:09,990 --> 00:06:14,350 Notice how that dice has been stretched beyond recognition. 71 72 00:06:14,370 --> 00:06:21,660 So we're going to change its aspect ratio to make sure that it's always set to an aspect ratio of one 72 73 00:06:21,720 --> 00:06:27,290 which means that it will be one to one on both the vertical and the horizontal. 73 74 00:06:27,510 --> 00:06:33,930 And then I'm going to set the content mode to fit, so that the image actually fitted to the size rather 74 75 00:06:33,930 --> 00:06:42,830 than stretched in an awkward way. Now, because I'm going to need two of these dice faces on the screen, 75 76 00:06:43,280 --> 00:06:47,130 instead of creating another one entirely from scratch, 76 77 00:06:47,150 --> 00:06:54,440 I'm actually going to hold down my commands here and extract this Subview. And I'm going to call my 77 78 00:06:54,440 --> 00:07:05,990 extracted view the DiceView and I'm going to move it just above the content view. And then I'm gonna 78 79 00:07:06,020 --> 00:07:13,670 go ahead and change this number to a dynamic number because we have six dice, and depending on what number 79 80 00:07:13,670 --> 00:07:23,470 I put at the end, I'll end up with a different dice face on screen. So instead of having a hardcode 80 81 00:07:23,470 --> 00:07:27,570 number, I'm going to put a value "n" in there. 81 82 00:07:27,730 --> 00:07:36,720 And when this DiceView struct gets initialized, I'm going to initialize it with the "n" as Int. So, now 82 83 00:07:36,750 --> 00:07:44,940 for this DiceView and it's going to be equal to one, and then I'm gonna drop this DiceView into a horizontal 83 84 00:07:44,940 --> 00:07:51,850 stack and copy it so that I have two of them. 84 85 00:07:51,980 --> 00:07:53,810 So there we go. 85 86 00:07:53,810 --> 00:08:00,590 Now, notice how at the moment, they're going all the way to the edges which is a little bit too much. 86 87 00:08:00,680 --> 00:08:08,000 So I want to add some padding to my HStack. So right at the end of the closing brace for the HStack, 87 88 00:08:08,060 --> 00:08:17,800 I'm gonna hit enter and I'm going to add my padding by writing .padding. And if I go ahead and just 88 89 00:08:17,920 --> 00:08:22,900 add this padding as it is, it will get added to all four sides. 89 90 00:08:23,110 --> 00:08:30,130 But if you only want it on a particular side, then inside the parentheses, you can specify which edge 90 91 00:08:30,160 --> 00:08:31,790 you want to add the padding to. 91 92 00:08:32,230 --> 00:08:37,220 And in my case, I want to keep it just on the horizontal sides. 92 93 00:08:37,270 --> 00:08:44,070 Now, the last element I'm going to add into my user interface is going to be a button. 93 94 00:08:44,170 --> 00:08:50,360 So let's search for a button and just go ahead and drag it into your code. 94 95 00:08:50,380 --> 00:08:55,650 I find that when you actually drag it onto the screen, it has so many options to choose from. 95 96 00:08:55,660 --> 00:08:59,170 You often get it ending up somewhere where you don't want it to be. 96 97 00:08:59,230 --> 00:09:07,120 So I want it inside this VStack alongside my diceeLogo, my DiceViews and my Button. 97 98 00:09:07,120 --> 00:09:15,130 So in this case, the button is going to say "Roll" and the action is going to be determined by what's inside 98 99 00:09:15,190 --> 00:09:17,080 these set of curly braces. 99 100 00:09:17,080 --> 00:09:23,880 So let's hit enter and activate that closure. And let's first modify our Text. 100 101 00:09:24,130 --> 00:09:26,730 So at the moment, it's really, really small. 101 102 00:09:26,800 --> 00:09:37,060 So I want to go ahead and change the font to a system font and I'm going to specify a size. So the size 102 103 00:09:37,060 --> 00:09:40,840 is going to be a 50.font to make it really large. 103 104 00:09:41,170 --> 00:09:46,300 And then I'm going to change the fontWeight to a heavy set font, 104 105 00:09:46,300 --> 00:09:49,720 so just a bit thicker than bold. 105 106 00:09:49,720 --> 00:09:55,900 And finally, I'm going to change the foreground color which is going to be the text color effectively 106 107 00:09:56,500 --> 00:10:01,630 and that's going to be white. And the button itself, 107 108 00:10:01,690 --> 00:10:04,840 so outside of these curly braces, 108 109 00:10:04,840 --> 00:10:15,940 so not in the text area. But down here, we can set the background color of the button to Color.red 109 110 00:10:16,300 --> 00:10:20,120 to make it a red background. 110 111 00:10:20,170 --> 00:10:26,980 And finally, if we want our text to have a little bit of padding before it reaches the edges of the button, 111 112 00:10:27,430 --> 00:10:33,010 we can go ahead and add some padding right here. 112 113 00:10:33,120 --> 00:10:41,020 And, again, if you only want it along the horizontal, then we can use the .horizontal modifier. 113 114 00:10:41,120 --> 00:10:41,450 All right. 114 115 00:10:41,480 --> 00:10:46,740 So now it's looking pretty close to our end results. 115 116 00:10:46,760 --> 00:10:53,720 The only thing that I would, perhaps, change is to just give the image a little bit of padding around 116 117 00:10:53,840 --> 00:10:57,550 four edges, so that they separate out from each other a little bit. 117 118 00:10:57,650 --> 00:10:59,230 So it's easier to see. 118 119 00:10:59,510 --> 00:11:07,760 So in the extracted Subview, our DiceView, I'm going to change the image modifier to add some padding 119 120 00:11:07,850 --> 00:11:13,340 around all four sides. And then let's go ahead and reindent our code. 120 121 00:11:13,350 --> 00:11:16,130 And now that's looking a lot better. 121 122 00:11:16,190 --> 00:11:20,440 So in previous lessons, this is how we've seen all these stacks. 122 123 00:11:20,450 --> 00:11:24,790 Everything is stacked together with a little bit of gap in between each element. 123 124 00:11:25,310 --> 00:11:34,220 But what if we wanted to be able to push the stack to take up the full width or length that it has access 124 125 00:11:34,220 --> 00:11:34,550 to? 125 126 00:11:35,070 --> 00:11:41,510 Well, in this case, we could, for example, add some separation between our dice logo and our HStack. 126 127 00:11:41,660 --> 00:11:49,760 So we would do that using something called a spacer. So a spacer is going to create a flexible amount 127 128 00:11:49,760 --> 00:11:53,590 of space depending on how much space there is on the screen. 128 129 00:11:53,630 --> 00:12:00,440 So if it's a small aspect ratio phone or if it's in landscape, then it would shrink that space down automatically 129 130 00:12:00,920 --> 00:12:05,390 without us having to create any constraints or any order layout rules. 130 131 00:12:05,960 --> 00:12:13,520 So let's go ahead and drag our Spacer in between our image and our HStack which will now push these 131 132 00:12:13,520 --> 00:12:19,610 two away, and the spacer will try to take up as much space as it possibly has access to. 132 133 00:12:19,670 --> 00:12:26,330 Now, in addition to having a space between the logo and the dice, I'm also gonna put a spacer between 133 134 00:12:26,330 --> 00:12:33,590 the dice and my Button, so that everything is pretty much evenly distributed on the screen. 134 135 00:12:33,590 --> 00:12:34,100 That's it. 135 136 00:12:34,100 --> 00:12:38,230 That's all we had to do to set up the user interface. 136 137 00:12:38,280 --> 00:12:42,770 There's nothing really new in the code here that you haven't seen before 137 138 00:12:42,980 --> 00:12:49,610 other than, perhaps, the spacer which is a really flexible component that helps us layout our user interface 138 139 00:12:49,610 --> 00:12:51,980 for different sized screens. 139 140 00:12:52,100 --> 00:12:57,440 So, now all you need to do is figure out how do we change the dice 140 141 00:12:57,440 --> 00:13:03,480 images. And that's exactly what we're going to be covering in the next video where we're going to learn 141 142 00:13:03,540 --> 00:13:06,090 about managing state in the SwiftUI.