今天要实现这样的一个效果,下面的indicator是一个不规则的矩形,所以使用原生的TabLayout必须用定制的CustomView
,在切换的时候动态更换CustomView
的背景。
方法很简单,代码如下:
val tabTitles = arrayOf("全部", "合格证", "发票", "打款凭证", "其他票据")
tabTitles.forEach {
val tab = ui.tabLayout.newTab()
tab.customView = createView(it)
ui.tabLayout.addTab(tab)
}
private fun createView(title: String): View {
return TextView(mActivity).apply {
text = title
includeFontPadding = false
gravity = Gravity.CENTER
setPadding(dip(10), dip(5), dip(10), dip(5))
textColor = mActivity.getColorKt(R.color.color_1F3F58)
compoundDrawablePadding = mActivity.dip(3)
textSize = 14f
}
}
本以为这样就搞定了,运行出来并不是我们想要的效果,给CustomView设置的效果没有效果,文字显示的默认的样式,点击tab还闪退了,这使我感到不解。经过排查发现我使用了 setupWithViewPager
,当我们自定义TabLayout时,设置setupWithViewPager
会删除所有TabLayout动态添加的View和设置的监听。简单的看下源码:
private void setupWithViewPager(
@Nullable final ViewPager viewPager, boolean autoRefresh, boolean implicitSetup) {
//下面是移除我们自己设置的各种监听
if (this.viewPager != null) {
// If we've already been setup with a ViewPager, remove us from it
if (pageChangeListener != null) {
this.viewPager.removeOnPageChangeListener(pageChangeListener);
}
if (adapterChangeListener != null) {
this.viewPager.removeOnAdapterChangeListener(adapterChangeListener);
}
}
if (currentVpSelectedListener != null) {
// If we already have a tab selected listener for the ViewPager, remove it
removeOnTabSelectedListener(currentVpSelectedListener);
currentVpSelectedListener = null;
}
if (viewPager != null) {
this.viewPager = viewPager;
// Add our custom OnPageChangeListener to the ViewPager
if (pageChangeListener == null) {
pageChangeListener = new TabLayoutOnPageChangeListener(this);
}
pageChangeListener.reset();
viewPager.addOnPageChangeListener(pageChangeListener);
// Now we'll add a tab selected listener to set ViewPager's current item
currentVpSelectedListener = new ViewPagerOnTabSelectedListener(viewPager);
addOnTabSelectedListener(currentVpSelectedListener);
final PagerAdapter adapter = viewPager.getAdapter();
if (adapter != null) {
//移除所有的tab,根据我们传的adapter创建tab
// 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 (adapterChangeListener == null) {
adapterChangeListener = new AdapterChangeListener();
}
...
} else {
// We've been given a null ViewPager so we need to clear out the internal state,
// listeners and observers
this.viewPager = null;
setPagerAdapter(null, false);
}
}
void setPagerAdapter(@Nullable final PagerAdapter adapter, final boolean addObserver) {
...
// Finally make sure we reflect the new adapter
populateFromPagerAdapter();
}
void populateFromPagerAdapter() {
//移除所有的Tab
removeAllTabs();
if (pagerAdapter != null) {
final int adapterCount = pagerAdapter.getCount();
for (int i = 0; i < adapterCount; i++) {
addTab(newTab().setText(pagerAdapter.getPageTitle(i)), false);
}
// Make sure we reflect the currently set ViewPager item
if (viewPager != null && adapterCount > 0) {
final int curItem = viewPager.getCurrentItem();
if (curItem != getSelectedTabPosition() && curItem < getTabCount()) {
selectTab(getTabAt(curItem));
}
}
}
}
我们发现如果要自定义CustomView
就不能使用setupWithViewPager
和ViewPager进行关联,那还有没有其他的方法可以进行关联呢,答案是有的,方法如下:
//使用TabLayout中的一个静态内部类TabLayoutOnPageChangeListener监听ViewPager切换,传入tabLayout
ui.viewPager.addOnPageChangeListener(object : TabLayout.TabLayoutOnPageChangeListener(ui.tabLayout) {})
//监听TabLayout切换,当Tab被选中切换ViewPager
ui.tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab) {
ui.viewPager.currentItem = tab.position
}
override fun onTabUnselected(tab: TabLayout.Tab) {
}
override fun onTabReselected(tab: TabLayout.Tab) {
}
})