Todor Kostov
Todor Kostov

Reputation: 1829

How to add margin between tabs in TabLayout?

Is there a way to add margin between the tabs in a TabLayout? I've tried with using a custom style for Widget.Design.TabLayout, but there are properties only related to padding, but no margins.

Upvotes: 19

Views: 24485

Answers (7)

Edwinfad
Edwinfad

Reputation: 535

This is how set margin for four different tabs. You can change the setMargins(v1,v2,v3,v4) function values to get a suitable fitting for the number of tabs that you are working with. I hope this helps. Please note that tabHost is the object of TabHost hosting different tabs you are working with.

Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
View currentView;

for(int i=0; i<tabHost.getTabWidget().getChildCount(); i++) {
    //This code removes divider between tabs
    tabHost.getTabWidget().setDividerDrawable(null);
    tabHost.getTabWidget().getChildAt(i).setLayoutParams(new
        LinearLayout.LayoutParams((width / 8) - 2, 50));
    currentView = tabHost.getTabWidget().getChildAt(i);
    LinearLayout.LayoutParams currentLayout =
        (LinearLayout.LayoutParams) currentView.getLayoutParams();
    currentLayout.setMargins(30, 5, 80, 0);
}

Upvotes: 0

Kishan Solanki
Kishan Solanki

Reputation: 14618

None of the answers was working for me! So here is the answer that will work for you and see the below result.

enter image description here

Upvotes: 1

FJJ
FJJ

Reputation: 129

Most suggestions here seems to suggest calling requestLayout() to update the margins. This will trigger a new layout pass. I also personally saw issues when animating the layout, in which the TabLayout was defined, causing the requestLayout to be called a bunch of times, and sometimes making the tabs "jump"

I think a better way of setting the margins between the tabs, would be to extend the TabLayout, and listen to when child views are added to the SlidingTabIndicator.

private const val YOUR_CUSTOM_MARGIN = 8

class CustomTabLayout @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : TabLayout(
    context,
    attrs,
    defStyleAttr
) {

    init {
        val tabStrip = (this.getChildAt(0) as ViewGroup)
        tabStrip.setOnHierarchyChangeListener(object : OnHierarchyChangeListener {
            override fun onChildViewAdded(p0: View?, p1: View?) {
                if (p1 is TabView && p1.layoutParams is MarginLayoutParams) {
                    val params = p1.layoutParams as MarginLayoutParams
                    params.setMargins(YOUR_CUSTOM_MARGIN, 0, YOUR_CUSTOM_MARGIN, 0)
                }
            }

            override fun onChildViewRemoved(p0: View?, p1: View?) {}
        })
    }
}

Upvotes: 0

Vadims Krutovs
Vadims Krutovs

Reputation: 217

Here is Kotlin version of @Todor Kostov's answer.

 for (i in 0 until applicationList_tabLayout.tabCount) {
            val tab = (applicationList_tabLayout.getChildAt(0) as ViewGroup).getChildAt(i)
            val p = tab.layoutParams as ViewGroup.MarginLayoutParams
            p.setMargins(10, 0, 10, 0)
            tab.requestLayout()
 }

Upvotes: 9

Boycott A.I.
Boycott A.I.

Reputation: 18871

Here's how I did it in pure xml.

dimens.xml:

<!-- Set this to 50% of what you want the actual space between the tabs to be. -->
<dimen name="tab_spacing_half">5dp</dimen> <!-- i.e., 10dp spacing between tabs. -->

Layout containing your TabLayout:

<android.support.design.widget.TabLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="@dimen/tab_spacing_half"/>

Add this to your theme in styles.xml:

<item name="tabBackground">@drawable/tab_background</item>

drawable-nodpi\tab_background.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector
    xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:drawable="@drawable/tab_background_selected"
        android:state_selected="true" />

    <item
        android:drawable="@drawable/tab_background_unselected"
        android:state_selected="false"
        android:state_focused="false"
        android:state_pressed="false" />

</selector>

drawable-nodpi\tab_background_selected.xml:

<?xml version="1.0" encoding="utf-8"?>
<layer-list
    xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:left="@dimen/tab_spacing_half"
        android:right="@dimen/tab_spacing_half"
        android:top="@dimen/tab_spacing_half"
        android:bottom="@dimen/tab_spacing_half">

        <shape
            android:shape="rectangle">

            <corners
                android:radius="@dimen/border_radius_small">
            </corners>

            <stroke
                android:width="@dimen/divider_height_thick"
                android:color="@color/white">
            </stroke>

        </shape>

    </item>

</layer-list>

...That's where the trick is. Effectively, wrapping your background shape in an item with "padding" according to your @dimen/tab_spacing_half value. And finally...

drawable-nodpi\tab_background_unselected.xml:

<?xml version="1.0" encoding="utf-8"?>
<layer-list
    xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:left="@dimen/tab_spacing_half"
        android:right="@dimen/tab_spacing_half"
        android:top="@dimen/tab_spacing_half"
        android:bottom="@dimen/tab_spacing_half">

        <shape
            android:shape="rectangle">

            <corners
                android:radius="@dimen/border_radius_small">
            </corners>

            <stroke
                android:width="@dimen/divider_height_thin"
                android:color="@color/white">
            </stroke>

        </shape>

    </item>

</layer-list>

Upvotes: 16

Tura
Tura

Reputation: 1326

@Todor Kostov answered well, but the center of the tabs are slipped away because the last tab has margin too.

so use mTabLayout.getTabCount() - 1 instead of just mTabLayout.getCodeCount().

        for(int i=0; i < mTabLayout.getTabCount() - 1; i++) {
            View tab = ((ViewGroup) mTabLayout.getChildAt(0)).getChildAt(i);
            ViewGroup.MarginLayoutParams p = (ViewGroup.MarginLayoutParams) tab.getLayoutParams();
            p.setMargins(0, 0, 50, 0);
            tab.requestLayout();
        }

Upvotes: 5

Todor Kostov
Todor Kostov

Reputation: 1829

Ok mates, after spending 2-3 hours on that I finally found a solution.

If you are using TabLayout there is no way to add margins to the tabs by using styles and so on. (as @Connecting life with Android earlier)

But, you can do that by writing some Java code. All in all your code should look similar to that one:

            for(int i=0; i < mTabLayout.getTabCount(); i++) {
                View tab = ((ViewGroup) mTabLayout.getChildAt(0)).getChildAt(i);
                ViewGroup.MarginLayoutParams p = (ViewGroup.MarginLayoutParams) tab.getLayoutParams();
                p.setMargins(0, 0, 50, 0);
                tab.requestLayout();
            }

In order to get each and every tab as a View we have to first get the container which contains them. In this case the TabLayout is using a SlidingTabStrip as a container for the tabs. The SlidingTabStrip is the first child of the TabLayout:

View tab = ((ViewGroup) mTabLayout.getChildAt(0))

And after this small detail, everything is pretty straight forward.

Upvotes: 62

Related Questions