Material Design 笔记之 TabLayout
标签: MaterialDesign
先上图
添加依赖
compile 'com.android.support:design:25.0.1' //后面25.0.1是版本号,根据你的编译目标版本修改版本号
基本写法
- XML
<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:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.zp.usetablayout.MainActivity">
<android.support.design.widget.TabLayout
android:id="@+id/tablayout"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</android.support.design.widget.TabLayout>
</LinearLayout>
- Java
public class MainActivity extends AppCompatActivity {
private TabLayout mTabLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTabLayout = ((TabLayout) findViewById(R.id.tablayout)); //找到控件
//自身添加标签,自身new一个标签设置文本,传给自身
mTabLayout.addTab(mTabLayout.newTab().setText("首页"));
mTabLayout.addTab(mTabLayout.newTab().setText("个性化推荐"));
mTabLayout.addTab(mTabLayout.newTab().setText("歌单"));
mTabLayout.addTab(mTabLayout.newTab().setText("主播电台"));
mTabLayout.addTab(mTabLayout.newTab().setText("排行榜"));
mTabLayout.addTab(mTabLayout.newTab().setText("我的"));
}
}
Tips:TabLayout可以在Java代码中设置Tab,也可以在XML布局中设置
- 修改XML
<android.support.design.widget.TabLayout
android:id="@+id/tablayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabIndicatorColor="@color/colorPrimary"
app:tabSelectedTextColor="@color/colorPrimary"
app:tabTextColor="@android:color/darker_gray">
<android.support.design.widget.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="首页"/>
<android.support.design.widget.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="个性化推荐"/>
<android.support.design.widget.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="歌单"/>
<android.support.design.widget.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="主播电台"/>
<android.support.design.widget.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="排行榜"/>
<android.support.design.widget.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="我的"/>
</android.support.design.widget.TabLayout>
Tips:同样的,如果想设置每个Tab带图片,在XML中android:icon="@drawable/ic_favorite_border_black_24dp"
,在Java代码中就是在setText之后再去setIcon()
基本写法就写完了,但是并不够啊,因为实际项目中不会这么粗简,既然如此,那就进阶吧
进阶
了解实际需求
在实际项目中,我们的需求更复杂一些,比如:需要改变Tabs指示器的高和颜色,需要改变Tab的宽高,选定的Tab颜色,滚动模式,更常用的Tabs+ViewPager+Fragment的配套使用等等
XML属性值说明
- app:tabBackground 设置Tabs的背景
- app:tabGravity 为Tabs设置Gravity,有两个常量值,GRAVITY_CENTER,GRAVITY_FILL,用法:
app:tabGravity="center"
或者
app:tabGravity="fill"
值为center,Tabs就居中显示,fill就充满TabLayout- app:tabIndicatorColor 设置指示器的颜色(默认颜色为colorAccent)
- app:tabIndicatorHeight 设置指示器的高度,官方规范建议是2dp
- app:tabMaxWidth 设置Tab的最大宽度
- app:tabMinWidth 设置Tab的最小宽度
- app:tabMode 设置Tabs的显示模式,有两个常量值,MODE_FIXED,MODE_SCROLLABLE。用法:
app:tabMode="fixed"
或者
app:tabMode="scrollable"
fixed表示固定的Tab,scrollable可滚动的Tab,Tab个数少的时候用fixed,当Tab个数较多时用scrollable。- app:tabPadding 很好理解,就是设置Tab的padding,下面同解
- app:tabPaddingTop
- app:tabPaddingBottom
- app:tabPaddingStart
- app:tabPaddingEnd
- app:tabSelectedTextColor 设置Tab选中之后,文本显示的颜色
- app:tabTextColor 设置Tab未选中时,文本显示的颜色
- 实现TabLayout与ViewPager的联动
实现联动的关键有两点
mTabLayout.setupWithViewPager(mViewPager)
将TabLayout与ViewPager进行绑定FragmentStatePagerAdapter
V4包下作用于TabLayout和ViewPager的适配
1.修改XML中的布局
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.zp.usetablayout.MainActivity">
<android.support.design.widget.TabLayout
android:id="@+id/tablayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabBackground="@color/colorPrimary"
app:tabIndicatorColor="@android:color/holo_red_light" <!-- 指示器颜色 -->
app:tabIndicatorHeight="2dp" <!-- 指示器高度 -->
app:tabSelectedTextColor="@android:color/holo_red_light" <!-- 选中的文本颜色 -->
app:tabTextColor="@android:color/white"> <!-- 未选中的文本颜色 -->
</android.support.design.widget.TabLayout>
<android.support.v4.view.ViewPager
android:id="@+id/vp"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v4.view.ViewPager>
</LinearLayout>
2.创建几个Fragment,数量取决你ViewPager想有几个界面,并设置不同的背景颜色以区分,我就创建6个Fragment了
public class MainActivity extends AppCompatActivity implements TabLayout.OnTabSelectedListener, ViewPager.OnPageChangeListener {
private static final String TAG = "MainActivity";
private TabLayout mTabLayout;
private ViewPager mViewPager;
private String[] tabName = new String[]{"首页", "个性化推荐", "歌单", "主播电台", "排行榜", "我"};
//这两个集合到时候都要传到适配器里面去的
private List<String> titles = new ArrayList<>();
private List<Fragment> fragments = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTabLayout = ((TabLayout) findViewById(R.id.tablayout));
mViewPager = ((ViewPager) findViewById(R.id.vp));
initView();
}
private void initView() {
for (int i = 0; i < tabName.length; i++) {
//这个不用说,赋值到tab标签
mTabLayout.addTab(mTabLayout.newTab().setText(tabName[i]));
//赋值到集合中去
titles.add(tabName[i]);
}
//添加标签选择监听
mTabLayout.addOnTabSelectedListener(this);
//实例化Fragment实例传入集合中去,此时上面说的两个集合都有数据了
fragments.add(new HomeFragment());
fragments.add(new RecomFragment());
fragments.add(new MusicMenuFragment());
fragments.add(new RadioFragment());
fragments.add(new NoticeFragment());
fragments.add(new MyFragment());
//关键点---FragmentStatePagerAdapter的子类实例化
MyFragmentAdapter adapter = new MyFragmentAdapter(getSupportFragmentManager(),fragments, titles);
//给ViewPager设置适配器
mViewPager.setAdapter(adapter);
//给ViewPager设置页面改变监听
mViewPager.addOnPageChangeListener(this);
//关键点---将TabLayout与ViewPager进行绑定
mTabLayout.setupWithViewPager(mViewPager);
}
@Override
public void onTabSelected(TabLayout.Tab tab) {
Log.i(TAG, "onTabSelected: " + tab.getText());
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
Log.i(TAG, "onPageSelected: " + titles.get(position));
}
@Override
public void onPageScrollStateChanged(int state) {
}
}
3.适配器(这可是关键)
public class MyFragmentAdapter extends FragmentStatePagerAdapter {
private List<Fragment> mFragments ;
private List<String> mTitles ;
//第一个参数碎片管理器,第二个和第三个参数就不说了
public MyFragmentAdapter(FragmentManager fm,List<Fragment> fragments,List<String> titles) {
super(fm);
mFragments = fragments;
mTitles = titles;
}
@Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
@Override
public int getCount() {
return mFragments == null ?0:mFragments.size();
}
/**
* 这个函数就是给TabLayout的Tab设定Title
*/
@Override
public CharSequence getPageTitle(int position) {
return mTitles.get(position);
}
}
Tips:有人就问了,适配器里面的getPageTitle是给TabLayout的Tab设定Title,那我MainActivity可以不写mTabLayout.addTab(mTabLayout.newTab());
吗?回答是:可以的;那我们将前面的这些代码注释掉,
此时MainActivity代码如下:
public class MainActivity extends AppCompatActivity implements TabLayout.OnTabSelectedListener, ViewPager.OnPageChangeListener {
private static final String TAG = "MainActivity";
private TabLayout mTabLayout;
private ViewPager mViewPager;
private String[] tabName = new String[]{"首页", "个性化推荐", "歌单", "主播电台", "排行榜", "我"};
private List<String> titles = new ArrayList<>();
private List<Fragment> fragments = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTabLayout = ((TabLayout) findViewById(R.id.tablayout));
mViewPager = ((ViewPager) findViewById(R.id.vp));
initView();
}
private void initView() {
for (int i = 0; i < tabName.length; i++) {
// mTabLayout.addTab(mTabLayout.newTab()); //这一行代码已经注视掉了
titles.add(tabName[i]);
}
mTabLayout.addOnTabSelectedListener(this);
fragments.add(new HomeFragment());
fragments.add(new RecomFragment());
fragments.add(new MusicMenuFragment());
fragments.add(new RadioFragment());
fragments.add(new NoticeFragment());
fragments.add(new MyFragment());
MyFragmentAdapter adapter = new MyFragmentAdapter(getSupportFragmentManager(),fragments, titles);
mViewPager.setAdapter(adapter);
mViewPager.addOnPageChangeListener(this);
mTabLayout.setupWithViewPager(mViewPager);
}
@Override
public void onTabSelected(TabLayout.Tab tab) {
Log.i(TAG, "onTabSelected: " + tab.getText());
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
Log.i(TAG, "onPageSelected: " + titles.get(position));
}
@Override
public void onPageScrollStateChanged(int state) {
}
}
另一种方式:实现以上TabLayout与ViewPager的联动还有一种方式,其实也就是省略setupWithViewPager
这一步的绑定,那到底是如何省略的?修改XML布局
···原谅我省略一些代码
<android.support.v4.view.ViewPager
android:id="@+id/vp"
android:layout_below="@id/toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.TabLayout
android:id="@+id/tablayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabBackground="@color/colorPrimary"
app:tabGravity="fill"
app:tabIndicatorColor="@android:color/holo_red_light"
app:tabIndicatorHeight="2dp"
app:tabSelectedTextColor="@android:color/holo_red_light"
app:tabTextColor="@android:color/white">
</android.support.design.widget.TabLayout>
</android.support.v4.view.ViewPager>
Tips:也就是将TabLayout作为ViewPager的子类,TabLayout会检查他的父类是不是ViewPager,是的话自动完成绑定(内部调用setupWithViewPager
)
结尾留点小问题
- 适配器的这个函数应该还记得吧
/**
* 这个函数就是给TabLayout的Tab设定Title
*/
@Override
public CharSequence getPageTitle(int position) {
return mTitles.get(position);
}
这个函数返回的是一个字符串,这样的话就不能为Tab设置图标,但说实话我也不懂怎么解决,对这个问题有兴趣的人可以走进传送门,粗略看了一下说用SpannableString,具体不懂,懂的人记得告诉我一声;