Alright, so moving on. We're now back at our YoutubeActivity class.
So let's see how we can add a widget to the layout pragmatically, instead of just by editing the layout.
So the first thing we need to do is get hold of the layout object, and I've mentioned before that our layout
is just a view.
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.
The only difference is we cast it to be ConstraintLayout, rather than a button, so we could try something like val,
this is in the onCreate method, layout, is equal to find view by id, and then in the diamond we're going to put
ConstraintLayout, ConstraintLayout, then within the parentheses r.id.activity_youtube.
Now that would actually work fine if the wizard gave the layout an ID, activity_youtube.
It no longer does.
So what we need to do is open up activity_youtube and give the ConstraintLayout the ID activity
underscore youtube.
So let's go ahead and do that. Just select the ConstraintLayout and change the ID to activity_youtube, like
so and press enter. Then we'll close it down again, and we go back to our YoutubeActivity and we now find that
that error has disappeared. It clears the error in other words. Now notice that we're using the same name for
the layout, and the ConstraintLayout that it contains, and that's fine. The
layout file ID is in R.Layout as you can see here on line 13,
and the view, that's the ConstraintLayout, is in R.id in case you're wondering, so they actually are separate.
Now that's one way of doing it, but we can do it slightly differently.
What I'm going to do is comment out the two lines, the set content view and the layout line that we added,
and we're going to add some slightly different code. So we can do it this way, we can type val layout is equal
to layoutInflater.inflate, then parentheses R.layout.activity
underscore youtube, comma null, then as ConstraintLayout. Then we can do
setContentView parentheses layout.
So that's actually doing exactly the same thing as the previous two lines of code. When setContentView is
called with the resource ID of an XML
layout file, it inflates the XML and sets the activities view to be the view it creates from the XML.
Now this second way inflates the XML and assigns the view that's created to our layout variable. We
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.
In fact we did something very similar when creating the menu in the previous app.
Now notice that inflate returns a view,
so we have to cast it to be a constraint layout, and we do that by adding the as ConstraintLayout that
you can see on line 15, to the end of the expression.
Now at the moment we've got a warning here on line 15, 'Avoid passing null as the view route'.
Now I do definitely recommend paying attention to that warning whenever you see it,
and that's because it's a common cause of display problems.
There's also a lot of code on line that passes null there when it shouldn't,
and we'll be seeing examples of what you should be passing as the view's route in later apps.
Now there are always exceptions to any rule though, and here we're inflating the route layout for the activity,
so this is the route view. So this is one of only a couple of times when you can pass null
and we can safely ignore this warning.
Alright, so the next step is to create a new YouTubePlayerView object, then add that to our constraint layout.
Now there's a bit more setting up of a YouTubePlayerView before we can run the app to test it,
but the principle's the same for most of the widgets.
So I'm going to add a button to start with, just
so we can see how this works.
So we're going to start still in the onCreate function, below the set content of view call. We're going to
type val button 1 equals button, then parentheses this, then button 1
dot layout Params is equal to ConstraintLayout.LayoutParams parentheses 600,
180, then button1.text equals Button added, then layout.addView parentheses button1
Now when creating a new widget in code, we have to provide the constructor with a context so that it
knows about the environment it's created in.
Now an activity is a context and YouTubeBaseActivity is a subclass of activity, and consequently we can
actually just pass this as we're doing on line 19, as the context.
And that by the way is what the rendering engine gets wrong.
It just uses an ordinary activity which isn't what the YouTubePlayerView widget needs, and therefore we're
getting that exception thrown.
Alright, after that we then need to set some of the properties that we would otherwise have to set
in the layout designer.
Now the only ones we must specify are the width and height, and in code we do that by using a layoutParams
object, and you can see me using that on line 20. So here I'm setting the width to 600dp and the height
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
that we've created here. Now the final step to add the widget is to call the layout's add view method,
passing it the reference to the view we want to add,
in this case our button 1. Now we would have called setContentView anyway so that the activity knows what
to display when it's launched,
so it's really only taken five additional lines of code to add a button to the layout.
So if we actually run this now. So what I'm going to do is start my emulator.
Alright I'm just going to speed up the video now until it starts. Alright so the emulator's started. Now,
we can now run the app to see that it has added the new button to the layout.
However we can't just use the run button on the tool bar though, because that's going to run MainActivity and we
want to launch YoutubeActivity instead.
So just to show you what I mean, if I click on run now.
So you can see that we're just getting the Hello World program on the screen when we run the app by default,
and that's because by default it's using
the MainActivity. In this case we want to actually right click our YoutubeActivity in the project pane
over here, because that's the one
we want to run. We want to choose run YoutubeActivity, run our emulator, tab over to emulator.
So we can see our activity_youtube layout, and we can see our button now showing on the screen.
Now nothing happens when I click it, and
that's because we haven't created a listener to respond to the click, but it is added to the layout, just
as if we'd dragged it onto the layout in the layout designer.
So that's how you go about adding a widget to the layout in code.
Now it's not something you probably do very often, but it can be very useful for making layouts a little
bit more dynamic.
And this technique is more often used with simpler layouts like the linear layout that we'll be looking at later in the course.
One problem with adding widgets in a constraint layout dynamically, is that you also have to set all
the constraints in code. Now our layout parameters here were very simple, just the width and the height, but it can
get a lot more complex when you try to do it with a more complicated layout.
But fortunately our YouTubePlayerView is just going to fill the entire space available in the layout,
so the code's going to be almost identical to this.
The only real difference here is that we're going to specify MATCH_PARENT for the width and height.
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
we're going to go ahead and add our YouTubePlayerView.
So to do that we're going to do val playerView is equal to YouTubePlayerView, and
parentheses this,
the context, then we're going do playerView dot.layoutParams is equal to Constraint
Layout.LayoutParams, then parentheses, and we're going to
start this on the next line, and we're going to do match parent for both, so to specify match
parent, right so to specify match parent we need to do a ViewGroup
dot LayoutParams.MATCH_PARENT, and do that twice, so ViewGroup.LayoutParams dot
MATCH_PARENT again.
Then lastly, so we'll get rid of that second, the closing parentheses now.
Then on the next line, we're going to do layout.addView(playerView).
So that's actually how he add it.
So basically instead of specifying the width and height as dp units, as we did for the button that we've now
commented out, I've used a predefined constant MATCH_PARENT so that the widget fills all
the available space in the layout.
But other than that, this code is doing the same thing as we did to add the button.
Now I'm not going to run it because an uninitialized YouTubePlayerView is very boring.
In the next few videos, we'll see what we have to do to make our player play something.
The first step though is to get a Google API key and I'll show you how to do that in the next video.