Changing the background color of a Tab in TabLayout (Android design support library) doesn't occupy the entire tab space
Asked Answered
M

4

33

I have a TabLayout (design support library) which is tied up to a ViewPager containing three tabs. I have designed a custom layout and set that to each tab in the TabLayout. I have been trying to change the background color of the currently selected tab. The color only wraps up around the text in the tab but doesn't occupy the entire tab space.

Below are the code snippets of my activity and the custom layout file.

Activity code

public class CustomTabLayoutActivity extends AppCompatActivity {

private TabLayout tabLayout;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_custom_tab_layout);
    tabLayout = (TabLayout) findViewById(R.id.tabLayout);
    ViewPager viewPager = (ViewPager) findViewById(R.id.viewPager);
    setupViewPager(viewPager);
    tabLayout.setupWithViewPager(viewPager);
    tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
    setupTabLayout();
    viewPager.setCurrentItem(0);
    viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

        }

        @Override
        public void onPageSelected(int position) {
            for (int i = 0; i < tabLayout.getTabCount(); i++) {
                if (i == position) {
                    tabLayout.getTabAt(i).getCustomView().setBackgroundColor(Color.parseColor("#198C19"));
                } else {
                    tabLayout.getTabAt(i).getCustomView().setBackgroundColor(Color.parseColor("#f4f4f4"));
                }
            }
        }

        @Override
        public void onPageScrollStateChanged(int state) {
        }
    });
}


private void setupViewPager(ViewPager viewPager) {
    CustomViewPagerAdapter pagerAdapter = new CustomViewPagerAdapter(getSupportFragmentManager());
    pagerAdapter.addFragments(new OneFragment(), "ONE");
    pagerAdapter.addFragments(new OneFragment(), "TWO");
    pagerAdapter.addFragments(new OneFragment(), "THREE");
    viewPager.setAdapter(pagerAdapter);
}

private void setupTabLayout() {

    TextView customTab1 = (TextView) LayoutInflater.from(CustomTabLayoutActivity.this)
            .inflate(R.layout.custom_tab_layout, null);
    TextView customTab2 = (TextView) LayoutInflater.from(CustomTabLayoutActivity.this)
            .inflate(R.layout.custom_tab_layout, null);
    TextView customTab3 = (TextView) LayoutInflater.from(CustomTabLayoutActivity.this)
            .inflate(R.layout.custom_tab_layout, null);
    customTab1.setText("ONE");
    tabLayout.getTabAt(0).setCustomView(customTab1);
    customTab2.setText("TWO");
    tabLayout.getTabAt(1).setCustomView(customTab2);
    customTab3.setText("THREE");
    tabLayout.getTabAt(2).setCustomView(customTab3);
}
}

Custom Layout file for each tab

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
   android:id="@+id/tab"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:layout_gravity="center"
   android:background="#ffffff"
   android:text="Test"
   android:textColor="@android:color/black"
   android:textSize="20sp" />

Here is the screenshot of the tabs after running the above code.

enter image description here

As you guys can see, the color only occupies the text in the tab but not the entire tab space. How to achieve this? Any ideas/suggestions would help me a lot. Thanks in advance.

Mammalogy answered 16/9, 2015 at 14:45 Comment(0)
T
87

Define a selector as a drawable, and also have a drawable for the selected/unselected states.

For this solution, I started with the code from this answer, and then added the functionality that changes the background color for the current Tab.

First, the selector, tab_background.xml in the drawable folder:

<?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>

Then, tab_background_selected.xml in the drawable folder:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
    <solid android:color="#d13fdd1a" />
</shape>

Then, tab_background_unselected.xml in the drawable folder:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
    <solid android:color="#3F51B5" />
</shape>

Finally, in your styles.xml, specify the selector to use, and also specify the tab indicator style, since the app:tabIndicatorColor property in the TabLayout will now be ignored:

<style name="Base.Widget.Design.TabLayout" parent="android:Widget">
    <item name="tabBackground">@drawable/tab_background</item>
    <item name="tabIndicatorColor">#ff00ff</item>
    <item name="tabIndicatorHeight">2dp</item>
</style>

Result with the example colors above:

enter image description here

enter image description here

Additional Note:

Tested with the 23.3.0 versions of the support library components:

