TabLayout提供了一个水平的布局用来展示Tabs,很多应用都有这样的设计,典型的有网易新闻,简书,知乎等。TabLayout就可以很好的完成这一职责,当然也或许各家应用的实现方式不尽相同,这里介绍下TabLayout的用法。
首先TabLayout一般都是配合Viewpager使用的,Viewpager里的Fragment随着顶部的Tab一起联动,这种场景再熟悉不过了。在没有TabLayout的日子里关于这种设计一般都是自己实现的。
- 先来个简单通俗的代码:
<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/toolbar_tab"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:layout_gravity="bottom"
android:background="#ffffff"
android:fillViewport="false"
app:tabMode="fixed"
app:layout_scrollFlags="scroll"
app:tabIndicatorColor="#057523"
app:tabIndicatorHeight="2.0dp"
app:tabSelectedTextColor="#057523"
app:tabTextColor="#ced0d3">
<android.support.design.widget.TabItem
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="a" />
<android.support.design.widget.TabItem
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="b" />
<android.support.design.widget.TabItem
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="c" />
</android.support.design.widget.TabLayout>
<android.support.v4.view.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
上面代码的运行效果如下:
E7C96D0A-4692-40B3-B1D7-08361A7793E7-75356-000684F41CA2CA41.gif- 为了使用TabLayout,我们要让Activity继承自AppCompatActivity,但有时候你项目里的BaseActivity却是继承自FragmentActivity的,这就尴尬了。其实没关系的, AppCompatActivity 也是extends FragmentActivity的。可以把BaseActivity extends AppCompatActivity。如果不想这么做也可以,可以指定当前Activity的theme为
android:theme="@style/Theme.AppCompat"
然后build.gradle文件在dependencies里加上
compile 'com.android.support:design:25.0.0'
然后基本上就不会有什么问题了。
下面来解析下TabLayout的一些基本属性:
app:tabIndicatorColor :指示条的颜色
app:tabIndicatorHeight :指示条的高度
app:tabSelectedTextColor : tab被选中时的字体颜色
app:tabTextColor : tab未被选中时的字体颜色
app:tabMode="scrollable" : 默认是fixed:固定的,标签很多时候会被挤压,不能滑动。
重要的属性基本就这些,其他简单的属性可以自己去摸索,这里选中和未选中的字体颜色,可以根据自己的设计自行修改,同样指示条的高度颜色也可以随意修改。
- 但假如我的设计里不需要指示条怎么办,好像没发现隐藏的API,那也很简单。有两个思路:
1:把指示条高度设为0:
app:tabIndicatorHeight="0dp"
2:把指示条的颜色设为透明:
app:tabIndicatorColor="@color/transparent"
效果如下:
40FAEFFF-FF76-43D1-8DD9-98177B630AE4-75356-00068525B87F337E.gif-
TabItem
在高版本的design库里已经有了TabItem,TabItem是作为TabLayout的子View而配合使用的,点进去发现其实代码很简单,就是个自定义View。
public final class TabItem extends View {
final CharSequence mText;
final Drawable mIcon;
final int mCustomLayout;
public TabItem(Context context) {
this(context, null);
}
public TabItem(Context context, AttributeSet attrs) {
super(context, attrs);
final TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs,
R.styleable.TabItem);
mText = a.getText(R.styleable.TabItem_android_text);
mIcon = a.getDrawable(R.styleable.TabItem_android_icon);
mCustomLayout = a.getResourceId(R.styleable.TabItem_android_layout, 0);
a.recycle();
}
}
所以当我们的需求能够明确知道Tab的个数时,可以在xml里直接添加TabItem。但是但是,心细的你不知道有没有发现问题,我在上面的代码中,tab明明设置的小写,但是运行出来确是大写:
<android.support.design.widget.TabItem
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="a" />
事先申明我可没在代码里重新设置文本,就是这么操蛋。好在天无绝人之路,找到了一个属性叫app:tabTextAppearance,这是Tablayout的属性。TabItem代码简单到几乎没有什么属性可供设置,什么字体大小,颜色貌似都设置不了。
所以我们自己写了个样式,然后酱写:
app:tabTextAppearance="@style/MyTabLayoutTextAppearance"
MyTabLayoutTextAppearance里的代码如下:
<style name="MyTabLayoutTextAppearance"parent="TextAppearance.AppCompat.Widget.ActionBar.Title.Inverse">
<item name="android:textSize">16sp</item>
<item name="android:textAllCaps">false</item>
</style>
这里的android:textAllCaps属性就是控制字体大小写的,TabLayout里默认是true,我们手动改成false即可,我们顺便设置了下字体。
但是但是,问题又来了,我设置的字体大小貌似没什么卵用,无论我怎么调节字体大小就是不变。呵呵,还是要从tabTextAppearance这个属性来着手。
下面我们把代码改成这样:
app:tabTextAppearance="@android:style/TextAppearance.Holo.Large"
这下好了,字体的大小写解决了,字体大小也解决了。这样的属性我们找到了3组,
大.jpg 小<style name="TextAppearance.Holo.Large" parent="TextAppearance.Large" />
<style name="TextAppearance.Holo.Medium"parent="TextAppearance.Medium"/>
<style name="TextAppearance.Holo.Small" parent="TextAppearance.Small" />
分别设置字体为大中小,说实话,这玩意真的不太好用,跟其他控件比起来,这个属性设置有点绕。
- 不要用文本了,改成icon吧,wtf,TabItem根本没有这样的属性啊,TabLayout貌似也没有啊。怎么搞?TabLayout没有明确地提供向Tab中设置图标的途径,但是很多事情总可以另辟蹊径。我们知道,Tab是使用adapter中的getPageTitle()方法做其显示的内容,这个方法返回类型为CharSequence。于是,我们可以在PagerAdapter中重写getPageTitle()方法,创建一个SpannableString,而将图标放置在ImageSpan中,设置在SpannableString中:
private int[] imageResId = {
R.mipmap.ic_0,
R.mipmap.ic_1,
R.mipmap.ic_2
};
@Override
public CharSequence getPageTitle(int position){
Drawable image = ContextCompat.getDrawable(MainActivity.this, imageResId[position]);
image.setBounds(0, 0, image.getIntrinsicWidth(), image.getIntrinsicHeight());
SpannableString sb = new SpannableString(" ");
ImageSpan imageSpan = new ImageSpan(image, ImageSpan.ALIGN_BOTTOM);
sb.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return sb;
}
好了,运行起来,效果有了。
1B73B273D717C65EA0D26E63FEBB9C40.jpg- 要不改成icon+文本吧?呵呵。。。又改???
还好还好,还是上面的方案,稍微修改下代码。在SpannableString中添加文本就可以了:
@Override
public CharSequence getPageTitle(int position){
Drawable drawable = null;
String title=null;
switch (position) {
case 0:
drawable = ContextCompat.getDrawable(MainActivity.this,R.mipmap.ic_qq_pre);
title = "a";
break;
case 1:
drawable = ContextCompat.getDrawable(MainActivity.this, R.mipmap.ic_weibo_pre);
title = "b";
break;
case 2:
drawable = ContextCompat.getDrawable(MainActivity.this, R.mipmap.login_weixin_icon);
title = "c";
break;
default:
break;
}
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
ImageSpan imageSpan = new ImageSpan(drawable, ImageSpan.ALIGN_BOTTOM);
SpannableString spannableString = new SpannableString(" " + title);
spannableString.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return spannableString;
}
还好还好,至于图片的select效果应该很easy了,就不演示了,效果如下。
C9E196F7ABD7AED92B5047DFA767E1E2.jpg- 图片在左边?要不放右边吧,不不不,放上面,算了算了,放下面吧。到底放哪???
如果需求太奇葩,常规手段或者奇技淫巧都无法满足需求的话,就只有最后一招了:自定义。前面说过了TabItem本质上也是View,我们可以根据自己的实际需求来重写这个View。
icon在右边:
右.jpg
icon在上边:
上.jpg
可以发现通过自定义View的方式我们可以随意摆放文本和icon的位置,无所谓上下左右,处理起来都是一样的。甚至一个tab想放两个icon或者两个文本什么的都不在话下。一不下心展开讲,说的有点多了,这里就不再介绍如何自定义TabItem了,放在下篇讲,说了这么多好像也没上Tablayout和ViewPager的代码,也放在下一篇。总体来讲Tablayout的坑还是蛮多的,很多API都没提供,或者提供了但留了很多坑,这很google,一方面给你一个很常用的控件,一方面这个控件又留了很多坑,最后这个控件带给你无限想象和发挥,根据自己的想法,动手去实现吧。
完整代码:GitHub
网友评论