1. 程式人生 > 實用技巧 >轉 android design library提供的TabLayout的用法

轉 android design library提供的TabLayout的用法

原文出處:http://chenfuduo.me/2015/07/30/TabLayout-of-design-support-library/

在開發中,我們常常需要ViewPager結合Fragment一起使用,如下圖:
1

我們可以使用三方開源的PagerSlidingTabStrip去實現,或者viewpagerindicator,我一般都偏向前者。現在我們可以使用Design support library庫的TabLayout去實現了。最終的效果圖:

效果圖

建立佈局

<?xmlversion="1.0"encoding="utf-8"?>
<LinearLayoutxmlns: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">
<!--app:tabMode="scrollable"這個屬性我在程式碼中設定了-->
<!--tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);-->
<android.support.design.widget.TabLayout
android:id="@+id/sliding_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1"
android:background="@android:color/white"/>
</LinearLayout>
在xml新增TabLayout,如同ViewPager,直接`android.support.design.widget.TabLayout`即可。還有其他的屬性我會在程式碼中設定。

建立Fragment

packageme.chenfuduo.myfragmentdemo.fragment;
importandroid.os.Bundle;
importandroid.support.annotation.Nullable;
importandroid.support.v4.app.Fragment;
importandroid.view.LayoutInflater;
importandroid.view.View;
importandroid.view.ViewGroup;
importandroid.widget.TextView;
importme.chenfuduo.myfragmentdemo.R;
/**
*CreatedbyAdministratoron2015/7/30.
*/
publicclassPageFragmentextendsFragment{
publicstaticfinalStringARG_PAGE="ARG_PAGE";
privateintmPage;
publicstaticPageFragmentnewInstance(intpage){
Bundleargs=newBundle();
args.putInt(ARG_PAGE,page);
PageFragmentpageFragment=newPageFragment();
pageFragment.setArguments(args);
returnpageFragment;
}
@Override
publicvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
mPage=getArguments().getInt(ARG_PAGE);
}
@Nullable
@Override
publicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,BundlesavedInstanceState){
Viewview=inflater.inflate(R.layout.fragment_page,container,false);
TextViewtextView=(TextView)view;
textView.setText("Fragment#"+mPage);
returnview;
}
}

其中Fragment的佈局為:

<?xmlversion="1.0"encoding="utf-8"?>
<TextViewxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"/>

ViewPager的介面卡

packageme.chenfuduo.myfragmentdemo.adapter;
importandroid.content.Context;
importandroid.support.v4.app.Fragment;
importandroid.support.v4.app.FragmentManager;
importandroid.support.v4.app.FragmentPagerAdapter;
importme.chenfuduo.myfragmentdemo.fragment.PageFragment;
/**
*CreatedbyAdministratoron2015/7/30.
*/
publicclassSimpleFragmentPagerAdapterextendsFragmentPagerAdapter{
finalintPAGE_COUNT=3;
privateStringtabTitles[]=newString[]{"tab1","tab2","tab3"};
privateContextcontext;
publicSimpleFragmentPagerAdapter(FragmentManagerfm,Contextcontext){
super(fm);
this.context=context;
}
@Override
publicFragmentgetItem(intposition){
returnPageFragment.newInstance(position+1);
}
@Override
publicintgetCount(){
returnPAGE_COUNT;
}
@Override
publicCharSequencegetPageTitle(intposition){
returntabTitles[position];
}
}

設定TabLayout

packageme.chenfuduo.myfragmentdemo;
importandroid.os.Bundle;
importandroid.support.design.widget.TabLayout;
importandroid.support.v4.app.FragmentActivity;
importandroid.support.v4.view.ViewPager;
importandroid.view.Menu;
importandroid.view.MenuItem;
importme.chenfuduo.myfragmentdemo.adapter.SimpleFragmentPagerAdapter;
publicclassThirdActivityextendsFragmentActivity{
privateSimpleFragmentPagerAdapterpagerAdapter;
privateViewPagerviewPager;
privateTabLayouttabLayout;
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_third);
pagerAdapter=newSimpleFragmentPagerAdapter(getSupportFragmentManager(),this);
viewPager=(ViewPager)findViewById(R.id.viewpager);
viewPager.setAdapter(pagerAdapter);
tabLayout=(TabLayout)findViewById(R.id.sliding_tabs);
tabLayout.setupWithViewPager(viewPager);
tabLayout.setTabMode(TabLayout.MODE_FIXED);
}
}