dependencies {
    compile 'com.android.support:appcompat-v7:23.3.0'
    compile 'com.android.support:cardview-v7:23.3.0'
    compile 'com.android.support:recyclerview-v7:23.3.0'
    compile 'com.android.support:design:23.3.0'
    compile 'com.android.support:support-v4:23.3.0'
}
Tillford answered 16/9, 2015 at 15:53 Comment(20)
WOW man !!! I have been trying to achieve this for the past 5 hours. You saved my day. That worked like a charm.Mammalogy
Can you please explain why we need to add few lines of code to styles.xml?Mammalogy
Glad it worked for you! The addition to styles.xml is just to link up the selector and drawables that set the background color.Tillford
It works fine when the tab mode is set to fixed, but when set to scrollable, the spacing between the tabs is lost. I have used "tab:padding" to add spacing between the tabs. Is that the right approach to do that?Mammalogy
Is there anyway to do this so that the selected tab is a different color depending tab position? For example, having first tab green when selected and having second tab red when selected? Edit: I think it can be done with OnTabSelectedListener() and using TabLayout.setBackgroundResource() for each tab in onTabSelected().Unlive
you are god, you save me :DCogitate
Why do we have state_focused and state_pressed set to false when not selected, but only set state_selected to true when selected?Daybreak
this overwrites the indicator of the selected tab (that small line under the tab with accentColor).. is there a way to get it back?Flor
if someone is interested in having an indicator: #38203085Flor
@zoup sorry, been meaning to update this answer forever. Thanks for the link.Tillford
maybe old but anyways to stop flickering when using this with viewPager?Margretmargreta
@DanielNugent during a swipe for me, it flickers between tabs for a split second since, my guess is it does not know which tab it is going to until it finishesMargretmargreta
@tanner yep, I was swiping when I recorded thatTillford
What if i have multiple tabLayout throughout my app , and i want to give this effect to particular tablayout ?Chronister
perfect answer. but I really like that ripple effect which is disappeared right now :(Heat
Similar workaround can be done with Navigation Drawer item? i tried many failed attempts to have a background color Selected drawer item.Ainu
How do I do this programaticallyMarchpast
Correct me if im wrong. We have to add the following line to the TabLayout in the xml: style="@style/Base.Widget.Design.TabLayout" This may be what @Zulqurnain needs to do as wellFaction
this code is ok for default tab layout but if u are using custom View for tablayout then the above code is not fruitfulAuthority
@Authority It works for me with a custom layout for each Tab. In fact, the screenshots in the answer are from using a custom layout. Take a look here for the implementation I used: https://mcmap.net/q/452411/-how-to-implement-recyclerview-with-cardview-rows-in-a-fragment-with-tablayoutTillford
H
5

you should use:

app:tabBackground="@drawable/tab_selector"
android:background="@color/colorNormal"

tab_selector.xml (in Drawable Folder):

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_selected="true" android:drawable="@color/colorSelected"/>
    <item android:state_selected="false" android:drawable="@color/colorNormal"/>
</selector>
Heins answered 5/8, 2018 at 8:52 Comment(0)
H
2

Tabs with Ripple effect: In addition to Daniel Nugent's answer It would be beautiful to add a ripple effect to tabs. In order to achieve this, you must add these two drawables to drawable-v21 folder:

tab_background_selected.xml :

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="#63D25B"> <!-- ripple color -->
    <item android:drawable="#d13fdd1a" /> <!-- normal color -->
</ripple>

tab_background_unselected.xml :

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="#606FC7"> <!-- ripple color -->
    <item android:drawable="#3F51B5" /> <!-- normal color -->
</ripple>
Heat answered 16/1, 2017 at 7:33 Comment(2)
Thanks for this, but I am already getting the ripple effect with Daniel Nugent's answer. I am using version 28.0.0-alpha3 of the support libraries - maybe that's why?Dicarlo
@Dicarlo Thanks for your comment. I haven't seen ripple effect with Daniel's answer at the time I was writing this answer.Heat
I
1

I know that its quite late to answer this question, but have a different & simple answer without creating any new background or selector. Tab-Layout have default padding of 12dp at its start & end. Just set

app:tabPaddingStart="0dp"
app:tabPaddingEnd="0dp"

to fill color in your tab.

Inheritance answered 4/1, 2018 at 10:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.