android:orientation="vertical" does not work for TabWidget
Asked Answered
L

4

12

My app has a tabhost with four tabs, and now I'm trying to make nice layouts for landscape mode. In order to make use of additional horizontal space I want to put TabWidget at the right side of the screen, and of cource all tabs must be one under another (like in a column). But when switching to landscape mode all tabs get aligned in a row, it looks quite ugly. How to fix that?

Screenshot

<?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/tabhost"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >
    <LinearLayout

        android:layout_width="fill_parent"
        android:layout_height="fill_parent" 
        >

        <FrameLayout
            android:id="@android:id/tabcontent"
            android:layout_width="wrap_content"
            android:layout_height="fill_parent"
            android:layout_weight="1">

            <include layout="@layout/filter_wizard"/>
            <include layout="@layout/filter_wizard"/>
            <include layout="@layout/filter_wizard"/>
            <include layout="@layout/filter_wizard"/>

            </FrameLayout>

             <TabWidget
            android:background="#75ffffff"
            android:id="@android:id/tabs"
            android:layout_width="wrap_content" android:orientation="vertical" 
            android:layout_height="fill_parent" android:layout_weight="0" />



    </LinearLayout>
</TabHost>
Liddle answered 10/11, 2010 at 23:0 Comment(5)
I've actually tried getting vertical tabs to work using the tabhost/tabwidget. I never got it to work. you'll probably have to roll your own tab view to do it.Balcke
I agree with Falmarri. This needs to be done in your own custom layout. TabHost isn't very nice when trying to customize it to look good for both portrait and landscape.Engineering
Falmarri, Austyn Mahoney, thanks for the explanation. Is there a feasible way to implement own tabwidget?Liddle
Do you have a way to publish your project ?Progressist
Can you post your solution ?The megaupload link is expired nowAmber
A
21

This is how I set up the TabHost to display the tabs on the left of the screen, with tabs vertically stacked.

One needs to set up 2 different layouts for the activity, one in portrait ("normal") mode, one in landscape mode. This implies to not use TabActivity.

I copied the layout used by TabActivity into my own project and called it main_view.xml (stored in res/layout). Here it is:

<TabHost xmlns:android="http://schemas.android.com/apk/res/android" 
         android:id="@+id/tabHost"
         android:layout_width="match_parent" 
         android:layout_height="match_parent">
    <LinearLayout android:orientation="vertical"
                  android:layout_width="match_parent" 
                  android:layout_height="match_parent">
        <TabWidget android:id="@android:id/tabs"
                   android:layout_height="wrap_content" 
                   android:layout_width="match_parent"
                   android:layout_weight="0" />
        <FrameLayout android:id="@android:id/tabcontent"
                     android:layout_width="match_parent" 
                     android:layout_height="0dip"
                     android:layout_weight="1"/>
    </LinearLayout>
</TabHost>

One must reuse the Android ids tabs and tabcontent.

In landscape, I changed this by inverting the layout height/width attributes for all controls and setting the orientation of LinearLayout to horizontal (the TabWidget and FrameLayout must be next to each other, horizontally). Here is the result, in res/layout-land, also called main_view.xml:

<TabHost   xmlns:android="http://schemas.android.com/apk/res/android" 
           android:id="@+id/tabHost"
           android:layout_width="match_parent" 
           android:layout_height="match_parent">
    <LinearLayout android:orientation="horizontal"
                  android:layout_width="match_parent" 
                  android:layout_height="match_parent">
        <TabWidget android:id="@android:id/tabs" 
                   android:layout_height="match_parent" 
                   android:layout_width="wrap_content"
                   android:layout_weight="0" />
        <FrameLayout android:id="@android:id/tabcontent"
                     android:layout_height="match_parent" 
                     android:layout_width="0dip"
                     android:layout_weight="1"/>
    </LinearLayout>
</TabHost>

Note that if you want the tabs on the right, you put the TabWidget after the FrameLayout in the XML above.

TabWidget is itself a LinearLayout. Notice that I did not set the orientation in XML. This because TabWidget does it in its own code (yes, it is hard-coded). To counter this, one has to re-set the orientation in code. Here is how I did it in my activity's oncreate

setContentView(R.layout.main_view);

final TabHost tabHost = (TabHost) findViewById(R.id.tabHost);
tabHost.setup();

Resources res = getResources();
Configuration cfg = res.getConfiguration();
boolean hor = cfg.orientation == Configuration.ORIENTATION_LANDSCAPE;

if (hor) {
    TabWidget tw = tabHost.getTabWidget();
    tw.setOrientation(LinearLayout.VERTICAL);
}

As TabHost is created through setContentView, one must call its setup method explicitly.

The usual way to create a tab is to call:

tabHost.addTab(tabHost.newTabSpec("tab name").setIndicator("title", icon).setContent(...));

