Android UI Development 101 — Part 2: ViewGroups!
Learn the tools to become the new Picasso in Android!
In Android UI Development 101 — Part 1: Views, we had a taste of what are Views and where they stand in Android development.
Now, before we talk about ViewGroups, I want to revisit the official documentation description of Views, specifically the words building blocks. Indeed, they are, but, if they are just the blocks, then who is the builder?
Imagine you traveled to Pisa and you were flabbergasted at its beauty in the sunset. You thought of taking a picture, but it wouldn’t be the same as painting it with your own artistic impressions! The first step would be to take the needed material. One of the first things that comes to our mind is the paint colors that would match what you see. These would be your blocks, that is, what you will actually put on the screen, right? However, paint is just paint if you don’t use something to play with it, so you would also need a canvas, a wooden stand and the brushes. These, along with your hands and mind, would be your builders, that is, the tools you would use to actually produce your masterpiece.
So, after our quick and lovely travel to Pisa, we understand that we need both the blocks and the builder to produce a painting. In Android, it’s exactly the same. While Views are the blocks, ViewGroups are the tools, or builders. From the official documentation:
A ViewGroup is a special view that can contain other views (called children.) The view group is the base class for layouts and views containers.
Although the documentation uses a much more technical jargon, let us remember the words tool and builder. We will focus on the “base class for layouts and views containers” part.
We use ViewGroups to hierarchize and organize our Views in the screen; put them in the form of a vertical or horizontal list; put one below the other; show a View atop another one and so on.
There are many ViewGroups and new ones are frequently developed by Google and Android developers. However, I would like to focus on four of them, which get most of the work done:
If you learn how to manage and efficiently combine these four, you will get a lot of your work done.
Some of their names are more obvious than others, ScrollView being the most one to me; you want to use it to be able to scroll your screen! But I find LinearLayout more abstract. Don’t worry about memorizing them at this moment; as you understand their use and practice, it will become easier to remember.
What is also very important to point out is that, when you are implementing a screen, there isn’t really just a single way to organize your Views. You may find two, three or even more ways to make the same screen. However, in this context, less is more; the less you nest the ViewGroups in the XML, the lower the cost will be in terms of performance:
The most common case in which layout takes an especially long time is when hierarchies of View objects are nested within one another. Each nested layout object adds cost to the layout stage. The flatter your hierarchy, the less time that it takes for the layout stage to complete.
Also, it tends to make your XML harder to understand and to change later, as your XML increases in number of lines and complexity. As with any case where you have a limited amount of resource, you will want to spend it in the most efficient way possible. You don’t want your app to use too much of a smartphone’s memory, battery and processor.
So, the painting metaphor also applies here: before you start implementing, try to organize how the elements will be displayed first and, only then, implement the screen, just as a painter first makes a draft before starting to paint. It helps a great deal to draw the screen in pencil and paper with your blocks, which you will, then, translate into code.
Having all that in mind, let’s start talking about one of my favorite and practical ViewGroups!
As its name intends to convey, this ViewGroup organizes Views in a linear fashion: vertically or horizontally.
Picture books organized in a bookshelf. You probably thought about them positioned horizontally, side by side, right? That is the fundamental idea behind LinearLayouts — you put View after View in either of those directions.
The picture below is a very good example of how a LinearLayout works: you give it the Views you want (in this case, the books!) and the LinearLayout (the shelf!) will display them orderly, one after the other, either vertically or horizontally; it cannot be both vertical and horizontal at the same time, but you can nest two LinearLayouts to produce that effect.
In a development context, there is a great number of uses you could attribute to this ViewGroup, such as listing text vertically, or and image with a text below, and so on; I’m sure you can imagine many uses for this one.
I also want to point out one of the most interesting attributes this ViewGroup has, which is the android:layout_weight attribute.
There will be many times where you will want to distribute Views evenly in the screen or that a View has a certain percentage of the screen, such as displaying two pictures side by side matching the screen width.
<?xml version="1.0" encoding="utf-8"?>
In this example, both ImageViews represent the pictures I want to have evenly divided in the screen. I set both their widths as android:layout_width=”0dp”, since I want that dimention to be determined by the weight. Then I set their weight by adding android:layout_weight=”1" to each of the tags, specifying, then, that I want each of them to occupy 50% of the parent’s width.
You can determine the android:weightSum for the LinearLayout if you want (if no weight is determined, the total weight will be the sum of the weight of the children) and give each child its respective weight. In this example, I didn’t and the implicit android:weight_sum here is 2 (so having 1 as the weight equals 50%; bingo! Makes sense, right?).
It is very important to notice that, for android:layout_weight attribute to work, you must set the desired dimensions (either width or height) to be 0dp. In this case, we want the width of the screen to be divided equally, so we set the Views weight to 0dp.
The weight attribute is one of the most powerful tools of the LinearLayout, so it’s a good idea to remember this property in the future, because, even though it is possible to calculate programmatically the width of the screen and to assert the correct amount of the width to each View, it is much more complex than simply giving each of them a percentage. It will also make your layout more responsive.
There is one important consideration to be made about LinearLayout. Using a LinearLayout to render a vertical list that has a considerable number of views in it may result in a decrease of performance, because LinearLayouts do not have such an efficient usage of memory. As mentioned earlier, you want to avoid spending too much of the smartphone’s resources, such as memory. Now, imagine you are using a movie app and that you want to list every movie starting with A. The list would easily have more than 100 movies, right? If you put them all inside a LinearLayout, the device memory would have to allocate a lot of its resources for that.
With that problem in mind, Google developed the RecyclerView. I am not going to talk in depth about the RecyclerView in this article, as it is more complex and would require an article for itself, but you should take a look at the official documentation; I have no doubt that you will eventually need to make a list that can grow quickly in number of views.
Next, a layout I am certain Einstein would be most proud of were he alive to learn about it. And, no, it’s not about people in your family.
As its name readily implies, RelativeLayout is all about having Views placed relatively to others. You might think “Alright, but that’s the same as a LinearLayout, right?”. It’s true — LinearLayouts also place Views relatively to others, in vertical or horizontal sequence. You are right, and, as a matter of fact, there are cases where either LinearLayout or RelativeLayout would work to build the same UI. However, RelativeLayout offers more flexibility when placing Views relatively, which means you can build the same blocks as LinearLayout but with less complexity.
The most important attributes that express the RelativeLayout potential are layout_below, layout_toRightOf, toLeftOf and layout_above, to name some of them. These attributes are the main reason for using this ViewGroup and, if you are not using them, then it’s a sign that you could probably use another ViewGroup. Also, in RelativeLayouts, some of the attributes used for gravity are layout_alignParentTop, layout_alignParentBottom, layout_alignParentRight and layout_alignParentLeft, which are equivalent to other ViewGroup’s layout_gravity attribute.
Let us use an example to illustrate its use: imagine we want to have the configuration described in the image below. Using a LinearLayout would certainly be possible here too (and I recommend you do the exercise of using it!), but it would be more complex. With a RelativeLayout, the View hierarchy is more flat and simpler.
<?xml version="1.0" encoding="utf-8"?>
Take note that we assigned an android:id to the Views so that we can specify how each of them will be positioned relatively to another. I used, in this example, android:layout_below and android:layout_toEndOf.
And now you might be thinking “Fantastic! A flexible layout, I will never use LinearLayout again!”. That’s the feeling I had when I found out about it, but that’s not true. Imagine having a sequence of 10 TextViews listed vertically. You would have to use layout_below 9 times (!) here, while you could just put them inside a vertical LinearLayout. And suppose you want to remove the 2nd, 4th and the 6th ones because you don’t need those elements anymore — can you imagine the torture of changing each of the layout_below attributes in each of the TextViews? Yikes. Meanwhile, with a LinearLayout, you would simply erase those Views and it would do all the hard work for you.
In summary, RelativeLayouts are a ViewGroup that can be used to have a more flexible positioning of Views and flatter View hierarchy. However, be prudent when using it, because, once your screen grows in number of Views and you start to assigning each of them to be relatively positioned to others more and more, you may be creating a Jenga tower — remove one of the Views and the rest falls with it!
Next in our journey, a ViewGroup that has a name glorified by cinephiles and painters.
This is a very interesting ViewGroup for a main reason: you can stack up, pile Views on the screen. So far, we talked about lining up Views in a certain direction or placing them in relation to one another, but all those movements are in the XY axis of the screen. With FrameLayout, we are also able to work in the Z axis, which adds depth to the screen.
So, imagine you have a background and you want to put text centered on it. If you use Facebook, you probably have already used this feature! You can easily achieve that by using a FrameLayout:
<?xml version="1.0" encoding="utf-8"?>
android:textAlignment="center" //to center the text
android:layout_gravity="center" // to center the TextView
android:text="Hooray! You now know how to use the FrameLayout"/>
As you probably noticed, which View goes on top has something to do with the order they appear in the XML. Indeed, the View that is placed most at the bottom of the FrameLayout container is the one who will appear most at the top in the screen, “closer to the user”. So, as our XML points out, the text will be at the top of the image, because it’s placed below it in the XML.
There is an important detail: even if you place a View on top of another, you can make it vanish by setting it’s visibility to gone. The View underneath will be, then, completely visible.
You can stack up as many Views as you want. So, you could have put a View with a background under the image and the text on top of the image, it would have worked too.
You can use FrameLayouts to make full screen loadings, in example, putting the loading component on top of the screen content and managing the loading visibility. Or, perhaps, you want to use a failed connection placeholder on top of everything should something wrong happen. Or maybe you just want to add a colored header on top of a portion of your screen content.
The key point here is piling up Views; whenever you need to put one on top of another, it’s a good idea to remember this ViewGroup.
FrameLayout can also be used to just “hold” Views. Suppose you have an image and you want to have the screen with a colored background; you can set the FrameLayout background with the color you want and put an image within it. LinearLayout and RelativeLayout would also work, but I like to think of FrameLayout as a sort of simple ViewGroup that should also be used for the simplest tasks (no orientation required and you don’t need those different attributes like RelativeLayout to determine the gravity of the content).
And, now, to the last ViewGroup we will see today, although its name does not end in “Layout” as the other ones.
I believe this is the most intuitive one, since we have all been using browsers for quite some time. When your screen cannot show you all the content, you need to be able to see the rest. In Android, this is achieved by either scrolling the content up or down, left or right, so it becomes visible in the screen.
But there is a catch about it. The ScrollView itself does not organize your Views — it doesn’t arrange them linearly, in relation to one another or in a stack. ScrollView needs a ViewGroup inside it so that it can work.
As an example, you could put a vertical LinearLayout within it and, if its total height occupies a space greater than the screen size, then, when the user swipes the screen up or down, the content you couldn’t previously see will show up, just as you would do in a webpage. And, by the way, ScrollView only accepts a direct single child, that is, you can only put a single ViewGroup directly into it. That ViewGroup can have as many children as it wants, but it’s mandatory that the ScrollView has only one. Since LinearLayouts tend to grow quicker than Relative or FrameLayouts in size, as they are used to list elements (which can make the list increase fast in size), they are more used as child ViewGroups in ScrollViews.
<?xml version="1.0" encoding="utf-8"?>
android:text="Hooray! You now know how to use the ScrollView"
android:text="Hooray! You now know how to use the ScrollView"
ScrollViews scroll vertically. If you want to have a horizontal scroll, then you would need to use a HorizontalScrollView. The concept is the same; it can only have one direct child.
It’s always a good idea to use a ScrollView when you have even the slightest impression your screen will have more than just a text and an image, which will be most of the cases.
You may be asking if you can use a ScrollView inside another ScrollView, like you can do with the other ViewGroups. Yes, you can, but you must use a NestedScrollView. It must be at the top of the hierarchy, with a regular ScrollView inside.
Phew! You now have much to think about all these ViewGroups. I strongly recommend that you think about screens you would like to implement and experiment with what you have just learned. Doubts may arise, and you can use this article, the link references and StackOverflow to aid you.
In the next section, I you can find a summary of good practices that I have noticed after some time developing UI; you don’t have to follow them, but these are some points that I found useful.
- Remember that Android devices come in various sizes, so it’s a good idea to test your app with as many devices as you can. Your screen should also be prepared to adapt to different screen orientation configurations (such as landscape) if your app supports it.
- Be careful with testing the functionalities just with an emulator; it’s not always accurate. Your final tests should always include real devices. I already found myself struggling to solve a bug in the emulator, just to find out it was because of the debugger, which made me lose valuable time. Always trust a real device more than an emulator. I know, it is obvious, but you may find yourself thinking your logic or implementation is wrong when, in fact, the emulator is playing a joke on you. So, if you find an unexpected behavior using the emulator and everything in the code seems to be fine, test your app in a real device.
- With Android updates come new functionality. However, not everything is backward compatible. The Android Studio IDE usually issues warnings if you are trying to implement something that will not be covered in your targeted Android versions, but that’s not always the case. Also, a functionality may even work in previous versions, but in a different way. So, if you are either having problems with a specific version or unsure about something, check the official documentation, because it tells what is the minimum API level you need to use something. Stack Overflow is also a good friend in these moments.
- Always test the borderline cases for variables such as screen size, that is, either very small or very big devices. Take the weight attribute for LinearLayout as an example: if you want to divide the screen width between two texts equally, pay attention to content being squished, because if the width is too small to accomodate the text in a single line, the text will break into more lines. If you have images, it may be the case that they are distorted if the screen is very small or very big. Make sure you treat these borderline cases correctly.
- Always check if you don’t need scrolling in a screen, even if you have very few content in it. You may presume that 3 TextViews and a Button fit, but you may find that it won’t, specially in older devices, which tend to be smaller than the most recent ones.
These are some of the advices that I found very useful when designing UI for Android. Of course, as screens become more and more complex, you will need an even bigger checklist than the one I wrote, but these are basic yet very important points when you are designing UI or for Android in general.
By using the four ViewGroups we went through, LinearLayout, FrameLayout, RelativeLayout and ScrollView, you can build most of the UI in Android. Here is a summary for each of them:
- LinearLayout: list Views vertically or horizontally;
- RelativeLayout: place Views with their position depending on another View’s position;
- FrameLayout: stack up Views on the Z axis;
- ScrollView: when the content is too big for the screen size and you need to allow the user to view it all.
Each of one of them has particularities that evidence why they exist — use that to your advantage!
Don’t worry about memorizing now their names and properties, the most important now is to remember their core concept. You can take these concepts to other platforms as well, because you will probably need to arrange Views in some way, such as a list or positioning one of top of another, whenever you are designing UI.
I strongly recommend that you apply everything you read here in the form of code, so you can solidify your understanding. You could either create a screen using your imagination or try to reproduce a screen you saw in an app you use. Start using a single ViewGroup and, later, mix them to produce more complex screens. There is no problem at all if your first implementation has many nested ViewGroups, learn first to make it and improve it later. It’s always good to have the habit of revisiting your screens and finding better solutions!
References for further study
As you study, you will find even more links, but I wanted to give special attention to these four, because they will give you a lot to start with:
- Android Jetpack — This is an excellent website to find the most important topics about Android development. The website was recently launched by Google itself as they recognized that there is too much content spread out there and it may hard to keep up. So they had the idea to summarize the core concepts and tools for Android at the moment.
- Android Developers — the official Android development Youtube channel. Useful for getting updated on what’s new and to explore.
- Android Pub — Medium blog for Android developers full of interesting development articles.
- Hacker Noon — Medium blog with great articles about technology and development in general.
Thank you for walking with me through Android UI development! Get your canvas ready and start painting!