TabLayout与ViewPager配合使用踩坑总结
Posted 胖子爱你520
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TabLayout与ViewPager配合使用踩坑总结相关的知识,希望对你有一定的参考价值。
前言:TabLayout是个神器,android系统提供的一种控件,和ViewPager搭配使用,能帮助我们很快捷的实现头部Tab点击切换和ViewPager滑动关联滑动的动画效果,但是在我近期的使用过程中,还是发现了一些坑,耗费了一点时间,发现问题后简直被自己蠢哭了,特此记录一下使用中的坑,供大家参考。
先来看看我们将要实现的一个效果吧:
这是我们最终版的效果,那么其中的过程是什么样的呢?一步步往下看吧!
一、TabLayout的标签名称不显示
这个视频里会发现TabLayout的Tab名称不显示了,阿西吧!当TabLayout没有调用setupWithViewPager方法时,我们是能看到标签名称的,好吧,那么问题应该就出在了setupWithViewPager这个方法里,跟进去看看吧!
public void setupWithViewPager(@Nullable ViewPager viewPager)
setupWithViewPager(viewPager, true);
public void setupWithViewPager(@Nullable final ViewPager viewPager, boolean autoRefresh)
setupWithViewPager(viewPager, autoRefresh, false);
private void setupWithViewPager(@Nullable final ViewPager viewPager, boolean autoRefresh,
boolean implicitSetup)
if (mViewPager != null)
// If we've already been setup with a ViewPager, remove us from it
if (mPageChangeListener != null)
mViewPager.removeOnPageChangeListener(mPageChangeListener);
if (mAdapterChangeListener != null)
mViewPager.removeOnAdapterChangeListener(mAdapterChangeListener);
if (mCurrentVpSelectedListener != null)
// If we already have a tab selected listener for the ViewPager, remove it
removeOnTabSelectedListener(mCurrentVpSelectedListener);
mCurrentVpSelectedListener = null;
if (viewPager != null)
mViewPager = viewPager;
// Add our custom OnPageChangeListener to the ViewPager
if (mPageChangeListener == null)
mPageChangeListener = new TabLayoutOnPageChangeListener(this);
mPageChangeListener.reset();
viewPager.addOnPageChangeListener(mPageChangeListener);
// Now we'll add a tab selected listener to set ViewPager's current item
mCurrentVpSelectedListener = new ViewPagerOnTabSelectedListener(viewPager);
addOnTabSelectedListener(mCurrentVpSelectedListener);
final PagerAdapter adapter = viewPager.getAdapter();
if (adapter != null)
// Now we'll populate ourselves from the pager adapter, adding an observer if
// autoRefresh is enabled
setPagerAdapter(adapter, autoRefresh);
// Add a listener so that we're notified of any adapter changes
if (mAdapterChangeListener == null)
mAdapterChangeListener = new AdapterChangeListener();
mAdapterChangeListener.setAutoRefresh(autoRefresh);
viewPager.addOnAdapterChangeListener(mAdapterChangeListener);
// Now update the scroll position to match the ViewPager's current item
setScrollPosition(viewPager.getCurrentItem(), 0f, true);
else
// We've been given a null ViewPager so we need to clear out the internal state,
// listeners and observers
mViewPager = null;
setPagerAdapter(null, false);
mSetupViewPagerImplicitly = implicitSetup;
里面调了几个重载方法,关注最后一个setupWithViewPager方法中的这一段代码:
final PagerAdapter adapter = viewPager.getAdapter();
if (adapter != null)
// Now we'll populate ourselves from the pager adapter, adding an observer if
// autoRefresh is enabled
setPagerAdapter(adapter, autoRefresh);
继续看看setPagerAdapter
void setPagerAdapter(@Nullable final PagerAdapter adapter, final boolean addObserver)
if (mPagerAdapter != null && mPagerAdapterObserver != null)
// If we already have a PagerAdapter, unregister our observer
mPagerAdapter.unregisterDataSetObserver(mPagerAdapterObserver);
mPagerAdapter = adapter;
if (addObserver && adapter != null)
// Register our observer on the new adapter
if (mPagerAdapterObserver == null)
mPagerAdapterObserver = new PagerAdapterObserver();
adapter.registerDataSetObserver(mPagerAdapterObserver);
// Finally make sure we reflect the new adapter
populateFromPagerAdapter();
最后执行了populateFromPagerAdapter这个方法,接着看:
void populateFromPagerAdapter()
removeAllTabs();
if (mPagerAdapter != null)
final int adapterCount = mPagerAdapter.getCount();
for (int i = 0; i < adapterCount; i++)
addTab(newTab().setText(mPagerAdapter.getPageTitle(i)), false);
// Make sure we reflect the currently set ViewPager item
if (mViewPager != null && adapterCount > 0)
final int curItem = mViewPager.getCurrentItem();
if (curItem != getSelectedTabPosition() && curItem < getTabCount())
selectTab(getTabAt(curItem));
可以看到这个方法里首先执行removeAllTabs,清除了TabLayout的所有Tabs,然后遍历添加Tab:
addTab(newTab().setText(mPagerAdapter.getPageTitle(i)), false);
我们要注意setText中设置的是mPagerAdapter中getPageTitle拿到的值,好吧,我们的PagerAdapter中那就得实现getPageTitle方法了:
@Nullable
@Override
public CharSequence getPageTitle(int position)
return girlList.get(position).name;
到这里TabLayout标签不展示的问题就解决了!
二、TabLayout标签的customView不显示
接着上面的问题,运行起来看看页面:
但是这里又有一个新的问题,我们会发现这里展示的样式并不是我们自己设置的View样式,从上面的代码中也可以知道,因为populateFromPagerAdapter中清除了所有的Tabs,然后取的是PagerAdapter中的title,所以这就会丢掉我们setCustomView中设置的样式,那我们应该怎么改呢?
这里最简单粗暴的方式是注释掉那两行代码:
void populateFromPagerAdapter()
//removeAllTabs();
if (mPagerAdapter != null)
final int adapterCount = mPagerAdapter.getCount();
//for (int i = 0; i < adapterCount; i++)
// addTab(newTab().setText(mPagerAdapter.getPageTitle(i)), false);
//
// Make sure we reflect the currently set ViewPager item
if (mViewPager != null && adapterCount > 0)
final int curItem = mViewPager.getCurrentItem();
if (curItem != getSelectedTabPosition() && curItem < getTabCount())
selectTab(getTabAt(curItem));
这样的话就可以解决样式丢失的问题了。
三、TabLayout的tab点击无反应
如图所示,会发现我们关联ViewPager后,是可以左右滑动联通TabLayout切换动画的,但是当我们点击TabLayout的Tab的时候是没有任何反应的,可以理解为点击事件失效,刚开始我也以为是代码写的不对导致的,但是排查了半天发现并没有什么不妥之处,后来上网查询网友的答案,看到一句话,是不是ViewPager把TabLayout盖住了?
大吃一斤!!!
回过来看看自己的布局,用的是RelativeLayout,然后TabLayout放在ViewPager位置的上面
<com.zhangyan.mytablayout.tablayout.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Hello World!"
app:tabGravity="fill"
app:tabIndicatorColor="#CBA788"
app:tabIndicatorHeight="3dp"
app:tabLineOffset="10dp"
app:tabMode="fixed"
app:tabSelectedTextColor="#CBA788"
app:tabTextColor="#CCFFFFFF" />
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
由于ViewPager的Item并没有背景颜色,所以这样显示出来并无不妥之处,TabLayout仍然显示出来了,但是实际上是被ViewPager盖住了,所以这就是导致ViewPager滑动能联动TabLayout滑动,但是TabLayout点击无反应的原因!
四、TabLayout源码
在使用TabLayout和ViewPager时特别需要注意某些设置关联的时机,并且在该判空的地方做好空指针判断,避免出问题,另外由于系统的TabLayout源码支持自定义的可改动性较差,那么这里我们将系统的TabLayout源码拷贝出来了,进行了一些修改,在使用过程中可以对一些属性进行个性化的配置,不再局限于系统样式了,上述案例的源码和TabLayout的源码都在附件中,有需要的同学可以自取,么么哒各位~
以上是关于TabLayout与ViewPager配合使用踩坑总结的主要内容,如果未能解决你的问题,请参考以下文章
关于TabLayout与ViewPager在Fragment中嵌套Fragment使用或配合使用的思考
关于tablayout+viewpager+fragment配合使用的一点记录
使用ViewPager和TabLayout与Xamarin时出错
如何在 Android 中使用 TabLayout 和 ViewPager2