The setIndicator method, taking a title string and a drawable as parameters, creates a layout that is valid only in portrait mode. One has to create one's own view and give it to setIndicator. It is enough to copy the TabSpec.LabelAndIconIndicatorStrategy.createIndicatorView code:

   private View createIndicatorView(TabHost tabHost, CharSequence label, Drawable icon) {

       LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);

       View tabIndicator = inflater.inflate(R.layout.tab_indicator,
               tabHost.getTabWidget(), // tab widget is the parent
               false); // no inflate params

       final TextView tv = (TextView) tabIndicator.findViewById(R.id.title);
       tv.setText(label);

       final ImageView iconView = (ImageView) tabIndicator.findViewById(R.id.icon);
       iconView.setImageDrawable(icon);

       return tabIndicator;
   }

The difference with the original Google code is that the view layout itself, the TextView and ImageView ids are from our own application, not Android internal ids.

For portrait mode, we can reuse the tab_indicator.xml from Android, that we store in res/layout:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="0dip"
    android:layout_height="64dip"
    android:layout_weight="1"
    android:layout_marginLeft="-3dip"
    android:layout_marginRight="-3dip"
    android:orientation="vertical"
    android:background="@drawable/tab_indicator">

    <ImageView android:id="@+id/icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
    />

    <TextView android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        style="?android:attr/tabWidgetStyle"
    />

</RelativeLayout>

Again, this is identical to the original Android XML, except for the ids. For a landscape-friendly version, we need to invert again the layout width and height attributes. Which gives us in res/layout-land:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="64dip"
    android:layout_height="0dip"
    android:layout_weight="1"
    android:layout_marginTop="-3dip"
    android:layout_marginBottom="-3dip"
    android:orientation="vertical"
    android:background="@drawable/tab_indicator">

    <ImageView android:id="@+id/icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
    />

    <TextView android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        style="?android:attr/tabWidgetStyle"
    />
</RelativeLayout>

(I changed marginLeft and marginRight to marginTop and marginBottom but am not that sure that it is helpful)

These last XML files reference @drawable/tab_indicator, so we need to copy it from Android source code, as well as drawable/tab_selected.9.png, drawable/tab_unselected.9.png, drawable/tab_focus.9.png.

Now creating a tab becomes:

tabHost.addTab(tabHost.newTabSpec(AllTabName)
                .setIndicator(createIndicatorView(tabHost, "tab title", icon)))
                .setContent(this));

EDIT: a demo project is available at: VerticalTabHost on SkyDrive

Antidisestablishmentarianism answered 22/3, 2011 at 23:48 Comment(8)
i do as your say,but when the screen is horizontal,my get the result is that the screen cannot show tabWidget,only show tabContentDysgenic
Do you have a way to publish your project ? I can have a look and compare with mine.Antidisestablishmentarianism
Thanks for the upload. It looks like my sample of tab_indicator.xml was not displaying correctly. I re-applied the formatting and it looks now complete (sorry about this). The <RelativeLayout> tag was not shown. This part was wrong in your sample in res/layout-land/tab_indicator.xml. I exchanged the layout_width and layout_height attributes (in your project) and the TabWidget is now showing correctly on my emulator.Antidisestablishmentarianism
On my emulator, the tabs were showing "reversed", i.e. in landscape view when in portrait and vice-versa. Maybe this is what you wanted. If I remove the android:screenOrientation="landscape" attribute in the manifest, it is displayed "normally".Antidisestablishmentarianism
Your link in megauploads is broken can you please Edit your answer and put a source code so that all users can see your post ? I am not able to display tabs vertically it displays only content SO please help me.Amber
I've updated the answer to include a link to the sources. Here's also the link: skydrive.live.com/…Antidisestablishmentarianism
@Antidisestablishmentarianism I made the xml as said and create custom views for the indicators. My activity is set to landscape only so I can just set tw.setOrientation(LinearLayout.VERTICAL); in the onCreate. But then my TabWidget disappears. on LinearLayout.HORIZONTAL it displays my TabWidget.Janycejanyte
@Janycejanyte the comment from Davor in the answer by ATom says the same thing. If you post your code somewhere, I can have a look.Antidisestablishmentarianism
G
4

TabHost does not support the orientation attribute and tabs can only be used horizontally.

Gocart answered 11/11, 2010 at 5:39 Comment(0)
N
3

So, only important think that you must do is this:

getTabWidget().setOrientation(LinearLayout.VERTICAL);

Because TabWidget has hardcoded setOrientation(LinearLayout.HORIZONTAL); in initTabWidget() method. I don't know why.

Narcisanarcissism answered 25/4, 2011 at 14:14 Comment(1)
When I do that, my TabWidget disappears.Zetes
I
0

Here i have an look alike solution for the Vertical Tab alignment view

Kindly visit this link :-how to change the layout in frame layout on the click event?

Thank You Happpieeee coding

Iluminadailwain answered 2/10, 2014 at 11:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.