现象:在使用TabLayout的时候,实现ViewPager Indicator 的效果
代码:
NewsPagerAdapter adapter = new NewsPagerAdapter(getSupportFragmentManager(), fragmentList);
vpnewInfo = (ViewPager) findViewById(R.id.vp_newInfo);
indiactor = (TabLayout) findViewById(R.id.tl_indiactor);
vpnewInfo.setAdapter(adapter);
indiactor.setupWithViewPager(vpnewInfo);
但是运行的时候会报错:ClassNotFoundException: Didn't find class "android.support.v7.internal.widget.TintManager
就是这句代码:indiactor.setupWithViewPager(vpnewInfo);
在给TabLayout关联ViewPager的时候报错,
先说解决办法吧:
在引入design包的时候,版本要和appcompat版本一致。
但是为什么呢?
今天有空,正好看一下TabLayout是怎么实现的?内部原理的是怎样的?为什么版本一致就能解决问题了呢?知其然,知其所以然。
TabLayout实现源码:
public void setupWithViewPager(@NonNull ViewPager viewPager) {
final PagerAdapter adapter = viewPager.getAdapter();
if (adapter == null) {
throw new IllegalArgumentException("ViewPager does not have a PagerAdapter set");
}
// First we'll add Tabs, using the adapter's page titles
setTabsFromPagerAdapter(adapter);
// Now we'll add our page change listener to the ViewPager
viewPager.addOnPageChangeListener(new TabLayoutOnPageChangeListener(this));
// Now we'll add a tab selected listener to set ViewPager's current item
setOnTabSelectedListener(new ViewPagerOnTabSelectedListener(viewPager));
// Make sure we reflect the currently set ViewPager item
if (adapter.getCount() > 0) {
final int curItem = viewPager.getCurrentItem();
if (getSelectedTabPosition() != curItem) {
selectTab(getTabAt(curItem));
}
}
}
可以看出来setupWithViewPager做了几件事:
1、判断一下,viewpager是否设置了适配器,如果没有,就抛异常(这就是为什么要先设置适配器,在关联TabLayout)。
2、拿到adpter,设置Tab(上边的title),把adpter传进去(具体下面详细谈)。
3、给Tab设置选择监听。
4、给Tab设置当前状态。
根据断点调试发现,setTabsFromPagerAdapter(adapter);这句代码出错,直接跟进去查看源码:
public void setTabsFromPagerAdapter(@NonNull PagerAdapter adapter) {
removeAllTabs();
for (int i = 0, count = adapter.getCount(); i < count; i++) {
addTab(newTab().setText(adapter.getPageTitle(i)));
}
}
通过adpter获取pager的个数,动态设置Tab的个数,而且title的值是通过getPageTitle(i)获取的。
如果继续跟下去,会发现它的调用栈是
addTab()
addTabView()
createTabView()
TabView()
这里,在实现TabView()的时候,发现TintManager报错,最终导致应用崩溃。
但是为什么呢?
TintManager是干嘛的呢?
为什么版本一致了,就能解决这个问题呢?
TintManager查看源码会发现,它是被@hide修饰的,而依赖的类库不一致,就会导致找不到TintManager这个类。
所以会报错。
另:@hide可以修饰的类、常量、函数。谷歌官方意思是:编译时这些API不对外开放,运行时,这些API就可以被访问了。
这就可以解释,为什么会报错 Didn't find class TintManager