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.

