TabHost in Android Apps

TabHost displaying statistics in Android device

TabHost displaying statistics in Android device

The ‘Fitness Manager’ App provides several statistics for the user in order to check the workout progress. The different statistics should be displayed in a TabHost. A TabHost is a container for a tabbed window view. The TabHost holds two children. One child contains a set of tab labels that the user clicks to select a specific tab. The other child contains a FrameLayout object that displays the contents of that page. The TabHost integrated in the Fitness App should meet the following further requirements:

  • Every tab displays a button bar which contains a different amount of buttons depending on the selected tab.

  • Every tab contains an area where the corresponding statistics are plotted.

First I had to define the XML Layout for the TabHost in a XML Layout file. In Android Studio the container for TabHost is provided in the palette of the Android Studio designer. The TabHost can be simply inserted in an empty activity by drag and drop.

When integrating the container for TabHost, first the TabHost itself is defined in the XML Layout definition. The TabHost contains a RelativeLayout of the same size.

TabHost XML Layout definition

TabHost XML Layout definition

The RelativeLayout of the TabHost contains the definition of a TabWidget. The TabWidget displays a list of tab labels representing each page in the parent’s tab collection. The container object for this widget is TabHost. When the user selects a tab, this object sends a message to the parent container TabHost, to tell it to switch the displayed page.

TabWidget XML Layout definition

TabWidget XML Layout definition

The XML Layout definition for TabWidget contains the attribute android:id set to the value @android:id/tabs. This value cannot be changed and therefore the TabWidget cannot be accessed programmatically by using the function findViewbyId.

Additionally the RelativeLayout of the TabHost contains a FrameLayout. The FrameLayout is used for displaying the content of the TabHost.

FrameLayout XML Layout definition

FrameLayout XML Layout definition

The XML Layout definition for FrameLayout also contains the attribute android:id. The value for the attribute android:id is set to the value @android:id/tabs. This value cannot be changed either and therefore cannot be accessed programmatically by using the function findViewbyId. For every tab added to the container TabHost a LinearLayout is defined in the XML Layout definition of the FrameLayout. There you have the base frame for a TabHost. Now the LinearLayouts in the FrameLayouts can be filled with view elements like every other convenient view. GridLayouts or LinearLayouts can be inserted into the LinarLayout for ButtonBars or mobile forms. ImageViews, ScrollViews or ListViews can also be embedded by the LinearLayouts of the FrameLayout.

After finishing the XML Layout definition of the TabHost, the TabHost has to be instantiated programmatically in the onCreate method of the corresponding activity. The TabHost instantiation includes the definition of the single tabs. The tab of a TabHost has a tab indicator, content and a tag that is used to keep track of it. After declaring objects for every tab, the content of the tab is assigned by specifing the id of the corresponding view and the label is set as tab indicator.

TabHost instantiation

TabHost instantiation

In order to handle the user input action, when a different tab is selected, a setOnTabChangedListener must be implemented in the onCreate function of the corresponding activity. In this Listener the content of the selected tab can be set.

TabHost: setOnTabChangedListener

TabHost: setOnTabChangedListener

Now the basic implementation of the TabHost is finished.

But if your app should resize the content of the TabHost depending on the Android device or the orientation of the Android device, then you have to implement a runnable with post functionality. There the content of the tab must be accessed and the tab must be resized, which cannot be handled easily by calling findViewbyId as I already mentioned. The content of the tab can only be accessed via the container TabHost by host.getTabContentView().getChildAt(int i). The same access point is valid for the TabWidget of the TabHost: host.getTabWidget(). getChildAt(int i). Then for example the LayoutParams of the TabWidget or the content of the TabHost can be set.

TabContent LayoutParams definition

TabContent LayoutParams definition

Last issue I want to point out concerning TabHost is the Android device orientation. If the user rotates the Android device while displaying a TabHost in an App, then the tab is always set to the first tab of the TabHost with every rotation, no matter which tab was selected previously to the screen rotation. In order to solve this issue I did overwrite the function onSaveInstanceState of the activity and saved the current tab value.

Activity onSaveInstanceState implementation

Activity onSaveInstanceState implementation

Therefore I could access the savedInstanceState now in the onCreate and onConfigurationChanged functions of the activity and set the tab selected previously to a screen rotation.

Activity access of savedInstanceState

Activity access of savedInstanceState

And done ­čÖé

If you have any questions, any improvement suggestions for the implementation (I mentioned that this is my first Android App) or any improvement suggestions for my English, I really would appreciate if you can leave me a comment.

