Android开发笔记(一百四十七)标签布局TabLayout

时间:2021-01-02 13:34:28
标签布局TabLayout是MaterialDesign库中的一个新控件,常与工具栏Toolbar搭配使用。大家平时常用的App就有不少采用了TabLayout,比如京东App的商品页,从左到右依次是“商品”、“详情”、“评价”,具体界面如下图所示:
Android开发笔记(一百四十七)标签布局TabLayout

京东的这个页面便是典型的Toolbar+TabLayout效果,实现的话不外乎Toolbar内部嵌套TabLayout,然后TabLayout再通过ViewPager集成多个Fragment页。如此说来其实也不复杂,那还是先看看模拟京东的页面效果图。下面是模拟页面之一的“商品”页:
Android开发笔记(一百四十七)标签布局TabLayout

下面是模拟页面之一的“详情”页:
Android开发笔记(一百四十七)标签布局TabLayout

接下来看看这两个页面互相切换的动图,切换操作可以通过点击顶部的标签文字实现(TabLayout切换页面),也可以通过在下方左右滑动页面实现(ViewPager切换页面)。如下所示:
Android开发笔记(一百四十七)标签布局TabLayout

看完了效果图,再来分析分析具体的实现过程。TabLayout的展现形式类似PagerTabStrip,一样是文字标签带下划线,不同的是,TabLayout允许定制更丰富的样式,它新增的样式属性主要有:
tabBackground : 指定标签的背景。
tabIndicatorColor : 指定下划线的颜色。
tabIndicatorHeight : 指定下划线的高度。
tabTextColor : 指定标签文字的颜色。
tabTextAppearance : 指定标签文字的风格。
tabSelectedTextColor : 指定选中文字的颜色。

而在代码中,TabLayout通过如下方法操作标签:
newTab : 创建新标签。
addTab : 添加一个标签。
getTabAt : 获取指定位置的标签。
setOnTabSelectedListener : 设置标签的选中监听器。该监听器需实现OnTabSelectedListener接口的三个方法,具体说明如下:
onTabSelected: 在标签选中时触发;
onTabUnselected: 在标签取消选中时触发;
onTabReselected: 在标签已选中状态再次选中时触发;

上面的属性和方法说明略显单调,那还是给个具体的代码例子,看看这些属性和方法该如何搭配使用。下面是界面布局的xml文件例子:
<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.v7.widget.Toolbar
android:id="@+id/tl_head"
android:layout_width="match_parent"
android:layout_height="50dp"
app:navigationIcon="@drawable/ic_back" >

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

<android.support.design.widget.TabLayout
android:id="@+id/tab_title"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerInParent="true"
app:tabIndicatorColor="@color/red"
app:tabIndicatorHeight="2dp"
app:tabSelectedTextColor="@color/red"
app:tabTextColor="@color/grey"
app:tabTextAppearance="@style/TabText" />

</RelativeLayout>
</android.support.v7.widget.Toolbar>

<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/grey" />

<android.support.v4.view.ViewPager
android:id="@+id/vp_content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>

下面是操纵TabLayout和ViewPager的代码片段:
public class TabLayoutActivity extends AppCompatActivity implements OnTabSelectedListener, OnPageChangeListener {private Toolbar tl_head;private ViewPager vp_content;private TabLayout tab_title;private ArrayList<String> mTitleArray = new ArrayList<String>();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_tab_layout);tl_head = (Toolbar) findViewById(R.id.tl_head);tab_title = (TabLayout) findViewById(R.id.tab_title);vp_content = (ViewPager) findViewById(R.id.vp_content);setSupportActionBar(tl_head);tl_head.setNavigationOnClickListener(new OnClickListener() {@Overridepublic void onClick(View view) {finish();}});mTitleArray.add("商品");mTitleArray.add("详情");initTabLayout();initTabViewPager();}private void initTabLayout() {tab_title.addTab(tab_title.newTab().setText(mTitleArray.get(0)));tab_title.addTab(tab_title.newTab().setText(mTitleArray.get(1)));tab_title.setOnTabSelectedListener(this);}private void initTabViewPager() {GoodsPagerAdapter adapter = new GoodsPagerAdapter(getSupportFragmentManager(), mTitleArray);vp_content.setAdapter(adapter);vp_content.addOnPageChangeListener(this);}@Overridepublic void onTabReselected(Tab tab) {}@Overridepublic void onTabSelected(Tab tab) {vp_content.setCurrentItem(tab.getPosition());}@Overridepublic void onTabUnselected(Tab tab) {}@Overridepublic void onPageScrollStateChanged(int position) {}@Overridepublic void onPageScrolled(int position, float arg1, int arg2) {}@Overridepublic void onPageSelected(int position) {tab_title.getTabAt(position).select();}}