這裡提幾點我遇到的問題

  • tabLayout.setTabMode(TabLayout.MODE_FIXED);

開始我設定的是:

tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);

執行後,三個TabLayout標籤擠到一塊去了。如下:


檢視api,找到結果了。這個tabmode有兩個屬性值:

  • MODE_FIXED:Fixed tabs display all tabs concurrently and are best used with content that benefits from quick pivots between tabs.

  • MODE_SCROLLABLE:Scrollable tabs display a subset of tabs at any given moment, and can contain longer tab labels and a larger number of tabs.

不做過多的解釋,MODE_SCROLLABLE適合很多tabs的情況。

  • setupWithViewPager必須在ViewPager.setAdapter()之後呼叫

檢視下原始碼就知道了:

publicvoidsetupWithViewPager(ViewPagerviewPager){
PagerAdapteradapter=viewPager.getAdapter();
if(adapter==null){
thrownewIllegalArgumentException("ViewPagerdoesnothaveaPagerAdapterset");
}else{
...
}
}

以上就是最基本的用法,是不是很簡單。哈~

定義TabLayout的樣式

預設的情況下,TabLayout的tab indicator的顏色是Material Design中的accent color(#009688),我們可以稍作修改:

<stylename="MyCustomTabLayout"parent="Widget.Design.TabLayout">
<itemname="tabIndicatorColor">#0000FF</item>
</style>

在佈局中使用:

<android.support.design.widget.TabLayout
android:id="@+id/sliding_tabs"
style="@style/MyCustomTabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>

還有一些其他的樣式可供選擇:

<stylename="MyCustomTabLayout"parent="Widget.Design.TabLayout">
<itemname="tabMaxWidth">@dimen/tab_max_width</item>
<itemname="tabIndicatorColor">?attr/colorAccent</item>
<itemname="tabIndicatorHeight">2dp</item>
<itemname="tabPaddingStart">12dp</item>
<itemname="tabPaddingEnd">12dp</item>
<itemname="tabBackground">?attr/selectableItemBackground</item>
<itemname="tabTextAppearance">@style/MyCustomTabTextAppearance</item>
<itemname="tabSelectedTextColor">?android:textColorPrimary</item>
</style>
<stylename="MyCustomTabTextAppearance"parent="TextAppearance.Design.Tab">
<itemname="android:textSize">14sp</item>
<itemname="android:textColor">?android:textColorSecondary</item>
<itemname="textAllCaps">true</item>
</style>

新增icon到tab

當前的TabLayout沒有方法讓我們去新增icon,我們可以使用SpannableString結合ImageSpan來實現,在SimpleFragmentPagerAdapter中:

privateint[]imageResId={
R.drawable.ic_one,
R.drawable.ic_two,
R.drawable.ic_three
};
//...
@Override
publicCharSequencegetPageTitle(intposition){
//Generatetitlebasedonitemposition
//returntabTitles[position];
Drawableimage=context.getResources().getDrawable(imageResId[position]);
image.setBounds(0,0,image.getIntrinsicWidth(),image.getIntrinsicHeight());
SpannableStringsb=newSpannableString("");
ImageSpanimageSpan=newImageSpan(image,ImageSpan.ALIGN_BOTTOM);
sb.setSpan(imageSpan,0,1,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
returnsb;
}

執行,發現沒有顯示,這是因為TabLayout建立的tab預設設定textAllCaps屬性為true,這阻止了ImageSpan被渲染出來,可以通過下面的樣式檔案定義來改變:

<stylename="MyCustomTabLayout"parent="Widget.Design.TabLayout">
<itemname="tabTextAppearance">@style/MyCustomTextAppearance</item>
</style>
<stylename="MyCustomTextAppearance"parent="TextAppearance.Design.Tab">
<itemname="textAllCaps">false</item>
</style>

現在執行,效果就出來了。

新增icon和text到tab

@Override
publicCharSequencegetPageTitle(intposition){
//Generatetitlebasedonitemposition
Drawableimage=context.getResources().getDrawable(imageResId[position]);
image.setBounds(0,0,image.getIntrinsicWidth(),image.getIntrinsicHeight());
//Replaceblankspaceswithimageicon
SpannableStringsb=newSpannableString(""+tabTitles[position]);
ImageSpanimageSpan=newImageSpan(image,ImageSpan.ALIGN_BOTTOM);
sb.setSpan(imageSpan,0,1,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
returnsb;
}

我們看到在例項化SpannableString的時候,我在tabTitles[position]前面加了幾個空格,這些空格的位置是用來放置icon的。

新增自定義的view到tab

介面卡中增加getTabView(...)方法:

packageme.chenfuduo.myfragmentdemo.adapter;
importandroid.content.Context;
importandroid.support.v4.app.Fragment;
importandroid.support.v4.app.FragmentManager;
importandroid.support.v4.app.FragmentPagerAdapter;
importandroid.view.LayoutInflater;
importandroid.view.View;
importandroid.widget.ImageView;
importandroid.widget.TextView;
importme.chenfuduo.myfragmentdemo.R;
importme.chenfuduo.myfragmentdemo.fragment.PageFragment;
/**
*CreatedbyAdministratoron2015/7/30.
*/
publicclassSimpleFragmentPagerAdapterextendsFragmentPagerAdapter{
finalintPAGE_COUNT=3;
privateStringtabTitles[]=newString[]{"tab1","tab2","tab3"};
privateint[]imageResId={R.drawable.avatar_enterprise_vip,
R.drawable.avatar_grassroot,
R.drawable.avatar_vip};
privateContextcontext;
publicSimpleFragmentPagerAdapter(FragmentManagerfm,Contextcontext){
super(fm);
this.context=context;
}
@Override
publicFragmentgetItem(intposition){
returnPageFragment.newInstance(position+1);
}
@Override
publicintgetCount(){
returnPAGE_COUNT;
}
@Override
publicCharSequencegetPageTitle(intposition){
//第一次的程式碼
//returntabTitles[position];
//第二次的程式碼
/**
Drawableimage=context.getResources().getDrawable(imageResId[position]);
image.setBounds(0,0,image.getIntrinsicWidth(),image.getIntrinsicHeight());
SpannableStringsb=newSpannableString(""+tabTitles[position]);
ImageSpanimageSpan=newImageSpan(image,ImageSpan.ALIGN_BOTTOM);
sb.setSpan(imageSpan,0,1,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
returnsb;*/
returnnull;
}
publicViewgetTabView(intposition){
Viewview=LayoutInflater.from(context).inflate(R.layout.tab_item,null);
TextViewtv=(TextView)view.findViewById(R.id.textView);
tv.setText(tabTitles[position]);
ImageViewimg=(ImageView)view.findViewById(R.id.imageView);
img.setImageResource(imageResId[position]);
returnview;
}
}

簡單的佈局:

<?xmlversion="1.0"encoding="utf-8"?>
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/imageView"
android:layout_centerVertical="true"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/imageView"
android:layout_centerVertical="true"
android:id="@+id/textView"
android:layout_marginLeft="3dp"
/>
</RelativeLayout>

使用:

@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_third);
pagerAdapter=newSimpleFragmentPagerAdapter(getSupportFragmentManager(),this);
viewPager=(ViewPager)findViewById(R.id.viewpager);
viewPager.setAdapter(pagerAdapter);
tabLayout=(TabLayout)findViewById(R.id.sliding_tabs);
tabLayout.setupWithViewPager(viewPager);
tabLayout.setTabMode(TabLayout.MODE_FIXED);
for(inti=0;i<tabLayout.getTabCount();i++){
TabLayout.Tabtab=tabLayout.getTabAt(i);
tab.setCustomView(pagerAdapter.getTabView(i));
}
}

處理配置改變

當螢幕旋轉或者配置改變的時候,我們需要儲存當前的狀態。

@Override
publicvoidonSaveInstanceState(BundleoutState){
super.onSaveInstanceState(outState);
outState.putInt(POSITION,tabLayout.getSelectedTabPosition());
}
@Override
protectedvoidonRestoreInstanceState(BundlesavedInstanceState){
super.onRestoreInstanceState(savedInstanceState);
viewPager.setCurrentItem(savedInstanceState.getInt(POSITION));
}

需要注意的是getSelectedTabPosition()方法是最新的design support library才有的。
最後的效果如下: