Android使用TabLayout与ViewPager结合以及TabItem自定义
使用android的design支持包中的android.support.design.widget.TabLayout结合ViewPager/Fragment来写多Tab的应用,只需要一句代码,就可以完成Tab与ViewPager切换的联动,免除很多麻烦。
mTabLayout.setupWithViewPager(mViewPager);
先写个主布局文件,只需要加入ViewPager和TabLayout即可,Tab可在ViewPager上方,也可在下方,看各自需求:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:clipToPadding="true" android:orientation="vertical"> <android.support.v4.view.ViewPager android:id="@+id/container_viewpager" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:background="@color/color_white" /> <android.support.design.widget.TabLayout android:id="@+id/tab_layout" android:layout_width="match_parent" android:layout_height="@dimen/tabbar_def_height" app:tabBackground="@color/color_f7f7f7" app:tabIndicatorHeight="@dimen/margin_0" app:tabMode="fixed" /> </LinearLayout>
在java代码中,ViewPager按常规设置个PagerAdapter就有效果了,但需要和Tab关联,需要加上setupWithViewPager()的调用:
mViewPager = (ViewPager) findViewById(R.id.container_viewpager); mTabLayout = (TabLayout) findViewById(R.id.tab_layout); ... mViewPager.setAdapter(pagerAdapter); mTabLayout.setupWithViewPager(mViewPager);
如此之后发现,ViewPager可以正常使用,TabLayout的标题却没有显示,这时,如果TabLayout上只需要显示文字标题,就很容易了,在我们自定义的PagerAdapter里重写getPageTitle方法,TabLayout与ViewPager结合以后它会从这里读取内容去显示:
public class MainPagerAdapter extends FragmentPagerAdapter { ... @Override public CharSequence getPageTitle(int position) { return titles.get(position); } }
Tab的标题显示出来了,联动也可以了,样式的话,在TabLayout控件的属性里设置就行了。什么?标题光有文字还不够?那也可以,只想在上方加个图标,弄个仿微信样式的话也不需要自定义布局文件,主要有两种办法,第一是在setupWithViewPager之后,把循环给单个Tab设置icon:
mTabLayout.setupWithViewPager(mViewPager); mTabLayout.getTabAt(0).setIcon(R.mipmap.ic_launcher); mTabLayout.getTabAt(1).setIcon(R.mipmap.ic_launcher); mTabLayout.getTabAt(2).setIcon(R.mipmap.ic_launcher);
另一种办法可以直接把Tab布局写死,使用控件android.support.design.widget.TabItem即可,形如:
<android.support.design.widget.TabLayout android:id="@+id/tablayout" android:background="@color/colorPrimary" android:layout_width="match_parent" android:layout_height="wrap_content"> <android.support.design.widget.TabItem android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Android"/> <android.support.design.widget.TabItem android:layout_width="match_parent" android:layout_height="wrap_content" android:icon="@mipmap/ic_launcher"/> </android.support.design.widget.TabLayout>
如此操作,效果也是可以给TabItem设置一个图标和一个文字标题。当然,如果想要定制更加复杂的TabLayout,同样是先获取Tab,给它设置自定义View即可:
mTabLayout.getTabAt(i).setCustomView(view);
自定义的完整代码如下:
首先我自定义了一个结构TabItemInfo,用于方便用代码添加Tab和ViewPager的Item,一看便明了:
public class TabItemInfo { private Class<? extends Fragment> fragmentClass; private int nameResource; private int iconResource; public TabItemInfo(Class<? extends Fragment> fragmentClass, @StringRes int nameResource, @DrawableRes int iconResource) { this.fragmentClass = fragmentClass; this.nameResource = nameResource; this.iconResource = iconResource; } public Class<? extends Fragment> getFragmentClass() { return fragmentClass; } public int getNameResource() { return nameResource; } public int getIconResource() { return iconResource; } }
PagerAdapter,无奇特之处,只是多加了一个根据position来获取自定义TabView的方法,以便在Activity里设置TabLayout的时候可以方便获取:
public class MainPagerAdapter extends FragmentPagerAdapter { private Context mContext; private List<TabItemInfo> mTabItems; public MainPagerAdapter(Context context, FragmentManager fm, List<TabItemInfo> tabItems) { super(fm); mContext = context; mTabItems = tabItems; } @Override public Fragment getItem(int position) { try { return mTabItems.get(position).getFragmentClass().newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return null; } @Override public int getCount() { return mTabItems.size(); } public View getTabView(int position) { TabItemInfo itemInfo = mTabItems.get(position); View view = LayoutInflater.from(mContext).inflate(R.layout.custom_view_tab_item, null); TextView tv = (TextView) view.findViewById(R.id.tab_text); tv.setText(itemInfo.getNameResource()); ImageView img = (ImageView) view.findViewById(R.id.tab_image); img.setImageResource(itemInfo.getIconResource()); return view; } }
在Activity里设置ViewPager和TabLayout:
mViewPager = (ViewPager) findViewById(R.id.container_viewpager); mTabLayout = (TabLayout) findViewById(R.id.tab_layout); List<TabItemInfo> tabItems = new LinkedList<>(); tabItems.add(new TabItemInfo(CashLoanFragment.class, R.string.cash_loan, R.drawable.apply_tab_icon_drawable)); tabItems.add(new TabItemInfo(GoodsLoanFragment.class, R.string.apply_credit, R.drawable.phone_tab_icon_drawable)); tabItems.add(new TabItemInfo(UserCenterNewFragment.class, R.string.user_center, R.drawable.my_tab_icon_drawable)); MainPagerAdapter pagerAdapter = new MainPagerAdapter(this, getSupportFragmentManager(), tabItems); mViewPager.setAdapter(pagerAdapter); mTabLayout.setupWithViewPager(mViewPager); for (int i = 0; i < mTabLayout.getTabCount(); i++) { TabLayout.Tab tab = mTabLayout.getTabAt(i); if (tab != null) { tab.setCustomView(pagerAdapter.getTabView(i)); } }
这样之后,自定义的TabItemView就设置好了,注意,自定义的布局里,background,textColor之类的,可以用selector指定好选中状态和非选中状态的不同资源,这样TabLayout左右切换的时候,才会有效果。