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.
-
1margin means what.. gaps between the tabs? – Connecting life with Android Apr 11 '16 at 12:39
-
Seems adding margins is not really possible however you can do some tricks to make it work. may b add a dummy view or tabs. – Connecting life with Android Apr 11 '16 at 12:44
7 Answers
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.
- 1,697
- 1
- 12
- 20
-
2Your solution works really well for me! If someone wants to add a margin contained in the dimens.xml file, he can use getResources().getDimensionPixelSize(R.dimen.your_dimens) instead of a fixed pixel value like "50". – Mattia Ruggiero Nov 23 '16 at 10:59
-
1This works, however the underline indicator begins to misbehave when you do this, swiping works fine, but paging to a given point on tab click breaks it. I'm looking into a fix now. – JMRboosties Dec 27 '16 at 03:13
-
-
-
@Todor Your answer is good. The code snippet you shared does not set margin for last tab. So Can you tell me how can i achieve this ? – Deepak Rathore Apr 12 '19 at 07:25
-
@DeepakRathore the above implementation sets margin to the last tab. – Todor Kostov Apr 12 '19 at 07:36
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>
- 17,070
- 21
- 157
- 242
-
-
This should be the accepted answer. No java/kotlin "hacking" needed for it to work. – Hampel Előd Mar 05 '20 at 08:06
-
That was a great answer and easily understandable. Thanks @ban-geoengineering – Sandy Nov 25 '20 at 09:30
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()
}
- 149
- 2
- 3
@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();
}
- 1,008
- 9
- 21
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);
}
- 477
- 6
- 13
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?) {}
})
}
}
- 121
- 5
None of the answers was working for me! So here is the answer that will work for you and see the below result.
- 11,648
- 2
- 65
- 69