以上的xml文件与代码配合,已经能够实现文章开头的商品页切换效果了。不过这里尚存在两点待改进的地方,首先我们看到,商品页和详情页之间的切换,既能通过点击TabLayout实现,也能通过滑动ViewPager实现;也就是说,TabLayout和ViewPager要完成的页面切换其实是同一个行为,可是代码中给TabLayout注册了一个选择监听器,得重写三个方法;同样的,ViewPager也注册了一个滑动监听器,又得重写三个方法;如此一来,一共要重写六个方法,使得代码的冗余程度增加了。

当然Android在设计之初也考虑到了这个冗余的情况,所以这个页面切换其实有捷径可以走。比如对于ViewPager的页面切换,多数情况只需重写onPageSelected一个方法,所以系统已经自带了简单的滑动监听器SimpleOnPageChangeListener,使用该监听器即可大大简化代码,简化后的页面切换代码如下所示:
vp_content.addOnPageChangeListener(new SimpleOnPageChangeListener() {@Overridepublic void onPageSelected(int position) {tab_title.getTabAt(position).select();}});
对于TabLayout的页面切换,它的简化方案更简洁,只需下面一行代码,即可完成TabLayout与ViewPager的页面选择关联,具体代码如下所示:
tab_title.setOnTabSelectedListener(new ViewPagerOnTabSelectedListener(vp_content));

TabLayout第二个有待改进的地方,是它的标签文字风格。前面说到,TabLayout的几个属性可以调整标签文字的颜色、样式等等,可是这仅限于修改文本,无法在标签中定制图片,因此若要给标签加个角标什么的,就必须进行自定义了。虽然TabLayout默认采用文本标签,但它也支持自定义标签,而且自定义标签的过程也很简单,只要定义标签项的布局文件,然后调用Tab页的setCustomView方法即可设置自定义布局。

比如下面是一个标签项的自定义布局文件,其中指定了一个标签文本,加上一个圆点角标,并通过状态图形区分标签的选中与非选中两种状态:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent" >    <TextView        android:id="@+id/tv_toolbar1"        android:layout_width="wrap_content"        android:layout_height="match_parent"        android:layout_centerInParent="true"        android:gravity="center"        android:textColor="@drawable/toolbar_text_selector"        android:textSize="17sp" />    <ImageView        android:id="@+id/iv_point1"        android:layout_width="25dp"        android:layout_height="25dp"        android:layout_toRightOf="@+id/tv_toolbar1"        android:paddingTop="10dp"        android:paddingLeft="3dp"        android:scaleType="fitCenter"        android:src="@drawable/toolbar_image_selector" /></RelativeLayout>

接着打开活动页面代码,只消把initTabLayout函数改成下面这样,寥寥几行就实现了自定义的标签栏:
private void initTabLayout() {tab_title.addTab(tab_title.newTab().setCustomView(R.layout.item_toolbar1));tv_toolbar1 = (TextView) findViewById(R.id.tv_toolbar1);tv_toolbar1.setText(mTitleArray.get(0));tab_title.addTab(tab_title.newTab().setCustomView(R.layout.item_toolbar2));tv_toolbar2 = (TextView) findViewById(R.id.tv_toolbar2);tv_toolbar2.setText(mTitleArray.get(1));tab_title.setOnTabSelectedListener(new ViewPagerOnTabSelectedListener(vp_content));}

自定义标签栏的最终页面切换效果如下面的动图所示:
Android开发笔记(一百四十七)标签布局TabLayout



点此查看Android开发笔记的完整目录

__________________________________________________________________________
本文现已同步发布到微信公众号“老欧说安卓”,打开微信扫一扫下面的二维码,或者直接搜索公众号“老欧说安卓”添加关注,更快更方便地阅读技术干货。
Android开发笔记(一百四十七)标签布局TabLayout