A (very) brief overview of Android Views and Layouts
First of all I'm assuming that the reader has a basic knowledge of how the Android GUI works so the "overview" is just for the sake of introducing concepts and not to teach anything new.
Every screen in an Android app is made up of Views. The Views are just (basically) XML elements that specify the components that will be included in a screen and attributes to configure them. The Views are arranged according to different layouts provided by the API, such as LinearLayout (horizontal or vertical) which positions one element after another, or RelativeLayout which positions every component according to (in a position relative to) the position of another component.
Every screen in an Android app is made up of Views. The Views are just (basically) XML elements that specify the components that will be included in a screen and attributes to configure them. The Views are arranged according to different layouts provided by the API, such as LinearLayout (horizontal or vertical) which positions one element after another, or RelativeLayout which positions every component according to (in a position relative to) the position of another component.
A simple example of a LinearLayout is this:
<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:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello" />
</LinearLayout>
Here we have a LinearLayout with a vertical alignment (with only one View, in this case, it doesn't really matter what alignment we use) and a TextView. This produces the following screen:
Gravity vs Layout_gravity
The two attributes we are going to work with have different meanings. We can define them as follows: gravity controls the position of the contents inside a component (take it as a container if you prefer), and layout_gravity positions that component in respect to its parent container.
In our previous example we have a parent container, LinearLayout, and a child View, a TextView. Following our definition, gravity will control where the text is positioned inside the TextView (its content) and layout_gravity will position that TextView somewhere inside the LinearLayout container. But at the same time gravity applied to the LinearLayout will control the position of the TextView inside it. Layout_gravity won't any effect though as the LinearLayout doesn't have a parent container where to position it.
It is important to understand how LinearLayout works and how it arranges its children Views. You can take it as a stack that pushes items inside it, one after another (and this is an important point) and not in a random position. I say that that's an important point because it is not possible (or rather it is not meant to) in this type of layout to place items in different corners or at random places. For that we would use a RelativeLayout instead.
Knowing this we'll avoid surprises when using layout_gravity (in child items) and not getting the expected results. For example, if we have a LL (LinearLayout) vertically aligned where the items are added from top to bottom, the values of layout_gravity will be limited to the horizontal ones (left, center, right). If they weren't and we were able to use 'bottom', for example, we would be modifying the structure of the stack and basically we might overlap and element that had been included in that position. Therefore this is not possible.
Have in mind though that these rules only apply to layout_gravity and not to gravity, as the content inside a View (for example, the text inside a TextView) is not controlled by a layout per se and therefore, inside the container that a View represents by itself, the content can be freely moved around.
Let's check some examples to see this more clearly.
This is a vertical LL and the possible values of layout_gravity applied to each of the TVs inside it (left, center, right). I have colored the bounds of the TVs to highlight the fact that it is layout_gravity (the View itself) we're playing with and not gravity (the content inside the View).
<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:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:text="@string/hello" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/hello" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="@string/hello" />
</LinearLayout>
The same happens when we choose a horizontal alignment, the values will be limited to vertical ones (top, center, bottom):
<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:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:text="@string/hello" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/hello" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:text="@string/hello" />
</LinearLayout>
As we can see in both examples the first item starts in the top-left corner and the rest go after it either to the right or to the bottom. Even though we use 'center' as a value for layout_gravity, the TVs will never be truly centered in the screen. So how can we achieve this? We said that 'gravity' controls the content inside a component, so if we want to center the contents (TVs) inside the container (LL), let's change the gravity of the LL to center. After all, the text is the content of the TV but at the same time the TV is the content of the LL. This will change the point around which all Views are created.
Got it! Now all the Views are created around the very center of the LL. If we unset the layout_gravity of the TVs we'll have them in the same position as the 2nd TV. Like this:
So far we have seen the effect of layout_gravity and gravity in a screen-wide scale depending whether they're applied to a container or its contents. Let's take our example to a smaller scale to put more factors at play such as the width and height of the container/View and check the effects of our two gravity attributes on them. The TVs in the examples we have used so far had their width and height set to 'wrap_content' which, as expected, limits the size of the TV to the size of its content.
Let's modify our layout and the Views inside:
<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"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello" />
<ImageView
android:id="@+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher" />
</LinearLayout>
</LinearLayout>
The TV is aligned to the top-left corner and next to it there is an ImageView. If we want to align the TV to the center of the IV we can take two approaches:
- layout_gravity: Since we have wrapped our Views inside an extra horizontal LL we are able to move the TV vertically to either the top, the center or the bottom of its container. Therefore changing the TV's layout_gravity to center should do it:
And indeed it does. Problem fixed!
- gravity: The approach with gravity entails modifying the height of our TV. Since we said that gravity positions the content inside the TV and the current width and height are set to wrap_content there is no physical space to move our text around. So first we'll change the height of our TV to fill_parent and then we'll change the gravity to center.
And voilà. The TV's height now fills/matches the height of the containing LL and its content/text is centered. I have to add that the value 'center' applied to gravity will center the content both vertically and horizontally. We can't see the effect here because the width of the TV is set to wrap_content. If we had wanted to be meticulously correct we would have used 'center_vertical'.
I hope I made myself clear and that everyone understands now the difference between these two attributes and the different scenarios where they should be used.








No comments:
Post a Comment