Well isn’t the whole layout concept a strain on the old grey matter, let alone trying to align things with gravity or layout_gravity only to have it not lay out as you would typically expect.
Most of us (not all) are coming to Android from a Web background and as such we’ve been spoiled by a few things that we assume translate over into Android (or for that matter, any other layout centric platform).
Definitions
Let’s start by defining the different properties, then we’ll explore the implications of those differences and finally, explore the subtle differences that we’ve taken for granted all those years of writing HTML layouts.
android:gravity — Defines how to align this view’s CONTENT (ie. what this view has inside of it).
android:layout_gravity — Defines how this object acts WITHIN it’s parent (ie. how this view acts within the parent view)
Ok, if that isn’t the most confusing simplification I’ve ever had to explain, I don’t know what is! :)
Gravity – how it works
This ain’t a physics article so what I’m about to explain can actually be tested and proven :P
Android views that support gravity will have it noted in their documentation. If an view does not define a gravity (or layout_gravity) property then gravity can not be applied against that view itself.
So how do I align something that doesn’t implement a gravity property
Well the only way to do it is to (*sigh*) wrap the view within another view that DOES support gravity.
Actually this is the expected way it is to be done. So for those of you who don’t like nesting layouts unnecessarily, I’m sorry, but gravity will only work within view objects that specifically support it.
The desired outcome
In this example I want a layout that has three TextView’s, one left aligned, one right aligned, both on the same “line”, and a third on the next “line”, centered.
Step 1 – Adding TextView1 and TextView2
Let’s get started by simply adding the two textviews to the layout.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <TextView android:id="@+id/textView1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Text View 1" /> <TextView android:id="@+id/textView2" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Text View 2" /> </LinearLayout>
Here we have a LinearLayout that fill_parent in both vertical and horizontal directions. TV1 and TV2 are atypical textviews and fill horizontally but wrap vertically.
TV1 is aligned left by default so we won’t need to touch it, but how to we right align TV2?
Being spoiled by Web I typically would align the item right and so for layouts I would have to use gravity. Reviewing the TextView class documentation I can clearly see that there IS a gravity property. Though, by the very definition set above, android:gravity would align the CONTENT within the TV (in this case the text), which essentially is what we want.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <TextView android:id="@+id/textView1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Text View 1" /> <TextView android:id="@+id/textView2" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Text View 2" android:gravity="right" /> </LinearLayout>
The resultant layout is as follows.
Problem 1: TV1 and TV2 are on separate lines
So how do we get them on the same line? Well here’s where the (*sigh*) nested layouts come in to play. A view will typically use an entire “line” (there are exceptions to this rule of course), so even if you changed the TV layout_width from fill_parent to wrap_content you’ll get two TV’s on two lines, just left aligned :)
So we’ll make two new LinearLayouts and put the TV’s inside one each like so:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/textView1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Text View 1" /> </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/textView2" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Text View 2" android:gravity="right" /> </LinearLayout> </LinearLayout>
Which produces this wonderful change to the output like so:
Nothing was changed because all we did was encapsulate the TV’s behaviour within a View that was not told to change it’s childrens behaviour!
But we did gain something, the capacity to implement android:gravity whilst encapsulating the TV’s within a set of layout groups that are designed to help, you guessed it, laying out!
Step 2 – Using android:gravity within nested layouts correctly
We first need to understand that the layout_width of fill_parent on TV2 is causing some issues. If a view (namely TV2) is going to fill up as much space as it can, how can it be put along side another view (namely TV1) on the same line who is also layout_width of fill_parent? Well simply put, it can’t. So we need to wrap_content on both the TV’s in order for them to allow their parent LV’s to handle their placement appropriately.
So let’s wrap_content the TV’s. Though by doing so, we’re effectively removing the functionality of the android:gravity that we applied to TV2 (as it’s never going to be any wider than the content, therefore it’s never going to have the space TO align it).
To explain that concept a bit more, I’ll highlight the actual area taken by the TV’s within the LV’s so you can see the point.
The new source code looks like this:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Text View 1" /> </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Text View 2" /> </LinearLayout> </LinearLayout>
As you can see, by using wrap_content for the layout_width on both TV’s we’ve reduced the amount of space available. This means, that android:gravity of left, center or right effectively would not move the content anywhere because it is not able to move and therefore android:gravity will have no effect.
Step 3 – Bringing both LV’s together on a single line
By default a LV’s orientation is horizontal. For me this was strange as a Web dev everything is vertical (which kinda seemed logical at the time) and effort is needed to bring things up on the same line. In android it’s the opposite and effort is still required to keep things on the same line, but for a different reason (of course!)
So guess what? We’re gonna need another LV (*sigh*) to handle the single line layout, and allow the nested LV’s to handle their respective TV layouts.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content"> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Text View 1" /> </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Text View 2" /> </LinearLayout> </LinearLayout> </LinearLayout>
Which results in this, completely disturbing, hair pulling, cortisol producing scenario as illustrated below:
Problem 2: Where did my TV go?
Well if you look at the source code you’ll see that both LV’s holding both TV’s are layout_width of fill_parent. Since the grand parent LV holding the two LV’s is now bringing the LV’s on to the same line, and since LV1 is using up 100% of the screen size, LV2 and TV2 are now pushed off the right hand side of the screen.
Why didn’t it wrap as I expected it to?
Well you didn’t ask it to wrap to be frank. You said, use up 100% of the screen for LV1 and so the layout had no choice by to render LV2 outside the viewable area of the screen. Had your grand parent LV had it’s orientation set to vertical then the “wrapping” you thought was going happen would have been “simulated” even though that’s NOT what it’s doing.
Step 4 – Implementing android:gravity correctly
So let’s go ahead and change a few things. First, let’s make TV1′s LV layout_width = wrap_content. This will allow both TV’s to be displayed as so:
Next, since we know TV1 doesn’t need to be touched, let’s focus on TV2 and LV2. Though it is not necessary, I will add an android:gravity of left for TV1 so that any future dev looking at the layout can clearly see that my intention was to have TV1 left aligned and TV2 right aligned.
As you can see, LV2 layout_width is fill_parent. Have a look at the amount of space being used by LV2. TV2 is only using as much space as is necessary (layout_width = “wrap_content”), so now we can add gravity to LV2 to align TV2 correctly like so:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content"> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="left"> <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Text View 1" /> </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="right"> <TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Text View 2" /> </LinearLayout> </LinearLayout> </LinearLayout>
Which produces our solution to problem 1, having two views on the same line, one left and one right aligned using android:gravity correctly.
Step 5 – Implementing a TV center aligned
Well considering the above issues we’ve faced, this next task is quite simple in comparison. So the plan is, since we have two LV’s within a grand parent LV which is contained within an over arching LV, we will add yet another LV as a sibling to our grand parent LV. These two will act as our “lines” and so grand parent LV will handle the two TV’s on a line problem and our grand parent sibling will handle our one TV centered problem as so:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content"> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="left"> <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Text View 1" /> </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="right"> <TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Text View 2" /> </LinearLayout> </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center"> <TextView android:id="@+id/textView3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Text View 3" /> </LinearLayout> </LinearLayout>
Thus producing our desired outcome layout as requested.
As you can see on line 34 the android:gravity is set to center whilst on line 32 we’re asking the LV to take up as much space as possible (ie. layout_width = “fill_parent”). This means that android:gravity has space to move the TV as the TV has requested that it’s own layout_width is wrap_content.
Had TV3 set it’s layout_width to fill_parent we’d have been stuck in the same situation again whereby there would be no space for android:gravity to work and TV3 would effectively be left aligned.
Though if we had to have the layout_width on TV3 set to fill_parent, we could simply have used android:gravity on TV3 to align the textual content center and remove the android:gravity from the LV as so:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content"> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="left"> <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Text View 1" /> </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="right"> <TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Text View 2" /> </LinearLayout> </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/textView3" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Text View 3" android:gravity="center" /> </LinearLayout> </LinearLayout>
Conclusion
Perl said it best with their slogan, “there’s more than one way to do it”. There really isn’t a “right” way to do layouts, though there is a correct way to implement android:gravity on elements that you are laying out.
Layouts require planning and forethought. If you go into doing a layout without thinking about how you’re going to lay things out, you’ll be stressing out in no time!
Android layouts are extremely well thought out, especially since we have to deal with multiple screen sizes, orientations and more.
Coming from a Web background is fine as long as you accept that you have to learn a slightly augmented paradigm in order to use those existing skills. Everything is pretty similar, though it does have a few gotchas, like anything I suppose!








Thanks a lot!
Finally found answers to what I was looking for!
Great walk through, really clarified things up for me. Cheers!
Best description of android layout yet, really cleared things up for me. Thanks alot.
Hi, I was able to implement the top with only one level of nesting:
<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
android:orientation=”vertical” >
<LinearLayout
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:orientation=”horizontal” >
<TextView
android:id=”@+id/textView1″
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”Text View 1″ />
<TextView
android:id=”@+id/textView2″
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:gravity=”right”
android:text=”Text View 2″ />
</LinearLayout>
<TextView
android:id=”@+id/textView2″
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:gravity=”center”
android:text=”Text View 3″ />
</LinearLayout>