TabLayout update tab content with a custom view
Solution 1
Ok I think it's bug on android design support library v22.
Because You are talking about the changes in content but I can't change the color of Text. Once the tab are created and if you change the layout it will not reflecting.
And As i have seen your code you are giving the custom layout using setCustomView. and for changing a text you are calling again the method setTabView(). Instead of that there should be method getCustomView() so that you can change the layout. There is a method in a TabLayout.Tab.getCustomView but it doesn't have identifier and I have report this bug.
https://code.google.com/p/android/issues/detail?id=177492
[Update 08-07-2015]
Finally bug is accepted by android bug source traking and marked as Future Release . So we can say that bug will no more exist on future library.
and we can have method getCustomView()
so that we can easily get our custom view.
[Update 18-08-2015]
Finally the bug is resolved Released in the v23 support libs . Just update support library using SDK manager and you have getCustomView() as a public.
just change this line in gradle
compile 'com.android.support:design:23.0.0'
and make sure compile and target sdk set to 23.
please check my code working fine for me
TabLayout.Tab tab=tabLayout.getTabAt(position);
View view=tab.getCustomView();
TextView txtCount= (TextView)
view.findViewById(R.id.txtCount);
txtCount.setText(count+"");
Solution 2
Well ok, I might have found a very tricky solution just because I didn't have any time to wait for next support-library version. Here's what I did:
- Set pager adapter to your TabLayout
tabLayout.setTabsFromPagerAdapter(pagerAdapter);
-
Add listener to your ViewPager
customViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { tabLayout.getTabAt(position).select(); } @Override public void onPageScrollStateChanged(int state) { } });
-
Add listener to your TabLayout
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { @Override public void onTabSelected(TabLayout.Tab tab) { if (!isTabUpdating) { isTabUpdating = true; final int pos = tab.getPosition(); customViewPager.setCurrentItem(pos); // Clears and populates all tabs tabLayout.setTabsFromPagerAdapter(pagerAdapter); invalidateTabs(pos); } } @Override public void onTabUnselected(TabLayout.Tab tab) { } @Override public void onTabReselected(TabLayout.Tab tab) { if (!isTabUpdating) { isTabUpdating = true; final int pos = tab.getPosition(); customViewPager.setCurrentItem(pos); // Clears and populates all tabs tabLayout.setTabsFromPagerAdapter(pagerAdapter); invalidateTabs(pos); } } });
-
Add method for re-drawing all tabs
private void invalidateTabs(int selected) { for (int i = 0; i < tabLayout.getTabCount(); i++) { tabLayout.getTabAt(i).setCustomView(pagerAdapter.getTabView(i, i == selected)); } isTabUpdating = false; }
Ok, so let me explain know a little bit. First of all, you might wonder why did I used setTabsFromPagerAdapter()
instead of setupWithViewPager
. In the beginning I used setupWithViewPager
but somehow my it didn't work correctly with my pager and the 1st item wasn't been able to be selected.
The second thing you might admit - every time I'm selecting a tab I'm deleting all of them. Well, that was kind of easy problem, you see I android sources when you call Tab.setCustomView(View)
it checks the parent of the view and if it's not null - it removes all childviews. However if you pass newly-instantiated item you'll ADD another view instead of replacing the old one:
View custom = tab.getCustomView();
if(custom != null) {
ViewParent icon = custom.getParent();
if(icon != this) {
if(icon != null) {
// You wont get here
((ViewGroup)icon).removeView(custom);
}
this.addView(custom);
}
...
So, I ended up with setting all listeners by myself and re-creating all tabs every time on page/tab changes. That's NOT good solution, but as far as can't wait for Google to update their lib - this's probably the only solution to achieve such effect. (Just in case you're wondering why is this so complicated - I needed to have Tabs with custom views (text + image) which could change their view-properties (font color, image) when they're selected/unselected)
BTW - Here's the getTabView(...)
method from 4th step:
public View getTabView(int pos, boolean isSeleted) {
View tabview = ((LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout
.tab_sessioninfo,
null, false);
final ImageView ivTabIcon = (ImageView) tabview.findViewById(R.id.iv_tab_icon);
final TextView tvTabTittle = (TextView) tabview.findViewById(R.id.tv_tab_title);
if (isSeleted) {
tvTabTittle.setTextColor(context.getResources().getColor(R.color.tab_indicator));
}
switch (pos) {
case 0:
tvTabTittle.setText("1st Tab");
ivTabIcon.setImageResource(isSeleted ? R.drawable.ic_icon1_selected : R.drawable.ic_icon1);
break;
case 1:
tvTabTittle.setText("2nd Tab");
ivTabIcon.setImageResource(isSeleted ? R.drawable.ic_icon2_selected : R.drawable.ic_icon2);
break;
case 2:
tvTabTittle.setText("3rd Tab");
ivTabIcon.setImageResource(isSeleted ? R.drawable.ic_icon3_selected : R.drawable.ic_icon3);
break;
}
return tabview;
}
P.S. If you know better solution for all this stuff let me know!
UPDATE
Better solution could be approached by using Reflection:
-
Easy setup
tabLayout.setupWithViewPager(customViewPager); customViewPager.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++){ updateTab(tabLayout.getTabAt(i), position == i); } } @Override public void onPageScrollStateChanged(int state) { } });
-
Update Tab
private void updateTab(TabLayout.Tab tab, boolean isSelected){ Method method = null; try { method = TabLayout.Tab.class.getDeclaredMethod("getCustomView", null); method.setAccessible(true); View tabview = (View) method.invoke(tab, null); final ImageView ivTabIcon = (ImageView) tabview.findViewById(R.id.iv_tab_icon); final TextView tvTabTittle = (TextView) tabview.findViewById(R.id.tv_tab_title); if (isSeleted) { tvTabTittle.setTextColor(context.getResources().getColor(R.color.tab_indicator)); } switch (pos) { case 0: tvTabTittle.setText("1st Tab"); ivTabIcon.setImageResource(isSeleted ? R.drawable.ic_icon1_selected : R.drawable.ic_icon1); break; case 1: tvTabTittle.setText("2nd Tab"); ivTabIcon.setImageResource(isSeleted ? R.drawable.ic_icon2_selected : R.drawable.ic_icon2); break; case 2: tvTabTittle.setText("3rd Tab"); ivTabIcon.setImageResource(isSeleted ? R.drawable.ic_icon3_selected : R.drawable.ic_icon3); break; } tab.setCustomView(tabview); } catch (Exception e) { e.printStackTrace(); } }
UPDATE
New support library has public method for getCustomView()
, so you don't need reflection no more!
Giorgio Antonioli
My open source projects: KPermissions for Android: https://github.com/fondesa/kpermissions RecyclerViewDivider for Android: https://github.com/fondesa/recycler-view-divider Lyra for Android: https://github.com/fondesa/lyra
Updated on May 31, 2021Comments
-
Giorgio Antonioli almost 3 years
I'm using
TabLayout
of the new material design and i have a problem, i can't update tab content of a custom view once the tab is created:I can simplify my method inside my PagerAdapter with
public View setTabView(int position, boolean selected) { View v = LayoutInflater.from(context).inflate(R.layout.default_tab_view, null); tv = (TextView) v.findViewById(R.id.tabTextView); if(selected) tv.setText("SELECTED"); else tv.setText("UNSELECTED"); return v; }
And in activity i can simplify my code with:
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs); ViewPager pager = (ViewPager) findViewById(R.id.viewpager); PagerAdapter adapter = new PagerAdapter(getSupportFragmentManager()); pager.setAdapter(adapter); tabLayout.setupWithViewPager(pager); for (int i = 0; i < tabLayout.getTabCount(); i++) { boolean isFirstTab = i == 0; TabLayout.Tab tab = tabLayout.getTabAt(i); View v; v = adapter.setTabView(i, isFirstTab); v.setSelected(isFirstTab); tab.setCustomView(v); } tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { @Override public void onTabSelected(TabLayout.Tab tab) { adapter.setTabView(tab.getPosition(), true); } @Override public void onTabUnselected(TabLayout.Tab tab) { adapter.setTabView(tab.getPosition(), false); } @Override public void onTabReselected(TabLayout.Tab tab) { } });
The tabs' titles are set right when the app starts but when i change tab, the content still remains the same.