Alright, so apart from the two EditText
widgets and the position of the
operation TextView, the portrait layout's
identical to the landscape version. As is
often the case, though, there are several
ways to achieve the same effect, so let's
look at two different ways of adding
this negButton to our portrait layout.
Now the first slide here is showing a
similar approach as in the landscape
layout. The buttons in the second column -
that's 8 down to the dot - are constrained
to the left of the button to their right,
but it's the same otherwise. The
important thing is that all the buttons
are constrained towards the key button -
which in this example is button9. Now
the buttons in the first two columns
have a constraint from their right edge
to the button on their right, and a
baseline constraint also to the button
on their right. And the buttons in the
last two columns go the other way; so
their left edge is constrained to the
buttons on their left, and the baseline
constraint is also to the left. So that
way, all the columns are being
constrained towards the central column.
Now constraining the buttons like this
makes sure that they're a fixed
distance from their neighbour, and aligned
correctly with their neighbour's baseline. Now
the overall horizontal and vertical
alignment is handled by constraints in
the central column; each button has a
vertical constraint from its top edge to
the bottom of the button above, which
takes care of the spacing between the
rows of buttons. Now to keep the columns
in a straight line,
each button in the central column has
its left edge lined up with the
left edge of the button above
it. Now one disadvantage of this approach,
is that you'd have to change 13 margins
if you wanted to allow the spacing
between, or if you wanted to alter rather,
the spacing between the columns. All the
constraints from the right edge of one
button to the left edge of its neighbor
would have to be changed, and vice-versa
for the buttons to the right of centre.
So let's look at a slightly different
approach to this in the next slide. Now
here, the rows are still lined up
vertically by their baseline constraints,
and the row spacing set by vertical
constraints in the central column. Now
the columns are lined up by constraining
the edge of a button to the edge of the
button above. Now I've used the left edge,
but the right edge would do just as well,
because all the buttons are the same
size. Now the column spacing is set by
the horizontal constraints in the top
row. Now you'd only have to change the
margins on four constraints to alter the
column spacing, in this scenario, and
three constraints to alter the row
spacing. And as I mentioned, there's
nearly always more than one way to do
things, so it's worth looking at
alternatives, to see if there's any
advantage to be gained from choosing one
way or the other. In this video, we're
going to use that second approach, or
this second approach for the portrait
layout. It's probably not a good idea to
do things differently in a landscape and
portrait layout, unless you have to, so
I'm just doing it in this example, just
so you can see the different approaches.
In your own apps, though, you really want to
try to be consistent wherever possible.
Okay, so I'm editing the portrait layout
in activity_main.xml, and we
can obviously see up here in the tab, its
layout/activity_main,
and it's not land which was our
landscape one, and obviously, clearly we
can see that this is a portrait layout
anyway. Alright, so the first thing we
need to do is clear all the constraints
from the buttons. Now there's only three
widgets that aren't buttons, so it could
actually just make sense to use the
Clear all constraints button, and
re-create the constraints on the Edit
Views and the TextView.
Now if the layout was more complicated,
that could be a bit of a pain. So, there's
another way that's not obvious, but is
a bit quicker than selecting each button
in turn, and clicking its clear
constraints button. So what you need to
do is draw a rectangle to enclose all
the buttons, taking care to avoid the
other three widgets. So I want to come
down here and click, and I'm going to be
very careful just to include the 16
buttons. So I haven't touched the
TextView or either of the two EditTexts.
And by the way, you can confirm that
looking in the Component Tree, that both
EditTexts and the TextViews haven't
been selected here, but all the other
buttons have been selected. And again,
remember when you're doing that, you
don't have to fully enclose a button to
select it. And another alternative to that
was that I can just
unclick that or de-select that. I can
actually click on one button, and I can
right-click and click on Select, and
Select Same Type. That will then select
the rest of the buttons, or in this case,
all the widgets on screen of the same
type, which is button in this case. Now
once all the buttons are selected, if we
hover over that, we can see that the
clear constraints button for each one
becomes visible as we move over it, so we
just need to carefully click each one. I
just need to come over here and just click
each one as we go through. Now if you go
a bit fast, you might find that the
buttons get un-selected. That's fine - it just
take seconds to select them all again,
using either of the methods that I've shown
you. So I'm going to continue through and
clear the rest of the constraints for
the buttons - and the last four now. Alright,
so that's now the constraints cleared.
Did I miss that one? Yes I did. So, you can
see now on the screen, that looks to me
like we've actually now successfully
deleted
all the constraints from the buttons.
Now that I've done that, I'm just going
to click on a blank area. And because
we're in portrait, what I'm going to do
is just bring back the Designer as well.
Obviously, with the landscape version
when we're editing that, it made more
sense just to have the Blueprint. Because
we can fit both on there, I like to see
them both at once if possible,
although I still do my work in the
Blueprint. But just if you did want to
have just the one, another alternative is
just to go back to the Blueprint, and you
can then increase the size and get that
bigger - obviously, that's too big for my
monitor now - if you want to sort of see it in a
larger size. But in this case, we've got
enough screen real estate for both, so
I'm going to have both and leave them on the
screen. Alright, so I need another button,
and I could just drag one in from the
palette, and set all its size
properties, etc. But again, when you're
working with a group of widgets that are
all very similar, it's often easier to
just copy and paste one of them, as we've
seen in previous videos. So again, going
to choose the divide button, I'm just
going to right-click that and choose
copy. Then I'm going to right-click on a
blank area of the Blueprint
and choose Paste. As before, you
briefly saw another button animate and
appear over the top of the divide. You
want to make sure that it's selected in
the Component Tree, and we've got this button
Divide2, so I'm going to click on
that
so it's selected. And we're going to
change a few things, and we're going to call
it buttonNeg, like we called it in the
landscape version - the landscape
layout - a buttonNeg. And we also have
the text here. We're going to change that,
and the text will say Neg. Press Enter
there. And the other thing we're going to
do, if you recall, we changed the text
properly, or sorry, the textSize property
to 12sp. So let's go ahead and do that
as well - 12sp - just so it fits in a
little bit nicer with the rest of the
buttons. Now, here the ID is very
important. It has to be the same ID that
we've given it in the landscape layout,
and if we just briefly go back to the
landscape layout - our NEG button.
We call it buttonNeg, back here, button
Neg in the portrait version. And
remember that our code's already
referring to a by ID, in any event.
Alright, so what we need next is a
baseline constraint from each button in
the two outer columns, to the button on
its right or left, working in towards the
central row.
So let's go ahead and do that. So I'm
going to start over here with the 7. So I'm
gonna set a baseline constraint, and set
that to 8, and 8 I'm going to set to 9. So
select 8, constraint, set that to 9. And
the other thing I haven't done yet, I
haven't moved the NEG button. So I'm
gonna move that briefly so we can see it a
little bit there.
Now with the NEG button, we want to set
the constraint to the left, in this case.
So I'm going to select that, select the
baseline constraint, constrain that to the
divide. Then the divide button, I'm going
to set a constraint to that - that's going
to be constrained to the 9. So I'm going to
do the same now for the rest of the
buttons. So I'm going to do the 4;
baseline constraint to the 5. The 5; baseline
constraint to the 6,
and then the asterisk, we're going to a
baseline constraint to the 6. And let's
go and continue on now with the 1;
baseline constraint to the 2 - try that
again. And the 2, we're going to constrain
to the baseline - whoops, I'll just undo
that change - baseline constraint to the
3, and the minus sign; baseline
constraint to the 3. And the last
line now; baseline constraint for the
zero to the dot, and select the dot; baseline
constraint to the equals. And the plus,
we're going to do a baseline constraint
to the equals, and then the NEG - I need to
do a baseline constraint to that. I'll do
that when I try to move it, and then I'm
going to baseline constraint to the
division, the divide by button. Alright, so that's the
first step done. Next on the top row only,
we need a right or left constraint on
each button in the outer two columns,
again, working in towards the central
column. They're all actually a little bit
close together at the moment. So starting
at 7 - this is the top row only - we
want that, we need a right or left
constraint on each end of the button
in the outer two columns, again working
in towards the central column. So I'm
going to add the constraint to the e6,
and the 8, I'm going to add a constraint
to the 9. On the other side, I'm going
to add the constraint for the NEG to
the divide, and then click on the divide,
constrain that to the 9. And they are
pretty close together, so it's a good
idea to check the inspector as you're
doing that, just to make sure that they
are constrained. So we've got 8 and
7 both constrained, as you can see
there, NEG is constrained, as is the
divide. Now 9, at the moment,
hasn't got any constraints. We're going
to now, moving up, working up from the
equals button, up down here, each button
in that central column, effectively, needs
its top edge constrained to the bottom of
the button above. So I'm going to click
on that; constrain the equals to the
3. I can see at the top there, where
I've added the constraint or not. From
the 3, I'm going to constrain to the
6, and
again, I'm looking at the margins in the
inspector to say that that is working.
And from the 6, I'm going to constrain
that to the 9, and you can see that
we've added the constraint at the top
there, for that as well. Now button9
will have its top edge constrained to
the bottom of the newNumber EditText
widget, and if you recall, newNumber is the
second one. So I'm gonna click on 9
and constrain that to the newNumber, and you
can see we've got a constraint on there
now.
Alright, so finally, every button in the
bottom three rows needs to have its left
edge constrained to the left edge of the
button above, with a margin of zero. And
you can make that easier if you like, by
changing the default margins to zero,
using the button on the toolbar. So I'm
going to go ahead and do that, and change
that to zero. So again, what we're doing
is, for every button in the bottom of
three rows, we want its left edge
constrained to the left edge of the
button above. So I'm going to start with
4; constrain that to the 7, the
1, I'm going to constrain to the 4,
and the zero; constrain that to the 1.
And I'm going to do the same for the
next row, because we're doing this
for the bottom of three rows now, have
everything in those three rows. 2 there,
the 2, and for the 2 we're going to
constrain that to the 5. The 5 I'm
going to constrain to the 8, the
equals I'm going to constrain to the
3, the 3 to the 6 and 6 to the 9, and
then the plus, I'm going to constrain
to the minus. The minus, I'm going to
constrain to the multiplication one, and
the multiply, I'm going to
constrain to the divide. And I'm not sure
whether I did the minus there, did I?
Yes that's constrained. And again, when in
doubt you can click on any control, and
just check that we've actually got a
margin there, and that it has been
constrained.
Okay.
Now I know that I deleted all the
baseline and edge constraints just to
recreate some of them again, but it's
often safer to work with a clear slate,
when you're making significant changes
to constraints, like we were here.
Deleting just the side constraints for each
button individually would have been very
fiddly as well, and a good way to make a
mistake. So the layout now, should match
that second slide, which I'll just put on
the screen briefly. And I can test that
now, now we're back in Android Studio, by
dragging the button9 around. Let's go
ahead and do that, and you can see when
I'm moving button9 around, everything
is actually moving correctly. So
basically, all the other buttons are
following it. Now if any don't follow, it's
very easy to spot and fix up their
constraint, because you'll know the
button that's not moving that needs to
be actually adjusted. Now I didn't
actually increase all the margins when
producing the slide, so it was easier to
see the constraints clearly, but, apart
from the spacing, our layout should match
that slide. If any buttons look out of
line, then check the top and left or
right constraint margins, as
appropriate. Alright, the final step now
is to centre button9 in the layout.
We're going to do that by creating
constraints from its left and right
edges to the edges of the layout, and
then making sure that it's horizontal
slider is set to 50%. So I'm going to
start by doing that. So I've got the 9 -
constrain that to the left first. And you
can see that it's all moved off screen,
but that's fine, we're gonna click on 9
again and constrain the right hand side.
That brings it all back nicely. And we
just want to make sure that the
horizontal slider up here in the
inspector, is set to 50, which it is in
this case. Now button9's top constraint
margin should be 8dp. At the moment, it's
much larger - it's set to 20. So let's change
that to 8dp, so it's closer to the Edit
Text. And as you saw me do it there, it's
a lot easier to do that in the inspector,
rather than trying to drag it into
position. Alright, now that we've done
that, I'm gonna drag the buttonNeg in
the Component Tree, so that it's just
below the buttonDivide, as I did for
landscape - our version of this layout. And
now I'm just going to reformat the XML;
Code, Reformat Code. No lines needed to
be changed there. And importantly, let's
now run the app to make sure it works in
both portrait and landscape,
bearing in mind that last time when
we went into portrait mode we had a
crash. And now it's working nicely, as you
can see. So I should be able to press the
NEG button; 55 equals. That's working
nicely, and I should be able to go to
landscape mode again and put NEG
twelve times, and that's working nicely.
Now if he app happened to crash in
portrait mode when you tapped the Neg
button, use the option, back here in
Android Studio under Build, to Rebuild
Project. And that's because Instant Run
tries to update the app on the device,
rather than installing it from scratch,
and it can sometimes run into
difficulties and cause problems. But
rebuilding the project will fix that. And
in my testing, I did find it failed to
update the portrait layout correctly on
Windows sometimes, but rebuilding the
project solved that problem. Alright, so
that's actually the end of the
Calculator app, and this section - for now
anyway. I want to show you how to use the
chains in the ConstraintLayout, and
our grid of buttons is a great
way to demonstrate that. So I'm going to
be coming back to this app a little bit
later. But in this section, we covered
layouts and the layout designer in
greater detail, as well as looking at
ways to constrain groups of widgets
together, and to position the group in
the layout. And we also looked at
the guidelines that are available in the
ConstraintLayout. We created code to
respond to button clicks, and used the
same listener for groups of buttons -
which is generally more efficient when
the buttons performs similar tasks. We
also saw how to create different
layouts for both portrait and landscape
modes, to handle situations where widgets
just wouldn't fit comfortably in both
orientations. Now I also showed you a
technique for testing a layout with your
code, before creating all the layouts
that are required - that way you can be
sure that you're on the right track,
before investing a lot of time creating
multiple layouts. Alright, I've got some
homework now to finish off this section,
and to do that, we need the calculator
running. So I'm just going to run that again,
and we'll go hover over to it. So a strange
quirk of the calculator is that you have
to use the equals button to clear
everything off, in order to start a
completely new calculation.
For example, if I type in six divided by
two minus three, three equals; zero. But if
now I want to multiply nine by five, I enter
nine multiply, but because that tries
to multiply zero by nine, it doesn't work.
So what I actually have to do, is type
equals, or press equals, nine equals
star five, and now I get the answer 45
when I press the next operator button.
That's not very intuitive, and it might
be better to have some sort of clear
button to clear the result and start
again. So as an exercise, your homework is
to add a clear button to the calculator.
Now I'm not going to be going
through that solution to that in a video.
The real test that you've got here is,
does it work when you try to implement
your solution. Alright, so moving on in
the next section, we're going to start
looking at downloading XML data from the
internet, and parsing it to display the
information. And we're also going to look
at performing slow operations, such as
downloading on a separate thread, so the
app remains responsive even if it's busy
downloading. So let's move on now to the
next section.