7

I opend a post about this before but I feel that I can now (after reading some other posts) better explain what I want and rephrase it so it will be better understand.

I followed the tutorial about Tab Layout on the dev guide and I managed to create tabs with it, but I want to do some customization to it (and I did look on other posts, but either the code had many mistakes to it or it didn't answer what I'm looking for).

  1. The first problem I have is that the test is in most part over the icon instead of below it (I used an icon with dimensions 48x48 as recommended on the dev guide). I want the tab with to act like wrap_content does. I also want to change the text size (I think it's called the label).

  2. I want to use hex triplets to change the background color of the tabs, to change it between to situations : when this tab is the one selected and when it's not.

  3. I want to be able to change the color of the line that is below the tabs, I could not find any information on how to do this.

The code I'm currently using to create a new tab is (from the dev guide):

    intent = new Intent().setClass(this, GroupsActivity.class);
    spec = tabHost.newTabSpec("groups").setIndicator("groups",
                      res.getDrawable(R.drawable.ic_tab_groups))
                  .setContent(intent);
    tabHost.addTab(spec);

(groups is the tab name).

Help is very much appreciated!

SBerg413
  • 14,515
  • 6
  • 62
  • 88
Belgi
  • 14,542
  • 22
  • 58
  • 68
  • Belgi: the title is one of the most important parts of your question. Please at least quickly check it before submitting. – Mat Oct 16 '11 at 13:23
  • @Mat what was wrong with it ? (I'm asking to know better for the future). thanks for editing it and helping out – Belgi Oct 16 '11 at 13:24
  • Click on the link with time information just to the right of "edited" above my "signature", it will show the edit history. – Mat Oct 16 '11 at 13:26

3 Answers3

17

Rather than trying to customize the widget tabs themselves, here is an alternate approach that I've used successfully on a project that may save you some headaches:

The idea is to use a hidden TabWidget in your layout and control it with a customized LinearLayout containing Buttons. This way, you can more easily customize the buttons to look however you'd like. You'll control the actual TabWidget in your Activity within each button's OnClick.

  1. Create your layout with both the TabWidget and the Buttons:

        <?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">
    
        <RelativeLayout android:orientation="vertical"
            android:layout_width="fill_parent" android:layout_height="fill_parent"
            android:gravity="bottom">
            <TabWidget android:id="@android:id/tabs"
                android:layout_width="fill_parent" android:layout_height="wrap_content"
                android:visibility="gone" />
    
            <LinearLayout android:id="@+id/tabbar"
                android:orientation="horizontal" android:layout_width="fill_parent"
                android:layout_height="wrap_content">
                <Button android:id="@+id/firstButton"
                    android:layout_alignParentTop="true" android:background="@drawable/btn_first_on"
                    android:layout_width="100dp" android:layout_height="43dp"
                    android:clickable="true"></Button>
                <Button android:id="@+id/secondButton"
                    android:layout_alignParentTop="true" android:background="@drawable/btn_second_off"
                    android:layout_height="43dp" android:layout_width="100dp"
                    android:clickable="true"></Button>
                <Button android:id="@+id/thirdButton"
                    android:layout_alignParentTop="true" android:background="@drawable/btn_third_off"
                    android:layout_height="43dp" android:layout_width="100dp"
                    android:clickable="true"></Button>
                <Button android:id="@+id/forthButton"
                    android:layout_alignParentTop="true" android:background="@drawable/btn_forth_off"
                    android:layout_height="43dp" android:layout_width="100dp"
                    android:clickable="true"></Button>
            </LinearLayout>
    
            <FrameLayout android:id="@android:id/tabcontent"
                android:layout_width="fill_parent" android:layout_height="fill_parent"
                android:layout_below="@+id/tabbar" />
    
        </RelativeLayout>
    </TabHost>
    
  2. Set up the onCreate of your activity to handle using the buttons for adjusting the tab views:

        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            // tabs        
            firstButton = (Button) findViewById(R.id.firstButton);
            secondButton = (Button) findViewById(R.id.secondButton);        
            thirdButton = (Button) findViewById(R.id.thirdButton);
            forthButton = (Button) findViewById(R.id.forthButton);
    
            Resources res = getResources(); // Resource object to get Drawables
            final TabHost tabHost = getTabHost();  // The activity TabHost
            TabHost.TabSpec spec;  // Resusable TabSpec for each tab
            Intent intent;  // Reusable Intent for each tab
    
            intent = new Intent().setClass(this, FirstGroupActivity.class);
            spec = tabHost.newTabSpec("first").setIndicator("First").setContent(intent);
            tabHost.addTab(spec);
            intent = new Intent().setClass(this, SecondGroupActivity.class);
            spec = tabHost.newTabSpec("second").setIndicator("Second").setContent(intent);
            tabHost.addTab(spec);   
    
            intent = new Intent().setClass(this, ThirdGroupActivity.class);
            spec = tabHost.newTabSpec("third").setIndicator("Third").setContent(intent);
            tabHost.addTab(spec);
    
    
            intent = new Intent().setClass(this, ForthActivity.class);
            spec = tabHost.newTabSpec("forth").setIndicator("Forth").setContent(intent);
            tabHost.addTab(spec);
    
    
            tabHost.setCurrentTab(0);
    
            firstButton.setOnClickListener(new OnClickListener() {
    
                public void onClick(View v)
                {
                    tabHost.setCurrentTab(0);
                    firstButton.setBackgroundResource(R.drawable.btn_first_on);
                    secondButton.setBackgroundResource(R.drawable.btn_second_off);              
                    thirdButton.setBackgroundResource(R.drawable.btn_third_off);
                    forthButton.setBackgroundResource(R.drawable.btn_forth_off);            
                }
    
            });
    
    
            secondButton.setOnClickListener(new OnClickListener() {
    
                public void onClick(View v)
                {
                    tabHost.setCurrentTab(1);
                    firstButton.setBackgroundResource(R.drawable.btn_first_off);
                    secondButton.setBackgroundResource(R.drawable.btn_second_on);                       
                    thirdButton.setBackgroundResource(R.drawable.btn_third_off);                        
                    forthButton.setBackgroundResource(R.drawable.btn_forth_off);
    
                }
    
            });
    
    
            thirdButton.setOnClickListener(new OnClickListener() {
    
                public void onClick(View v)
                {
                    tabHost.setCurrentTab(3);
                    firstButton.setBackgroundResource(R.drawable.btn_first_off);
                    secondButton.setBackgroundResource(R.drawable.btn_second_off);              
                    thirdButton.setBackgroundResource(R.drawable.btn_third_on);
                    forthButton.setBackgroundResource(R.drawable.btn_forth_off);
    
                }
    
            });
    
    
            forthButton.setOnClickListener(new OnClickListener() {
    
                public void onClick(View v)
                {
                    tabHost.setCurrentTab(4);
                    firstButton.setBackgroundResource(R.drawable.btn_first_off);
                    secondButton.setBackgroundResource(R.drawable.btn_second_off);              
                    thirdButton.setBackgroundResource(R.drawable.btn_third_off);
                    forthButton.setBackgroundResource(R.drawable.btn_forth_on);
    
                }
    
            });
        }
    

As you can see, I'm using drawables for the images of the buttons on and off. Using this technique, you're not limited to the options available when simply just trying to customize the look of the TabWidget's tabs and you can create a completely custom look to your tabs.

SBerg413
  • 14,515
  • 6
  • 62
  • 88
  • looks very interesting, but the layout code gives me errors: " – Belgi Oct 16 '11 at 13:59
  • Sorry - had some typos in there from while i was trying to take out the non-relevant parts. Should be good now. Keep in mind that i'm making references to specific drawables. You'll need to create your own and adjust the names accordingly. – SBerg413 Oct 16 '11 at 14:17
  • I'm still getting "The markup in the document following the root element must be well-formed." but this time it's on " " – Belgi Oct 16 '11 at 14:24
  • Really sorry about that. This compiled for me. – SBerg413 Oct 16 '11 at 14:41
  • Also, keep in mind that you're going to have to create your drawable images or you'll get a resource not found error. But, that's the whole point of this approach - to create custom drawables to replace the original tabs. – SBerg413 Oct 16 '11 at 14:48
  • @drawable/btn_first_on is a pic (png etc') ? – Belgi Oct 16 '11 at 14:50
  • yes ... those will be your tab buttons.. make 2 for each tab.. on and off ... btn_first_on.png & btn_first_off.png – SBerg413 Oct 16 '11 at 14:55
  • ok, I used the code and it works, but I have two things I want to do and don't know how: A. I want to have some space between the icons, I tried adding padding but it didn't work. B.add text below the icons that is still a part of the button – Belgi Oct 17 '11 at 06:05
  • A) it's not padding but margins that you should be trying to set. B) Make the text part of the image. You could also try adding the text to the button and positioning it, but that's not how I do it. – SBerg413 Oct 17 '11 at 10:43
  • Best answer.... my question : Why only 2 upvotes... deserves at least 100 upvotes.... :) – Aamir Shah Dec 29 '12 at 10:44
  • @SBerg413 I used this method also added `HorizontalScrollView` for `LinearLayout` and now I can't make that the selected button was in the middle, have you any suggestions? thanks – pepela Jun 25 '13 at 08:53