And I would even more appreciate if you like to check out the ‘Fitness Manager’ App in the Google Play Store or the ‘Fitness Manager’ App in the iTunes Store. See you.

Follow us on

Facebook
Twitter
Google Plus

Layouts for Android Apps

Fitness Manager start screen

Fitness Manager start screen

Unfortunately our awesome, great, incredible, wonderful and joyful travel year is over now. So we have to work and earn money to hopefully continue this experience soon. So I started to program and develop my first Android App. I want to write about the difficulties I ran into while developing my apps. Therefore I have to switch the language of my blog to English and the blog is obviously getting technical. I want to apologize for both. Ok, let’s start and have a look to Layouts for Android Apps.

My first App is called ‘Fitness Manager’ and the app is available for all kind of Apple IOS Devices and for many many different Android Devices. The App provides the user with useful features and functions around planning workout sessions in the gym. The start screen of the app leads the user to different main functionalities like ‘Create a workout schedule’ or ‘View statistics’ and to further sub tasks like ‘Upload data to the cloud’. In order to get this looking good in my eyes on every device I had to take a lot of issues into account.

You can embed LinearLayouts in GridLayouts or you can use TableLayouts surrounded by FrameLayouts. You have depending on the choosen layout several different layout options which you can set. The posibilities concerning the layouts are incredible. But you only have three possible values in the layout.xml to set the layout_width and the layout_height of every view item: match_parent, wrap_content or a fixed value. I wanted to insert a logo, an advertise view element, four big ImageButtons for the main functionalities and 4 small ImageButtons for the sub tasks into the start screen like displayed in the above image. And that’s how layout.xml for the start screen looks like:

  1. All view elements are embedded in a GridLayout with only one column but 5 rows.

    GridLayout of Fitness Manager start screen

    GridLayout of Fitness Manager start screen

  1. The logo is inserted in the first row of the GridLayout and the advertise view (not displayed in the image above) in the second row. In order to center the logo and the advertise view in every device the layout_gravity of every view element has to be set to center.

  1. Logo embedded in LinearLayout

    Logo embedded in LinearLayout

    In the next rows of the GridLayout I did insert the ImageButtons for the main functionalities and the sub tasks. For every row I added one LinearLayout which spreads over the complete width of the screen and then I inserted two to four LinearLayouts which contain the ImageButtons. In order to get the design flexible I did work with the settings layout_sum and layout_weight. The layout_sum is set in the outer LinearLayout. The layout_weight is defined in the inner LinearLayouts. The sum of the layout_weights is defined in the layout_sum. Again I had to center every view element. The orientation of the outer LinearLayout is defined horizontal whereas the orientation of the inner LinearLayout is set to vertical.

    ImageButton embedded in LinearLayouts

    ImageButton embedded in LinearLayouts

    I want to point out the meaning of the LinearLayout orientation here because in the beginning my design looked like displayed below also I had centered every single element. The failure was the orientation of the inner LinearLayouts which was defined horizontal. Maybe this implementation issue is obvious for many many other Android developers but I’m a blonde developer and so I write this for all the blond programmers out there. It almost drove me nuts and I couldn’t find a hint in the internet why my design looked so shitty until I had a close look to the orientation of the LinearLayouts.

    Shitty start screen of Fitness Mangager App displayed in Android Studio Tablet emulator

    Shitty start screen of Fitness Mangager App displayed in Android Studio Tablet emulator

  1. At least I had to adapt the layout progammatically in the corresponding Java File because in the designer of the Android Studio the view was displayed like shown below and moreover the sizes of the ImageButtons needed to be fitted to the different screen sizes of available Android devices:

    Fitness Manager start screen displayed in Android Studio Designer

    Fitness Manager start screen displayed in Android Studio Designer

    If you want to change the sizes of different view elements dependent on the size of other view elements, you cannot implement the changes in the onCreate or onResume funtions of an activity. The drawing phase of the view, which provides the measurements of the single view elements is only finished at the end of onResume function. Therefore I added runnables to the layout queue which will be invoked after the call of setContentView when all view measurements are finished. In these runnables I could request the width and height of single view elements, the DisplayMetrics of the Android device and set the LayoutParams of the ImageButtons.

    ImageButton Runnable

    ImageButton Runnable

If you have any questions concerning my layout design and implementation, any improvement suggestions for the implementation (I mentioned that this is my first Android App) or any improvement suggestions for my English, I really would appreciate if you can leave me a comment.

And I would even more appreciate if you like to check out the ‘Fitness Manager’ App in the Google Play Store or the ‘Fitness Manager’ App in the iTunes Store. See you.

Follow us on
Facebook
Twitter
Google Plus