Material Design 控件知识梳理(1) - Android Design Support Library 是什么
Material Design 控件知识梳理(2) - AppBarLayout & CollapsingToolbarLayout
Material Design 控件知识梳理(3) - BottomSheet && BottomSheetDialog && BottomSheetDialogFragment
Material Design 控件知识梳理(4) - FloatingActionButton
Material Design 控件知识梳理(5) - DrawerLayout && NavigationView
Material Design 控件知识梳理(6) - Snackbar
Material Design 控件知识梳理(7) - BottomNavigationBar
Material Design 控件知识梳理(8) - TabLayout
Material Design 控件知识梳理(9) - TextInputLayout
一、概述
前面我们介绍了BottomNavigationBar
,TabLayout
和它的作用类似,都是方便用户进行页面之间的切换。
二、TabLayout
的基本用法
下面,我们先演示一遍TabLayout
的基本用法
第一步:引入依赖:
compile 'com.android.support:design:25.3.1'
第二步:定义布局,这里使用了最常用的TabLayout+ViewPager
的结构:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.demo.lizejun.repotransition.TabLayoutActivity">
<android.support.design.widget.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="scrollable"
app:tabGravity="center"/>
<android.support.v4.view.ViewPager
android:id="@+id/vp_content"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
第三步:定义ViewPager
的Adapter
,这里需要重写getPageTitle
方法,它就对应的是TabLayout
当中的文案:
public class ViewPagerAdapter extends PagerAdapter {
private List<String> mTitles;
public ViewPagerAdapter(List<String> title) {
mTitles = title;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
ViewGroup itemView = (ViewGroup) LayoutInflater.from(container.getContext()).inflate(R.layout.item_view_pager, container, false);
container.addView(itemView);
TextView tv = (TextView) itemView.findViewById(R.id.tv_title);
tv.setText(mTitles.get(position));
return itemView;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public int getCount() {
return mTitles.size();
}
@Override
public CharSequence getPageTitle(int position) {
return mTitles.get(position);
}
}
第四步:给ViewPager
设置数据,并把ViewPager
和TabLayout
关联起来:
public class TabLayoutActivity extends AppCompatActivity {
private static final String[] TITLE_SHORT = new String[] {
"深圳","南京","内蒙古"
};
private static final String[] TITLE_LONG = new String[] {
"深圳","南京","内蒙古呼和浩特","广西壮族自治区","上海","北京","天津"
};
private ViewPager mViewPager;
private TabLayout mTabLayout;
private ViewPagerAdapter mViewPagerAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tab_layout);
initViewPager();
initTabLayout();
}
private void initViewPager() {
mViewPager = (ViewPager) findViewById(R.id.vp_content);
List<String> titles = new ArrayList<>();
Collections.addAll(titles, TITLE_LONG);
mViewPagerAdapter = new ViewPagerAdapter(titles);
mViewPager.setAdapter(mViewPagerAdapter);
}
private void initTabLayout() {
mTabLayout = (TabLayout) findViewById(R.id.tab_layout);
mTabLayout.setupWithViewPager(mViewPager);
}
}
最终的效果为:
三、TabLayout
相关设置
3.1 TabItem
的外观设置
对于每个TabItem
的外观,TabLayout
我们比较常用的属性有:
- 未选中
TabItem
的文本颜色:app:tabTextColor
- 选中
TabItem
的文本颜色app:tabSelectedTextColor
- 底部滑动条的颜色:
app:tabIndicatorColor
- 底部滑动条的高度:
app:tabIndicatorHeight
-
TabItem
的背景:app:tabBackground
我们在第二节的基础上进行修改:
<android.support.design.widget.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="scrollable"
app:tabGravity="center"
app:tabTextColor="@android:color/darker_gray"
app:tabSelectedTextColor="@android:color/holo_orange_dark"
app:tabIndicatorColor="@android:color/holo_orange_dark"
app:tabIndicatorHeight="2dp"
app:tabBackground="@android:color/transparent" />
最终展现的效果为:
3.2 TabItem
的宽高相关设置
有两个关于宽度的属性比较重要:tabMinWidth
和tabMaxWidth
,它允许我们这是每个TabItem
的最小和最大宽度。
此外,我们还可以设置TabItem
四个维度的Padding
。
3.3 tabMode
和tabGravity
上面只是决定了单个TabItem
的外观,而TabItem
在TabLayout
当中的摆放规则需要由这两个属性来决定,它们可选的值分别为:
-
tabMode
:fixed
或者scrollable
-
tabGravity
:fill
或者center
这两个属性分别通过:app:tabMode
和app:tabGravity
来设置,下面,我们就来解释这几个值的含义。
3.3.1 tabMode=fixed
在这种模式下,每个TabItem
的宽度都是相等的,并且所有的TabItem
加起来的宽度不会大于TabLayout
的宽度,最终展现的结果还需要依赖于tabGravity
属性:
-
tabGravity=fill
要求所有TabItem
加起来的宽度等于TabLayout
的宽度,也就是下面的效果
-
tabGravity=center
不要求TabItem
加起来的宽度等于TabLayout
的宽度,会根据每个TabItem
的属性,计算出TabItem
的宽度,然后取它们中的最大值乘上TabItem
的个数,当这一数值小于TabLayout
的宽度时,会将每个TabItem
的宽度设置为这个最大值,并将它们放置在整个TabLayout
的中间,而如果这一数值大于TabLayout
的宽度,那么会将它们在TabLayout
中均匀排列。
3.3.2 tabMode=scrollable
在tabMode=fixed
模式下,TabItem
的位置是固定的,并且它们加起来的宽度不会大于TabLayout
的宽度,而在scrollable
模式下则没有这一限制,只需要计算好每个TabItem
的宽度,然后把它们排列在TabLayout
中就好了,可以通过拖动的方式查看更多的TabItem
,并且当tabMode=scrollable
时,tabGravity
其实并没有作用,下面是tabMode=scrollable
的事例:
在这种模式下,每个
TabItem
的宽度默认情况下是根据文字的宽度计算出来的,如果我们希望进行相应的限制,那么可以修改tabMinWidth
或者tabMaxWidth
属性。
3.4 设置监听
mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
Log.d("onTabSelected", "position=" + tab.getPosition());
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
Log.d("onTabUnselected", "position=" + tab.getPosition());
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
Log.d("onTabReselected", "position=" + tab.getPosition());
}
});
-
onTabSelected
,某个TabItem
从未选中状态变为选中状态时回调 -
onTabUnselected
,某个TabItem
从选中变为未选中时回调 -
onTabReselected
,某个TabItem
已经处于选中状态,但是它又被再次点击了,那么回调这个函数。
四、TabLayout + ViewPager
使用TabLayout
时,一般都是采用ViewPager
来管理多个子界面,而TabLayout
也十分贴心地提供了方法让它和ViewPager
的滚动关联起来,当点击TabLayout
中的Item
时,会切换到ViewPager
对应的界面,而如果滑动了ViewPager
,那么TabLayout
也会切换到对应的TabItem
。
我们所需要的只是下面这句设置:
mTabLayout.setupWithViewPager(mViewPager);
为了能让TabLayout
知道TabItem
的标题,需要重写ViewPager
所对应的PagerAdapter
中getPageTitle
的方法:
@Override
public CharSequence getPageTitle(int position) {
return mTitles.get(position);
}
虽然TabLayout
并没有提供切换到某个具体位置TabItem
的方法,但是其实这一过程这完全可以通过mViewPager.setCurrentItem(int item)
来实现。
更多文章,欢迎访问我的 Android 知识梳理系列:
- Android 知识梳理目录://www.greatytc.com/p/fd82d18994ce
- 个人主页:http://lizejun.cn
- 个人知识总结目录:http://lizejun.cn/categories/