VerticalTabLayout 是一种纵向的TabLayout,为了满足各种需求被某作者开发出来,怎么开发的暂且不讨论了,先讨论拿来使用,在Android studio gradle文件中添加
compile 'q.rorbin:VerticalTabLayout:1.2.5'
xml | code | 说明 |
---|---|---|
app:indicator_color | setIndicatorColor | 指示器颜色 |
app:indicator_width | setIndicatorWidth | 指示器宽度 |
app:indicator_gravity | setIndicatorGravity | 指示器位置 |
app:indicator_corners | setIndicatorCorners | 指示器圆角 |
app:tab_mode | setTabMode | Tab高度模式 |
app:tab_height | setTabHeight | Tab高度 |
app:tab_margin | setTabMargin | Tab间距 |
VerticalTabLayout 不是继承与Tablayout,而是继承于NestedScrollView,而NestedScrollView继承于Framelayout,所以基本和TableLayout的用法差不多,下面简单介绍几个常用方法
public void setupWithFragment(FragmentManager manager, List fragments) {
this.setupWithFragment(manager, 0, fragments);
}
public void setupWithFragment(FragmentManager manager, int containerResid, List fragments) {
if (this.mTabFragmentManager != null) {
this.mTabFragmentManager.detach();
}
if (containerResid != 0) {
this.mTabFragmentManager = new TabFragmentManager(manager, containerResid, fragments, this);
} else {
this.mTabFragmentManager = new TabFragmentManager(manager, fragments, this);
}
}
第一个方法最终调用的也是第二个方法,所以只讲第二个,看参数可以知道这两个方法都是把一些fragment和tab相绑定起来,达到点击tab显示对应fragment的目的,第一个方法没有传入containerResid,所以他会把fragment都加载在tablayout本身身上,需要空出空间来显示fragment,而第一个方法传入了containerResid所以fragment都会显示到传入的view上。
所有参数传入之后先会根据containerResid是否出入构建TabFragmentManager对象,这个对象里会直接把fragment全部加到FragmentTransaction中供切换使用
public void setupWithFragment(FragmentManager manager, List fragments, TabAdapter adapter);
public void setupWithFragment(FragmentManager manager, int containerResid, List fragments, TabAdapter adapter)
public void setupWithFragment(FragmentManager manager, int containerResid, List fragments, TabAdapter adapter) {
this.setTabAdapter(adapter);
this.setupWithFragment(manager, containerResid, fragments);
}
这两个方法,看起来好像和上面两个方法也是重载关系,唯一不同的就是这两个方法还多传入了一个参数TabAdapter,这个参数很有用,tab的风格都是由这个adapter决定,其实这两个方法最后都会调用之前的方法,只是比之前多做了一步setTabAdapter,这个方法就是设置TabLayout的方法,可以设置tablayout显示几个,显示成什么样
public void setupWithViewPager(@Nullable ViewPager viewPager);
这个方法就更加厉害了,它是直接把viewpager和tablayout绑定起来,只要将viewpager设置好出入,他就会直接从viewpager中解析数据然后显示出来,看他的代码
public void setupWithViewPager(@Nullable ViewPager viewPager) {
if (this.mViewPager != null && this.mTabPageChangeListener != null) { //判断有没添加监听有就移除
this.mViewPager.removeOnPageChangeListener(this.mTabPageChangeListener);
}
if (viewPager != null) {
PagerAdapter adapter = viewPager.getAdapter();// 获取viewpager的适配器
if (adapter == null) {
throw new IllegalArgumentException("ViewPager does not have a PagerAdapter set");
}
this.mViewPager = viewPager;
if (this.mTabPageChangeListener == null) {
this.mTabPageChangeListener = new VerticalTabLayout.OnTabPageChangeListener();
}
// 添加新的监听
viewPager.addOnPageChangeListener(this.mTabPageChangeListener);
this.addOnTabSelectedListener(new VerticalTabLayout.OnTabSelectedListener() {
public void onTabSelected(TabView tab, int position) { //这里基本上就是把viewpager的位置和tab位置相绑定了
if (VerticalTabLayout.this.mViewPager != null && VerticalTabLayout.this.mViewPager.getAdapter().getCount() >= position) {
VerticalTabLayout.this.mViewPager.setCurrentItem(position);
}
}
public void onTabReselected(TabView tab, int position) {
}
});
this.setPagerAdapter(adapter, true);// 这个方法中开始会对viewpager监察还有设置tablayout的一些东西
} else {
this.mViewPager = null;
this.setPagerAdapter((PagerAdapter)null, true);
}
}
上面的方法最终会走到这里populateFrompageradapter,这个方法很重要,主要是对tablayout的一下设置
private void populateFromPagerAdapter() {
this.removeAllTabs();
if (this.mPagerAdapter != null) {
int adapterCount = this.mPagerAdapter.getCount();
int curItem;
if (this.mPagerAdapter instanceof TabAdapter) { // 获取pageradapter是不是实现了TabAdapter借口如果实现了,就直接调用setTabAdapter,负责走默认风格
this.setTabAdapter((TabAdapter)this.mPagerAdapter);
} else {
for(curItem = 0; curItem < adapterCount; ++curItem) {//获取viewpager的title 作为tab的title,然后一个个添加,全部使用默认风格,默认风格无法更改,不太美观
String title = this.mPagerAdapter.getPageTitle(curItem) == null ? "tab" + curItem : this.mPagerAdapter.getPageTitle(curItem).toString();
this.addTab((new QTabView(this.mContext)).setTitle((new Builder()).setContent(title).build()));
}
}
if (this.mViewPager != null && adapterCount > 0) {
curItem = this.mViewPager.getCurrentItem();
if (curItem != this.getSelectedTabPosition() && curItem < this.getTabCount()) {
this.setTabSelected(curItem);
}
}
} else {
this.removeAllTabs();
}
}
接下来看看setTabAdapter到底干了啥
public void setTabAdapter(TabAdapter adapter) {
this.removeAllTabs();
if (adapter != null) {
this.mTabAdapter = adapter;
for(int i = 0; i < adapter.getCount(); ++i) {
this.addTab((new QTabView(this.mContext)).setIcon(adapter.getIcon(i)).setTitle(adapter.getTitle(i)).setBadge(adapter.getBadge(i)).setBackground(adapter.getBackground(i)));
}
}
}
可以看到,在这个方法里只做了一件事就是添加tab,添加有自定义风格的tab,没错这就是我们想要的,我们的每一个tab不仅可以设置title而且可以设置icon,badge(不知道是是什么鬼),background,这一系列的东西都是我们开发时候想要的,改成自己的风格,接下来看看TabAdapter
public interface TabAdapter {
int getCount();//个数
TabBadge getBadge(int var1);
TabIcon getIcon(int var1);// 图标,传入参数是资源id
TabTitle getTitle(int var1);//标题
int getBackground(int var1);//每个一个tab的背景,这里不仅可以用图片还能使用selector,非常好用
}
原来它是一个接口,很有意思了,上面说的viewpager要有自定义风格的话就必须让他的适配器实现这个接口,然后把方法一一实现就能有自定义的风格了,如果有一些参数不能满足自己的审美,我们还可以再改通过获取QTabView这个是每一个tab的view实体,里面有很多的方法可以使用,我们可以通过设置完参数之后再调用 getTabAt(i).getTitleView()