11

1- Use a custom view:

    spec = tabHost.newTabSpec("groups");
    View view = LayoutInflater.from(this).inflate(R.layout.tabwidget_tabs, tabHost.getTabWidget(), false);
    spec.setIndicator(view);
    spec.setContent(intent);

instead of:

    spec = tabHost.newTabSpec("groups").setIndicator("groups", res.getDrawable(R.drawable.ic_tab_groups)).setContent(intent);
    tabHost.addTab(spec);

And then define the view for the tabs in the file tabwidget_tabs.xml (you can define an ImageView before the textView and the textsize):

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/tabsLayout" 
        android:layout_width="wrap_content"
        android:layout_height="34dp"
        android:background="@drawable/tabs_bkgrd"
        android:padding="5dp" 
        android:orientation="vertical">

        <TextView android:id="@+id/tabsText" 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" 
            android:singleLine="true"
            android:textStyle="bold" 
            android:gravity="center_horizontal"
            android:textSize="14dp" />
    </LinearLayout>

2- It's not possible to use hex triplets to change the background color of the tabs because are drawables not colors. However you can use a selector that changes the drawables. and you can combine this solution with setColorFilter() and android:tint and then you can select the background using hex triplets: How to tint a bitmap

tabs_bkgrd.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Non focused states -->
    <item android:state_focused="false" android:state_selected="false" 
        android:state_pressed="false" android:drawable="@drawable/tab_unselected_shape" />
    <item android:state_focused="false" android:state_selected="true" 
        android:state_pressed="false" android:drawable="@drawable/tab_selected_shape" /> 

    <!-- Focused states -->
    <item android:state_focused="true" android:state_selected="false" 
        android:state_pressed="false" android:drawable="@drawable/tab_focused_shape" />
    <item android:state_focused="true" android:state_selected="true" 
        android:state_pressed="false" android:drawable="@drawable/tab_focused_shape" /> 

    <!-- Pressed -->
    <item android:state_pressed="true" android:drawable="@drawable/tab_pressed_shape" /> 

    </selector>

