以前看慕课网的教程,写过一个微信Tab选项卡切换的例子,使用的是ViewPager+Fragment来实现的,说实话,当时为了实现一些效果,还是写了蛮多的代码,但是,今天介绍的TabLayout+ViewPager+Fragment实现导航栏可以使用很少的代码实现很棒的效果。

首先说说TabLayout,它是在Android5.0之后提出的,可以实现Material Design效果,可以方便地帮助我们实现导航栏的效果。接着说一下ViewPager,它是Android扩展包v4中的类,可以实现view的左右切换。Fragment就不过多介绍了,相信大家都了解。下面就说说具体的实现步骤:

一、实现顶部导航栏

1 . 添加所需依赖

compile 'com.android.support:appcompat-v7:24.2.0'
compile 'com.android.support:design:24.2.0'

说明:上面的第一个包我们在创建Android工程的时候一般会默认引入,他其中包含了Android support v4的包,我们此处是使用v4包中的ViewPager。下面的那个包是我们要使用其中的TabLayout。

2 . 创建对应于每个Tab选项卡的Fragment

接着我们创建对应于每个Tab的View页面,假设你需要3个Tab,则对应创建3个Fragment文件,并生成每个Fragment对应的布局文件。此处写一个作为示例。

Fragment1.java

public class Fragment1 extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment1,container, false);
    }
}

fragment1.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</RelativeLayout>

3 . 定义适配器

接着我们要开始定义适配器类,为下一步的绑定做准备。

public class MyFragmentPagerAdapter extends FragmentPagerAdapter {
    private String[] mTitles = new String[]{"Fragment1", "Fragment2"};

    public HomeFragmentPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        //此处根据不同的position返回不同的Fragment
        if (position == 1){
            return new Fragment2();
        }
        return new Fragment1();
    }

    @Override
    public int getCount() {
        //此处返回Tab的数目
        return mTitles.length;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        //此处返回每个Tab的title
        return mTitles[position];
    }
}

上面的代码很好理解,这里不再解释。

4 . 创建主布局文件

由于我们要实现的是顶部导航栏,所有我们此处的布局应该为上面部分是TabLayout,下面部分是ViewPager,布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/activity_role"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="@color/colorGray">
    <android.support.design.widget.TabLayout
        app:tabGravity="fill"
        android:id="@+id/home_tablayout"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:background="@color/colorWhite"
        app:tabIndicatorColor="#66ff33"
        app:tabIndicatorHeight="2dp"
        app:tabTextColor="@color/colorTheme"
        app:tabSelectedTextColor="#CC33FF"
        app:tabMode="fixed"
        app:tabBackground="@drawable/tablayout_selector"
        app:tabTextAppearance="@style/TabLayoutTextAppearance">
    </android.support.design.widget.TabLayout>
    <android.support.v4.view.ViewPager
        android:id="@+id/home_viewpager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">

    </android.support.v4.view.ViewPager>
</LinearLayout>

上面ViewPager的使用没什么好说的,主要是说说TabLayout的一些属性:

属性

作用

tabGravity

fill 多个tab会平分TabLayout来显示 / center 多个tab会按实际大小在TabLayout上居中显示

tabIndicatorColor

tab上面指示器的颜色

tabIndicatorHeight

tab上面指示器的高度

tabTextColor

tab上面显示的字体的颜色

tabSelectedTextColor

tab被选中时字体的颜色

tabMode

fixed TabLayout上多个tab是固定的 / scrollable 多个tab时,tab是可以滚动的

注意:这是我踩过的一个坑,当时我把 tabMode设置为scrollable,然后发现tabGravity设置为fill,可是tab还是不能平分TabL,后来才知道,只有tabMode设置为fixed时,tabGravity设置为fill才会生效。

上面的tabBackground我是使用自定义的一个selector实现tab在选中和未选中状态的背景颜色,下面是代码

tablayout_selector.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_selected="true"
        android:drawable="@color/colorTheme"/>
    <item android:drawable="@color/colorGray"/>
</selector>

tabTextAppearance属性是自己简单定义的一个文本样式,主要是设置字体大小及颜色,下面是代码:
style.xml文件

<style name="TabLayoutTextAppearance" parent="TextAppearance.AppCompat.Widget.ActionBar.Title">
        <item name="android:textSize">15sp</item>
        <item name="android:textColor">@color/colorTextGray</item>
</style>

5 . 在MainActivity中绑定布局

private TabLayout mTabLayout;
private ViewPager mViewPager;
private MyFragmentPagerAdapter mFragmentPagerAdapter;

private TabLayout.Tab mTab1;
private TabLayout.Tab mTab2;

mViewPager = (ViewPager) findViewById(R.id.m_viewpager);
mFragmentPagerAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager());
//给ViewPager设置适配器
mViewPager.setAdapter(mFragmentPagerAdapter);
//tablayout与Viewpager绑定
mTabLayout = (TabLayout) findViewById(R.id.m_tablayout);
mTabLayout.setupWithViewPager(mViewPager);

mTab1 = mTabLayout.getTabAt(0);
mTab = mTabLayout.getTabAt(1);

通过上面的设置,就可以实现顶部导航栏啦。

下面放上一个效果图:

Android TabLayout 选择后 下面变换view tablayout+viewpager+fragment_tablayout

Android TabLayout 选择后 下面变换view tablayout+viewpager+fragment_xml_02


二、实现底部导航栏

其实,底部导航栏非常好实现,我们只需要在布局文件中,将上面的部分放置ViewPager,下面的部分放置TabLayout即可,其他内容不变。或许我们有时候需要在底部导航栏加入小图标,那我们就可以在上面的基础上通过以下代码进行设置:

mTab1.setIcon(R.drawable.ic_1);
mTab2.setIcon(R.drawable.ic_2);

有时候我们可能并不希望我们的ViewPager是可滑动切换的,只希望它可以点击切换,那我们可以通过自定义ViewPager,同时让其不再拦截触摸事件即可,代码如下:

public class DisabledTouchViewPager extends ViewPager {
    //true为允许滑动手势
    private boolean enable = false;

    public DisabledTouchViewPager(Context context) {
        super(context);
    }

    public DisabledTouchViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return enable;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return enable;
    }
}

然后将xml文件中的ViewPager换成我们自定义的ViewPager即可。记得必须使用自定义ViewPager的完整路径。