I have been slowly working more with Android and as I go I find myself in the need to do more complex stuff. I have been recently working on the UI side and I have been asking friends who have more experience with Android to review my code and I learned that I was doing some things the wrong way.
I come from a web development background so while I was learning how to use Android layouts I was looking at ways to translate what you do in Android with what you would do in the web. In Android we have layout files which are written in XML and live in res/layout/. When I started I pictured these being my HTML files, which is not completely correct. For styling android apps we use another XML file that lives in res/values/, these I thought of as being my CSS files.
Following this frame of thought this is how one of my layouts would look:
1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/ScreenLayout">
<Button android:id="@+id/save"
android:text="@string/save"
style="@style/MainButton" />
<Button android:id="@+id/cancel"
android:text="@string/cancel"
style="@style/MainButton.Cancel" />
</RelativeLayout>
And then, since I want to have the cancel button at the right of the save button I would have this in my style file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="ScreenLayout">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">fill_parent</item>
<item name="android:orientation">vertical</item>
</style>
<style name="MainButton">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
</style>
<style name="MainButton.Cancel">
<item name="android:layout_toRightOf">@id/save</item>
</style>
</resources>
To me, this way of doing things made perfect sense. We have the layout file specify semantically which elements are part of the screen and then have the style file define margins, sizes and positions. When I showed this to my Android developer friends they yelled at me about the MainButton.Cancel style. Their strongest argument was about referencing an id from the styles as I do for the MainButton.Cancel style:
1
2
3
<style name="MainButton.Cancel">
<item name="android:layout_toRightOf">@id/save</item>
</style>
We had a long discussion about how in web we keep our HTML semantic and then we take care of the layout in CSS, but at the end their arguments made good sense.
Layouts don’t translate directly to HTML, they don’t only specify which elements are in one page, but also how they are laid out, so all the information about their positions should be part of the layout file. This means that instead of having layout_toRightOf in a style file I would have it in the layout file:
1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/ScreenLayout">
<Button android:id="@+id/save"
android:text="@string/save"
style="@style/MainButton" />
<Button android:id="@+id/cancel"
android:text="@string/cancel"
style="@style/MainButton"
android:layout_toRightOf="@id/save" />
</RelativeLayout>
Doing it this way will allow you to know how this layout looks without having to look at your styles, it also makes your style file smaller so it is easier to read.
Reusing layouts
One thing that felt weird about android is that because you don’t have something like an HTML class, it seemed like the layouts couldn’t be reused the way they are in HTML. I asked about this an the answer to this problem is to use nested layouts. We can create a layout file like this and call it child.xml:
1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/TwoButtons">
<Button android:id="@+id/save"
android:text="@string/save"
style="@style/MainButton" />
<Button android:id="@+id/cancel"
android:text="@string/cancel"
style="@style/MainButton"
android:layout_toRightOf="@id/save" />
</RelativeLayout>
Define the styles for TwoButtons in the style file:
1
2
3
4
<style name="TwoButtons">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
</style>
And then we can include the child inside of a parent layout:
1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/ScreenLayout">
<include layout="@layout/child" />
<include layout="@layout/child" />
</LinearLayout>
And this would be the result:
However, this has some repercussions. Now, you have two elements with the same Id on your layout, so you can’t directly use findViewById. To fix this we need to assign an id to each of our include tags, select that view and then look for an element with an specific id inside:
1
2
View include = findViewById(R.id.first_include_id);
Button b = (Button)include.findViewById(R.id.new_entry_button);
android
design_patterns
java
mobile
programming
]