Android使用TabLayout与ViewPager结合以及TabItem自定义

importSUC 2017-09-13

使用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左右切换的时候,才会有效果。

相关推荐