1 00:00:05,120 --> 00:00:08,870 Alright, so moving on. We're now back at our YoutubeActivity class. 2 00:00:09,030 --> 00:00:14,260 So let's see how we can add a widget to the layout pragmatically, instead of just by editing the layout. 3 00:00:14,610 --> 00:00:19,320 So the first thing we need to do is get hold of the layout object, and I've mentioned before that our layout 4 00:00:19,430 --> 00:00:20,560 is just a view. 5 00:00:20,910 --> 00:00:27,300 So I could just use view, find view by id just like we've done before to get references to the buttons on the layout. 6 00:00:27,330 --> 00:00:32,729 The only difference is we cast it to be ConstraintLayout, rather than a button, so we could try something like val, 7 00:00:32,940 --> 00:00:40,760 this is in the onCreate method, layout, is equal to find view by id, and then in the diamond we're going to put 8 00:00:40,760 --> 00:00:55,150 ConstraintLayout, ConstraintLayout, then within the parentheses r.id.activity_youtube. 9 00:00:55,510 --> 00:01:01,700 Now that would actually work fine if the wizard gave the layout an ID, activity_youtube. 10 00:01:01,700 --> 00:01:03,150 It no longer does. 11 00:01:03,590 --> 00:01:08,930 So what we need to do is open up activity_youtube and give the ConstraintLayout the ID activity 12 00:01:08,930 --> 00:01:09,700 underscore youtube. 13 00:01:09,860 --> 00:01:18,190 So let's go ahead and do that. Just select the ConstraintLayout and change the ID to activity_youtube, like 14 00:01:18,260 --> 00:01:25,820 so and press enter. Then we'll close it down again, and we go back to our YoutubeActivity and we now find that 15 00:01:25,820 --> 00:01:30,620 that error has disappeared. It clears the error in other words. Now notice that we're using the same name for 16 00:01:30,620 --> 00:01:35,300 the layout, and the ConstraintLayout that it contains, and that's fine. The 17 00:01:35,300 --> 00:01:40,030 layout file ID is in R.Layout as you can see here on line 13, 18 00:01:40,490 --> 00:01:45,890 and the view, that's the ConstraintLayout, is in R.id in case you're wondering, so they actually are separate. 19 00:01:45,920 --> 00:01:49,040 Now that's one way of doing it, but we can do it slightly differently. 20 00:01:49,040 --> 00:01:55,200 What I'm going to do is comment out the two lines, the set content view and the layout line that we added, 21 00:01:55,280 --> 00:02:01,520 and we're going to add some slightly different code. So we can do it this way, we can type val layout is equal 22 00:02:01,520 --> 00:02:09,830 to layoutInflater.inflate, then parentheses R.layout.activity 23 00:02:09,840 --> 00:02:17,110 underscore youtube, comma null, then as ConstraintLayout. Then we can do 24 00:02:17,260 --> 00:02:22,490 setContentView parentheses layout. 25 00:02:22,760 --> 00:02:28,530 So that's actually doing exactly the same thing as the previous two lines of code. When setContentView is 26 00:02:28,540 --> 00:02:30,870 called with the resource ID of an XML 27 00:02:30,870 --> 00:02:38,210 layout file, it inflates the XML and sets the activities view to be the view it creates from the XML. 28 00:02:38,210 --> 00:02:44,990 Now this second way inflates the XML and assigns the view that's created to our layout variable. We 29 00:02:45,000 --> 00:02:52,610 can then pass the view to setContentView. The end result is the same, but it's useful to see how you can inflate you own views. 30 00:02:52,640 --> 00:02:56,590 In fact we did something very similar when creating the menu in the previous app. 31 00:02:56,870 --> 00:02:59,140 Now notice that inflate returns a view, 32 00:02:59,300 --> 00:03:04,240 so we have to cast it to be a constraint layout, and we do that by adding the as ConstraintLayout that 33 00:03:04,270 --> 00:03:07,550 you can see on line 15, to the end of the expression. 34 00:03:07,590 --> 00:03:13,310 Now at the moment we've got a warning here on line 15, 'Avoid passing null as the view route'. 35 00:03:13,400 --> 00:03:17,710 Now I do definitely recommend paying attention to that warning whenever you see it, 36 00:03:17,840 --> 00:03:21,220 and that's because it's a common cause of display problems. 37 00:03:21,230 --> 00:03:24,760 There's also a lot of code on line that passes null there when it shouldn't, 38 00:03:24,900 --> 00:03:30,980 and we'll be seeing examples of what you should be passing as the view's route in later apps. 39 00:03:31,220 --> 00:03:37,170 Now there are always exceptions to any rule though, and here we're inflating the route layout for the activity, 40 00:03:37,190 --> 00:03:43,020 so this is the route view. So this is one of only a couple of times when you can pass null 41 00:03:43,220 --> 00:03:45,860 and we can safely ignore this warning. 42 00:03:45,860 --> 00:03:52,570 Alright, so the next step is to create a new YouTubePlayerView object, then add that to our constraint layout. 43 00:03:52,820 --> 00:03:57,330 Now there's a bit more setting up of a YouTubePlayerView before we can run the app to test it, 44 00:03:57,380 --> 00:04:00,200 but the principle's the same for most of the widgets. 45 00:04:00,320 --> 00:04:01,980 So I'm going to add a button to start with, just 46 00:04:02,000 --> 00:04:03,950 so we can see how this works. 47 00:04:04,220 --> 00:04:10,040 So we're going to start still in the onCreate function, below the set content of view call. We're going to 48 00:04:10,040 --> 00:04:17,880 type val button 1 equals button, then parentheses this, then button 1 49 00:04:17,899 --> 00:04:30,350 dot layout Params is equal to ConstraintLayout.LayoutParams parentheses 600, 50 00:04:30,560 --> 00:04:43,690 180, then button1.text equals Button added, then layout.addView parentheses button1 51 00:04:43,730 --> 00:04:49,040 Now when creating a new widget in code, we have to provide the constructor with a context so that it 52 00:04:49,040 --> 00:04:51,960 knows about the environment it's created in. 53 00:04:52,170 --> 00:04:59,210 Now an activity is a context and YouTubeBaseActivity is a subclass of activity, and consequently we can 54 00:04:59,210 --> 00:05:03,930 actually just pass this as we're doing on line 19, as the context. 55 00:05:04,100 --> 00:05:06,650 And that by the way is what the rendering engine gets wrong. 56 00:05:06,830 --> 00:05:12,820 It just uses an ordinary activity which isn't what the YouTubePlayerView widget needs, and therefore we're 57 00:05:12,820 --> 00:05:14,520 getting that exception thrown. 58 00:05:14,930 --> 00:05:20,030 Alright, after that we then need to set some of the properties that we would otherwise have to set 59 00:05:20,060 --> 00:05:21,650 in the layout designer. 60 00:05:21,860 --> 00:05:27,570 Now the only ones we must specify are the width and height, and in code we do that by using a layoutParams 61 00:05:27,620 --> 00:05:34,060 object, and you can see me using that on line 20. So here I'm setting the width to 600dp and the height 62 00:05:34,400 --> 00:05:42,170 to 180 dp. And on the next line, line 21, I'm adding some text to the button, so that we can see it really is the button 63 00:05:42,320 --> 00:05:47,930 that we've created here. Now the final step to add the widget is to call the layout's add view method, 64 00:05:48,350 --> 00:05:50,840 passing it the reference to the view we want to add, 65 00:05:50,990 --> 00:05:57,610 in this case our button 1. Now we would have called setContentView anyway so that the activity knows what 66 00:05:57,610 --> 00:05:59,320 to display when it's launched, 67 00:05:59,320 --> 00:06:03,550 so it's really only taken five additional lines of code to add a button to the layout. 68 00:06:03,790 --> 00:06:08,840 So if we actually run this now. So what I'm going to do is start my emulator. 69 00:06:12,590 --> 00:06:18,460 Alright I'm just going to speed up the video now until it starts. Alright so the emulator's started. Now, 70 00:06:18,470 --> 00:06:22,300 we can now run the app to see that it has added the new button to the layout. 71 00:06:22,370 --> 00:06:28,310 However we can't just use the run button on the tool bar though, because that's going to run MainActivity and we 72 00:06:28,310 --> 00:06:30,110 want to launch YoutubeActivity instead. 73 00:06:30,170 --> 00:06:32,680 So just to show you what I mean, if I click on run now. 74 00:06:35,280 --> 00:06:39,820 So you can see that we're just getting the Hello World program on the screen when we run the app by default, 75 00:06:39,870 --> 00:06:41,340 and that's because by default it's using 76 00:06:41,460 --> 00:06:47,520 the MainActivity. In this case we want to actually right click our YoutubeActivity in the project pane 77 00:06:47,810 --> 00:06:50,260 over here, because that's the one 78 00:06:50,340 --> 00:06:58,820 we want to run. We want to choose run YoutubeActivity, run our emulator, tab over to emulator. 79 00:07:01,230 --> 00:07:06,730 So we can see our activity_youtube layout, and we can see our button now showing on the screen. 80 00:07:07,700 --> 00:07:09,640 Now nothing happens when I click it, and 81 00:07:09,640 --> 00:07:15,280 that's because we haven't created a listener to respond to the click, but it is added to the layout, just 82 00:07:15,280 --> 00:07:18,420 as if we'd dragged it onto the layout in the layout designer. 83 00:07:18,820 --> 00:07:22,000 So that's how you go about adding a widget to the layout in code. 84 00:07:22,140 --> 00:07:27,040 Now it's not something you probably do very often, but it can be very useful for making layouts a little 85 00:07:27,040 --> 00:07:28,340 bit more dynamic. 86 00:07:28,710 --> 00:07:35,270 And this technique is more often used with simpler layouts like the linear layout that we'll be looking at later in the course. 87 00:07:35,320 --> 00:07:40,240 One problem with adding widgets in a constraint layout dynamically, is that you also have to set all 88 00:07:40,240 --> 00:07:46,950 the constraints in code. Now our layout parameters here were very simple, just the width and the height, but it can 89 00:07:46,950 --> 00:07:50,610 get a lot more complex when you try to do it with a more complicated layout. 90 00:07:51,010 --> 00:07:56,780 But fortunately our YouTubePlayerView is just going to fill the entire space available in the layout, 91 00:07:57,040 --> 00:07:59,940 so the code's going to be almost identical to this. 92 00:07:59,980 --> 00:08:05,050 The only real difference here is that we're going to specify MATCH_PARENT for the width and height. 93 00:08:05,050 --> 00:08:09,820 So what I'm going to do now we've got that running is I'm going to comment out the code for the buttons, and 94 00:08:10,240 --> 00:08:13,080 we're going to go ahead and add our YouTubePlayerView. 95 00:08:13,710 --> 00:08:20,770 So to do that we're going to do val playerView is equal to YouTubePlayerView, and 96 00:08:23,820 --> 00:08:25,190 parentheses this, 97 00:08:25,300 --> 00:08:36,360 the context, then we're going do playerView dot.layoutParams is equal to Constraint 98 00:08:36,460 --> 00:08:42,970 Layout.LayoutParams, then parentheses, and we're going to 99 00:08:43,179 --> 00:08:47,590 start this on the next line, and we're going to do match parent for both, so to specify match 100 00:08:47,730 --> 00:08:52,780 parent, right so to specify match parent we need to do a ViewGroup 101 00:08:52,810 --> 00:09:08,820 dot LayoutParams.MATCH_PARENT, and do that twice, so ViewGroup.LayoutParams dot 102 00:09:09,420 --> 00:09:10,940 MATCH_PARENT again. 103 00:09:12,500 --> 00:09:17,720 Then lastly, so we'll get rid of that second, the closing parentheses now. 104 00:09:17,720 --> 00:09:25,310 Then on the next line, we're going to do layout.addView(playerView). 105 00:09:25,750 --> 00:09:27,710 So that's actually how he add it. 106 00:09:27,710 --> 00:09:32,700 So basically instead of specifying the width and height as dp units, as we did for the button that we've now 107 00:09:32,720 --> 00:09:38,510 commented out, I've used a predefined constant MATCH_PARENT so that the widget fills all 108 00:09:38,510 --> 00:09:40,280 the available space in the layout. 109 00:09:40,730 --> 00:09:45,030 But other than that, this code is doing the same thing as we did to add the button. 110 00:09:45,080 --> 00:09:50,070 Now I'm not going to run it because an uninitialized YouTubePlayerView is very boring. 111 00:09:50,300 --> 00:09:54,720 In the next few videos, we'll see what we have to do to make our player play something. 112 00:09:54,770 --> 00:09:59,450 The first step though is to get a Google API key and I'll show you how to do that in the next video.