以前要实现Android选项卡视图,基本上使用的是TabHost,不过谷歌已经不推荐使用了。现在比较普遍的是采用TabLayout实现选项卡布局。

布局

首先,在你的布局文件里,添加一个TabLayout布局

<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >

    <android.support.design.widget.TabLayout
        android:id="@+id/tab"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        >

    </android.support.design.widget.TabLayout>

</LinearLayout>

然后在onCreate的时候,给它添加两个tab

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);

   TabLayout tabLayout = (TabLayout)findViewById(R.id.tab);
   TabLayout.Tab tab1 = tabLayout.newTab().setText("tab111");
   TabLayout.Tab tab2 = tabLayout.newTab().setText("tab222");

   tabLayout.addTab(tab1);
   tabLayout.addTab(tab2);

}
    

此时的效果是这样的。只有两个选项卡,卡的标题不同,点击的时候才能切换,里面没什么内容。

tablayout just add tab

现在只是有两个tab,但是tab里没有内容。

tab.setCustomView()只是用来设置tab标签的自定义视图,而不是tab所代表的内容视图。
tab.setCustomView如果放在tablayout.addTab之前执行,那么会报错。

监听tab切换

在onCreate里面继续添加以下代码,给tablayout添加上切换监听

tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
      @Override
      public void onTabSelected(TabLayout.Tab tab) {

          int position = tab.getPosition();
          Log.d(this.getClass().toString(), "tab;selected;position=" + tab.getPosition());
      }

      @Override
      public void onTabUnselected(TabLayout.Tab tab) {
          Log.d(this.getClass().toString(), "tab;unselected;position=" + tab.getPosition());
      }

      @Override
      public void onTabReselected(TabLayout.Tab tab) {
          Log.d(this.getClass().toString(), "tab;released;position=" + tab.getPosition());
      }
  });


在onTabSelected里面,根据position就可以知道点击的是第几个选项卡,从而做出相应的响应。一开始创建的时候并不会触发上面这三个函数中的任何一个,而是当有切换动作的时候,才会触发。

此时的切换,还只能是点击切换。如果要使用滑动切换,就要用到viewpager

滑动切换

在布局文件里添加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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >

    <android.support.design.widget.TabLayout
        android:id="@+id/tab"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        >

    </android.support.design.widget.TabLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"  />

</LinearLayout>

要将viewpager绑定在tablayout上。由viewpager来绑定两个fragment


@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_sendback);
   Log.d(this.getClass().toString(), "-------onCreate---------");


   tabLayout = (TabLayout)findViewById(R.id.tab_needSend);
   viewPager = (ViewPager)findViewById(R.id.viewpager);

   viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
   viewPagerAdapter.addFragment(new FragmentOne(), "tab one";
   viewPagerAdapter.addFragment(new FragmentTwo(), "tab two");
   viewPager.setAdapter(viewPagerAdapter);

   tabLayout.setupWithViewPager(viewPager);
   tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
       @Override
       public void onTabSelected(TabLayout.Tab tab) {

           int position = tab.getPosition();

           viewPager.setCurrentItem(position);//如果不添加此句,则点击的时候视图不会切换
           Log.d(this.getClass().toString(), "tab;selected;position=" + tab.getPosition());
           if (0 == position) {
               FragmentOne fragment = (FragmentOne)viewPagerAdapter.getItem(position);
               fragment.refreshData();//刷新数据
           }else{
               FragmentTwo fragment = (FragmentTwo)viewPagerAdapter.getItem(position);
               fragment.refreshData();
           }

       }

       @Override
       public void onTabUnselected(TabLayout.Tab tab) {
           Log.d(this.getClass().toString(), "tab;unselected;position=" + tab.getPosition());
       }

       @Override
       public void onTabReselected(TabLayout.Tab tab) {
           Log.d(this.getClass().toString(), "tab;released;position=" + tab.getPosition());
       }
   });
}

这样就实现了即能点击切换,又能滑动切换。切换的时候还会刷新数据。


类似于这种TabLayout里面有多个Fragment的布局形式,假如在Fragment的布局文件里定义了一个Button,并给它写上属性android:onClick=“btClicked”,那么运行的时候,程序会去Fragment所在的Activity里去找有没有public void btClicked(View v)这个方法。

而我之前只是在Fragment本身的类方法里面实现了btClicked方法,所以程序每次都会崩掉,说在Activity里面找不到相应的方法。

这种问题的解决方法有两种:

1.在Fragment布局文件里依旧使用Button的android:onClick属性,然后在Activity里面定义相关方法,然后根据view的id或者tag来做区分,做出相应的响应。

2.在Fragment布局文件里去处Button的android:onClick属性,然后在Fragment类里面对button设置监听。

我倾向于第二种方法,毕竟属于这个Fragment的事情还是发生在这个Fragment类里面比较好。


修改tab颜色

修改选中条的颜色
tabLayout.setSelectedTabIndicatorColor

修改选中和不选中时tab字体的颜色
tabLayout.setTabTextColors

源代码中对setTabTextColors的解释:
tab text color