You can define a color or a shape, tab_selected_shape.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
                android:shape="rectangle">
            <gradient android:startColor="@color/gold1"
                android:centerColor="@color/gold2" 
                android:endColor="@color/gold2"
                android:angle="@integer/vertical_shape" />
    </shape>

3- The line is a drawable too. you can find the files in the sdk and copy them into your project after modify them to change the color using gimp. You can combine this solution with setColorFilter() and android:tint and then you can select the background using hex triplets too. Read: further explanation

android-sdk-linux_x86/platforms/android-7/data/res/drawable

tab_bottom_left.xml,  
tab_bottom_right.xml,  
tab_indicator.xml  (define state changes)

android-sdk-linux_x86/platforms/android-7/data/res/drawable-mdpi

tab_focus.9.png (change color)
tab_focus_bar_left.9.png
tab_focus_bar_right.9.png
tab_press.9.png (change color)
tab_press_bar_left.9.png
tab_press_bar_right.9.png
tab_selected.9.png (change color)
tab_selected_bar_left.9.png tab_selected_bar_right.9.png
tab_unselected.9.png

Community
  • 1
  • 1
albodelu
  • 7,931
  • 7
  • 41
  • 84
1

What about the solution I proposed on this question?

You can customize the drawable of each button using the same used by native Android Tab bar(looking for resources in Android.jar to find the right drawables), plus you can customize additional behavious as you desire.

At the end, you will obtain something that is graphically similar to a tabbar, from an user perspective, but acts differently from a developer perspective.

Community
  • 1
  • 1
Rainbowbreeze
  • 1,503
  • 1
  • 9
  • 14