导航栏+滑动页的组合算是目前Android开发最常用的套路之一,最经典的就是微信主界面。
我整理了一下TabLayout+ViewPager的最常用操作,方便以后使用(自己记忆力不好,每次都要查)。
整套布局主要由四个部分组成:
- TabLayout
- Viewpager
- PagerAdapter (FragmentPagerAdapter)
- ViewPager内容(通常为fragment或ListView)
xml布局和实例化控件
<android.support.design.widget.TabLayout
android:id="@+id/tab"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
app:tabIndicatorHeight="1dp"
app:tabIndicatorColor="@color/orange"
app:tabSelectedTextColor="@color/orange"
app:tabMode="fixed"
app:tabBackground="@color/white"
app:tabTextColor="@color/dark"/>
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:layout_marginTop="1px"/>
TabLayout mTabLayout = (TabLayout)findViewById(R.id.tab);
ViewPager mViewPager = (ViewPager)findViewById(R.id.viewpager);
这里面比较有用的是TabLayout的几个自定义命名空间“app”的属性,大部分人属性的作用从名字就可以看出来。(tabIndicator是指标签的下划线)
app:tabMode有两个值:fixed和scrollable。fixed是所有标签平分整个tabLayout,scrollable让tabLayout可滚动以显示超出屏幕的部分。
调用比较多的方法
TabLayout常用到的方法:
1.绑定ViewPager:
mTabLayout.setupWithViewPager(mViewPager,true);
官方API强调,如果传入的第一个参数viewpager不为空,这个viewpager必须已经设置好PagerAdapter。
2.获取每个Tab标签对象
mTabLayout.getTabAt(position);
position从0开始,代表从左到右每个位置的Tab。获取了每个Tab对象之后,我们可以接着对这些Tab进行更多的操作:
2.1自定义Tab的布局
如果需要开发复杂的或者动态的tab,我们需要给tab传入自定义布局(比如:当有未读消息的时候,tab标签上会展示一个红点)
mTabLayout.getTabAt(position).setCustomView(view);
后面想要对某个tab中的某一控件进行具体操作也就简单了:
View view = mTabLayout.getTabAt(position).getCustomView().findViewById(R.id.xxx);
2.2 设置Tab的图标
虽然说对tab使用自定义布局可以解决大部分需求,不过有的时候我们并不需要这么复杂,而是仅仅需要插入一个图标。
mTabLayout.getTabAt(0).setIcon(drawable);
这样就可以在指定的tab中直接插入一个图标。图标默认显示在文字的上方。
ViewPager常用到的方法:
1. 给viewpager绑定换页的监听器。
mViewPager.addOnPageChangeListener(this);
注意这里不能使用setOnPageChangeListener,而要使用addOnPageChangeListener
ViewPager.OnPageChangeListener接口有三个方法:
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
这三个回调方法都好理解,其中用的最多的就是onPageSelected,position是第几个view,从0开始计算。
2.设置viewpager的预加载页数
mViewPager.setOffscreenPageLimit(3);
这个方法是设置viewpager当前view的左右两边的预加载的页面的个数,默认值是1
在源码中,这个值不能小于1,如果需要让viewpager不预加载,可能需要自定义viewpager并修改默认值。
3.设置适配器
mViewPager.setAdapter(adapter);
setAdapter是必不可少的,也很好理解,和ListView,RecyclerView设置adapter差不多。
PagerAdapter
和别的适配器一样,ViewPager通过PagerAdapter来获取每一页的内容。
下面是一个PagerAdapter的例子,我们只在ViewPager中展示RecyclerView
private List<String> title = new ArrayList<>();
title.add("微信");
title.add("通讯录");
title.add("发现");
title.add("我");
private List<RecyclerView> recyclerViewList = new ArrayList<>();
class RecyclerViewPagerAdapter extends PagerAdapter{
@Override
public int getCount() {
return recyclerViewList.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public CharSequence getPageTitle(int position) {
return title.get(position);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
container.addView(recyclerViewList.get(position));
return recyclerViewList.get(position);
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(recyclerViewList.get(position));
}
}
这里面比较重要的是getPageTitle,注意标题传入的顺序。别的都比较套路(Android里面控件的Adapter都是一些比较模式化的东西)。
FragmentPagerAdapter
FragmentPagerAdapter是PagerAdapter的子类,专门用于ViewPager内容全部为fragment的情况(这也是使用ViewPagerr的大部分场景)。
FragmentPagerAdapter有一个自己的方法getItem(int position),用于生成新的fragment。我们可以在这个函数中返回position处的fragment。
class MyAdapter extends FragmentPagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
return null;
}
@Override
public int getCount() {
return 0;
}
}
上面是一个崭新的FragmentPagerAdapter,可以看到FragmentPagerAdapter 必须有一个带参数的构造方法,参数为FragmentManager实例。
FragmentManager并不是陌生的东西,只要用到fragment的地方都会用到FragmentManager。通常获取FragmentManager的方法为getSupportFragmentManager()
,但是,如果你是在一个fragment中使用FragmentPagerAdapter,这里就要使用getChildFragmetManager()
ViewPager中放置一个View
在ViewPager中放入fragment,只需要把所有Fragment的实例存入List<Fragment>
,再将List传入FragmentPagerAdapter就行。
如果想在ViewPager中仅仅放入一个View,比如RecyclerView,也是一样的,将RecyclerView的实例存入List<RecyclerView>
。
如何获取RecyclerView的实例,我通常这么做:
RecyclerView recyclerView = (RecyclerView)getLayoutInflater().inflate(R.layout.xxx,null,false);
自定义RecyclerView的layout,然后通过LayoutInflater()传入空的recyclerView实例。